Pulum DigitalOcean: use outputs - pulumi

I want to create some servers on DigitalOcean using Pulumi. I have the following code:
for i in range(0, amount):
name = f"droplet-{i+1}"
droplet = digitalocean.Droplet(
name,
image=_image,
region=_region,
size=_size,
)
pulumi.export(f"droplet-ip-{i+1}", droplet.ipv4_address)
This is correctly outputting the IP address of the servers on the console.
However I would like to use the IP addresses elsewhere in my Python script. Therefor I had added the droplets to a list as follows:
droplets = []
for i in range(0, amount):
name = f"droplet-{i+1}"
droplet = digitalocean.Droplet(
name,
image=_image,
region=_region,
size=_size,
)
pulumi.export(f"droplet-ip-{i+1}", droplet.ipv4_address)
droplets.append(droplet)
to then loop over the droplets as follows:
for droplet in droplets:
print(droplet.ipv4_address)
In the Pulumi output, I see the following:
Diagnostics:
pulumi:pulumi:Stack (Pulumi_DigitalOcean-dev):
<pulumi.output.Output object at 0x105086b50>
<pulumi.output.Output object at 0x1050a5ac0>
I realize that while the droplets are still being created, the IP address is unknown but I'm adding the droplets to the list after the creation.
Is there a way to know the IP addresses at some point so it can be used elsewhere in the Python script.

The short answer is that because these values are Outputs, if you want the strings, you'll need to use .apply:
https://www.pulumi.com/docs/intro/concepts/inputs-outputs/#apply
To access the raw value of an output and transform that value into a new value, use apply. This method accepts a callback that will be invoked with the raw value, once that value is available.
You can print these IPs by iterating over the list and calling the apply method on the ipv4_address output value:
...
pulumi.export(f"droplet-ip-{i+1}", droplet.ipv4_address)
droplets.append(droplet)
...
for droplet in droplets:
droplet.ipv4_address.apply(lambda addr: print(addr))
$ pulumi up
...
Diagnostics:
pulumi:pulumi:Stack (so-71888481-dev):
143.110.157.64
137.184.92.205
Outputs:
droplet-ip-1: "137.184.92.205"
droplet-ip-2: "143.110.157.64"
Depending on how you plan to use these strings in your program, this particular may may not be perfect, but in general, if you want the unwrapped value of pulumi.Output, you'll need to use .apply().
The pulumi.Output.all() also comes in handy if you want to wait for several output values to resolve before using them:
https://www.pulumi.com/docs/intro/concepts/inputs-outputs/#all
If you have multiple outputs and need to join them, the all function acts like an apply over many resources. This function joins over an entire list of outputs. It waits for all of them to become available and then provides them to the supplied callback.
Hope that helps!

Related

Building a data subscriber. How to loop hopen through IPs

I am trying to build a subscriber function that goes like this:
Every user register his machine name to a list using
hostname:enlist .z.h
The function loops through the hostname list, creates connection and do some function {u:hopen(`:x:200;5000);u"somefunction[]"} each hostname
The only issue is .z.h is of a symbol where x should have no type in order to have this: u:hopen(`:HURNMW052:200;5000) instead of this u:hopen(`:`HURNMW052:200;5000)
The same thing happens using IPs ”.” sv string”h”$0x0 vs .z.a = "161.16.16.23" not 161.16.16.23
Any idea how I could cast those or other solutions to create a loop of handles?
You can use a string to open a connection. See below.
q)":",string[.z.h],":8009"
":homer:8009"
q)h:hopen(":",string[.z.h],":8009";5000)
q)h
3i
This reference on the kx wiki is useful for opening connections in kdb.

In pytest, how to run against different ip for cases with different marks or name patterns

I have a question here.
I am using Pytest.
I have two cases with mark and name as:
1)
#pytest.mark.ip1
def test_ip1_actions()
...
#pytest.mark.ip2
def test_ip2_actions()
...
what I want is:
if the mark is ip1, then I will run the test against 1st ip - 192.168.2.23; if the mark is ip2, then the case should run against 2nd ip - 192.168.2.100
or:
based on the name, if case name contains "ip1", it will run against 1st ip; if case name contains "ip2", then run against 2nd ip.
In fact I have many cases to run against 2 ips, not only 2. and the ip information (as well some other information of the two hosts) are written in an json file. So I would like to find out a general and simple solution.
I tried but didn't get it.
I thought maybe do something in the conftest.py file? for example, before the case running, judge the mark or the name? But don't know how to handle.
Looking forward to your advice, to my first question in stackoverflow! :)
thanks very much!
Don't quite understand, and it's hard to understand more without seeing an example test, but how about using parameters to determine which ips are passed in.
Say you have a test to check ips are accessible. This would be one way to do it, but it's not very nice or extensible.
def test_ip_accessible():
assert is_accessible("192.168.2.23")
assert is_accessible("192.168.2.100")
Instead you can create helper functions that return specific ips, or a list of ips, and then use these as parameters.
ip_map: Dict[int, str] = { # ip id to address
1: "192.168.2.23",
2: "192.168.2.100",
3: "192.168.2.254",
}
def get_single_ip(id_: int) -> str:
return ip_map[id_]
def get_multiple_ips(*ids) -> Tuple[str]:
return tuple(ip_map[i] for i in ids)
#pytest.mark.parametrize("ip_address", [get_single_ip(1), get_single_ip(2)])
def test_ip_accessible(ip_address):
# ip_address will be 192.168.2.23 then 192.168.2.100 in two separate tests
assert is_accessible(ip_address)
#pytest.mark.parametrize("ip_addresses", [get_multiple_ips(1, 2), get_multiple_ips(2, 3)])
def test_with_multiple_ips(ip_addresses):
# this test will also be run twice. the first time, ip_addresses will be
# ["192.162.2.23", "192.168.2.100"]. the second time, it will be
# ["192.168.2.100", "192.168.2.254"].
assert something_with_a_list_of_ips(ip_addresses)

Host's pods panel in Grafana

I want to have a panel in Grafana which displays what pods are currently running in a host.
For the host variable I have the following query (the job variable is just label_values(node_uname_info, job).):
label_values(node_uname_info{job="$job"}, instance)
This gives me an array of sockets: host_ip:port
I can get the pod names from kube_pod_info{job="$job", host_ip="$host_ip"}, but in order to get the IP I need to remove the port part of the socket:
label_replace(node_uname_info{job="$job", instance="$node"}, "host_ip", "$1", "instance", "(.*):.*")
I haven't found how to use the new host_ip label in the pod query to eventually get all the pod label values of kube_pod_info. I don't want to put the label_replace in Prometheus to avoid data duplication - is there a way to use the new host_ip label in the pod query?
Edit:
I added the host_ip variable with the regex as shan1024 showed in his answer and changed the panel's query to:
sum by (pod) (kube_pod_info{job="$job", host_ip="$host_ip"})
Then I changed the panel's visualization to table and added column styles to Time and Value (chose type Hidden). This allows me to display the host's running pods in a list-like fashion.
This is actually quite easy to do in Grafana and no need to change labels in Prometheus. You just need to add a regex in the instance variable (when we add a regex with a capturing group, the value(s) of the 1st captured group will be the value(s) of the variable).
e.g.
Variable definition without Regex (you get host_ip:port)-
Variable definition with Regex (you only get host_ip)-
Then you can add a new variable with value kube_pod_info{ host_ip="$instance" } to get all pods in the selected host.

Treeline.io sanitize inputs

I have just started investigating into treeline.io beta, so, I could not find any way in the existing machinepacks that would do the job(sanitizing user inputs). Wondering if i can do it in anyway, best if within treeline.
Treeline automatically does type-checking on all incoming request parameters. If you create a route POST /foo with parameter age and give it 123 as an example, it will automatically display an error message if you try to post to /foo with age set to abc, because it's not a number.
As far as more complex validation, you can certainly do it in Treeline--just add more machines to the beginning of your route. The if machine works well for simple tasks; for example, to ensure that age is < 150, you can use if and set the left-hand value to the age parameter, the right-hand value to 150, and the comparison to "<". For more custom validations you can create your own machine using the built-in editor and add pass and fail exits like the if machine has!
The schema-inspector machinepack allow you to sanitize and validate the inputs in Treeline: machinepack-schemainspector
Here a screenshot how I'm using it in my Treeline project:
The content of the Sanitize element:
The content of the Validate element (using the Sanitize output):
For the next parts, I'm always using the Sanitize output (email trimmed and in lowercase for this example).

Obtaining Name of Simscape Physical Port

I am working on a model generation script to automatically generate Simscape models from a library of components with varying ports. Due to the vast number of ports that need to be connected across the model, I am looking for a good way to set up which ports need to be connected to each other. The best solution I have come up with so far is to name each port with a unique tag that indicates what other ports in the system it should be connected to in the generated model. However, I am not able to obtain the name of any physical port. It is labeled on the mask, but the 'Name' parameter always comes back empty. Here's what I've tried:
h = get_param(gcb,'PortConnectivity')
port = h(1).Type %This only returns the physical port #, not custom name
h = get_param(gcb,'PortHandles')
port = get_param(h.LConn(1),'Name') %This returns an empty cell array
Not sure where to go from here. Any ideas on how to solve this? Thanks!
You can use:
name = get_param(gcb, 'Name');
to get the port name. A general tip for finding the right block property, run:
get(get_param(gcb, 'object'))
this will display all block properties and their values.