0

I've recently started coding in python. I am trying to create an environment variable and assign list to it using python. So when I try to read my environment variables through command line like printenv it will be listed there.

This is my code in python:

from API_CALLS import Post_Request as Request
import os

class VTM_Config:

    @staticmethod
    def validate_pool_nodes(url, headers, expected_num_of_active_nodes):
        try:
            print('\nNow Executing Validate VTM Configs...\n')
            # validate that vtm api works by sending a get_session_with_ssl call to the url
            vtm_get_session_response = Request.get_session_with_ssl(url=url, headers=headers)
            data = vtm_get_session_response
            active_nodes = [
                n['node']
                for n in data['properties']['basic']['nodes_table']
                if n['state'] == 'active'

            ]
            actual_num_of_active_nodes = len(active_nodes)
            if expected_num_of_active_nodes != actual_num_of_active_nodes:
                print("Number of Active Nodes = {}".format(actual_num_of_active_nodes))
                raise Exception("ERROR: You are expecting : {} nodes, but this pool contains {} nodes".format(
                    expected_num_of_active_nodes, actual_num_of_active_nodes))
            else:
                print("Number of Active Nodes = {}\n".format(actual_num_of_active_nodes))
            print("Active servers : {}\n".format(active_nodes))
            os.environ["ENABLED_POOL_NODES"] = active_nodes
            return os.environ["ENABLED_POOL_NODES"]

        except Exception as ex:
            raise ex

I am trying to create an environment variable using os.environ["ENABLED_POOL_NODES"] = active_nodes and trying to return it.

When I run this code, I am getting an error like this: raise TypeError ("str expected, not %s % type(value).name) TypeError: str expect, not list.

Question: How do I assign list to an environment variable.

Shahboz
  • 466
  • 2
  • 10
  • 30
  • 2
    you could convert the list to its string representation: `os.environ["ENABLED_POOL_NODES"] = str(active_nodes)`. But what's the use for this? this is very hacky to use env. variables just to communicate between the various parts of your python program. – Jean-François Fabre Aug 06 '18 at 19:37
  • 3
    I'm saying that because you seem to expect that the env. variable will be propagated to the calling shell, which isn't possible. Env. variables are only propagated to the child processes. – Jean-François Fabre Aug 06 '18 at 19:39
  • @Jean-FrançoisFabre I am planning on reading that env variable and assign it in a jenkins variable to use it for various validations. – Shahboz Aug 06 '18 at 19:39
  • so I don't think you need an env. variable at all. – Jean-François Fabre Aug 06 '18 at 19:40
  • So in my jenkins job definition I have a build step to execute a shell which runs this python code and I am expecting it to return that active_nodes list. Is there way to do it without creating an env variable? – Shahboz Aug 06 '18 at 19:41
  • 1
    yes: write to an output file or to the console & parse it – Jean-François Fabre Aug 06 '18 at 19:42
  • @Jean-FrançoisFabre can you elaborate in code how I could write to the console and parse? in python? – Shahboz Aug 06 '18 at 19:46
  • just use `json` to serialize your data from python process #1, then from python process #2, just use `json` to read back your python data. – Jean-François Fabre Aug 06 '18 at 19:49
  • If your program `print`s something to output, a shell script can capture it with a command substitution: `varname=$(your-script ...)` will store output in a shell variable named `varname`. If you *need* to for some reason, you can then promote that shell variable to an environment variable with `export`. If this answers your question, then the question was duplicative of https://stackoverflow.com/questions/4651437/how-to-set-a-variable-to-the-output-of-a-command-in-bash – Charles Duffy Aug 06 '18 at 20:03
  • @CharlesDuffy I tried it with command substitution and export the varname. However when I echo it, it is also printing everything from the method that has print(). Is there way to export only active_nodes as string? – Shahboz Aug 06 '18 at 20:25
  • Here is my bash script, nodes=$(python python_file.py) export $nodes echo $nodes this outputs everything including the contents from print() – Shahboz Aug 06 '18 at 20:28
  • Yes, things you don't want to include as *output* should be printed to stderr, not stdout. If this is Python 2, `print >>sys.stderr, "This is an informational message"`; if it's Python 3, `print("This is an informational message", file=sys.stderr)`. – Charles Duffy Aug 06 '18 at 21:19
  • ...being a diagnostic channel (and status logging is diagnostic in nature) is the whole *point* of stderr. – Charles Duffy Aug 06 '18 at 23:01
  • Possible duplicate of [How to set environment variables in Python](https://stackoverflow.com/q/5971312/608639), [os.environ not setting environment variables](https://stackoverflow.com/q/30006722/608639), [How do I make environment variable changes stick in Python?](https://stackoverflow.com/q/488366/608639), etc. – jww Aug 06 '18 at 23:11
  • @Hashim77, ...btw, do take note of what I said about the `export` usually being unnecessary -- you only need that if you want to make the variable visible in subprocesses, not just the shell itself. – Charles Duffy Aug 07 '18 at 11:16

2 Answers2

1

As @Jean-Francois Fabre pointed out in the comments above, this likely isn't the best approach to the problem you are attempting to solve. However, to answer the question in the title and the last line of your post:

Question: How do I assign list to an environment variable.

You can't directly assign a list to an environment variable. These are inherently string values, so you need to convert your list to a string somehow. If you simply need to pass the whole thing back, you can do something as simple as:

os.envrion["ENABLED_POOL_NODES"] = str(active_nodes)

This will just cast the list into a string, which will look something like: "['a', 'b', 'c']". Depending on what you want to do with the env variable downstream, you may need to handle it differently.

bzier
  • 445
  • 3
  • 11
  • I'd like to read the env variable ["ENABLED_POOL_NODES"] and assign it to a variable in jenkins job. So in my jenkins job definition I have a build step to execute a shell which runs this python code and I am expecting it to return that active_nodes list (either as a list or string). I just want to read that object and assign to jenkins variable. – Shahboz Aug 06 '18 at 20:35
  • So my method `def validate_pool_nodes(url, headers, expected_num_of_active_nodes):` I changed it to `return str(active_nodes)` which returns the casted string of list. Now in bash script I'd like to export it this way `nodes=$(python pyhon_file.py) export $nodes echo $nodes` – Shahboz Aug 06 '18 at 20:43
  • There it looks like you are attempting to assign the stdout from your python script to the bash variable `nodes`. In that case, you'll need a main method, and you'll want to print your list to stdout rather than returning it. Just saw the comments w/Charles Duffy above. That should put you on the right track. – bzier Aug 06 '18 at 21:26
0

So, it was a simple solution thanks to all of you. I ended up just returning string value and print to the console where a shell script in my jenkins job would get the output:

def validate_pool_nodes(url, headers, expected_num_of_active_nodes):
        try:
            print('\nNow Executing Validate VTM Configs...\n', file=sys.stderr)
            # validate that vtm api works by sending a get_session_with_ssl call to the url
            vtm_get_session_response = Request.get_session_with_ssl(url=url, headers=headers)
            data = vtm_get_session_response
            active_nodes = {
                n['node']
                for n in data['properties']['basic']['nodes_table']
                if n['state'] == 'active'
            }
            actual_num_of_active_nodes = len(active_nodes)
            if expected_num_of_active_nodes != actual_num_of_active_nodes:
                print("Number of Active Nodes = {}".format(actual_num_of_active_nodes), file=sys.stderr)
                raise Exception("ERROR: You are expecting : {} nodes, but this pool contains {} nodes".format(
                    expected_num_of_active_nodes, actual_num_of_active_nodes))
            else:
                print("Number of Active Nodes = {}\n".format(actual_num_of_active_nodes), file=sys.stderr)

            return str(active_nodes)

        except Exception as ex:
            raise ex

And here is the "main" python method:

if __name__ == '__main__':
    arg1 = sys.argv[1]
    arg2 = int(sys.argv[2])
    run_prereq = Prerequisites()
    run_prereq.validate_login_redirect(pool_arg=arg1)
    nodes_list = run_prereq.validate_pool_nodes(pool_arg=arg1, num__of_nodes_arg=arg2)
    sys.stdout.write(nodes_list)
    sys.exit(0)
Shahboz
  • 466
  • 2
  • 10
  • 30