Idem 12.0.0

Idem 12.0.0 introduces 2 new features. kwarg credentials for batch runs, and recursive contracts for exec/state returns.

Recursive Contracts for exec/state returns

States

States already implicitly expect a dictionary with specific keys. With a recursive contracts however, malformed state returns are caught as soon as possible. The expected format for a state return is:

{
    "name": "<state name>",
    "changes": {
        "<change name>": {
            "old": <The status of the affected resource before the change>,
            "new": <The status of the affected resource after the change>
        },
    }
    "result": True|False,
    "comment": "<A comment about the state run>",
}

Exec

Exec modules now give a warning (in a future release this will be a raised exception) if the return isn’t formatted properly. The expected format for an exec return is:

{
    "result": True|False,
    "ret": <The return date from the exec module run>,
    "comment": <A status code, exception, or other context for the given result>,
}

Kwarg Credentials for internal batch runs

idem.state.batch can run multiple states at once from within python code. This is useful if you don’t want to run idem states from the cli, but from your own python project. Now batch runs will accept encrypted or unencrypted acct information as kwargs.

First, put your credentials into a yaml file. Check the documentation for the idem provider to see what the available parameters are.

credentials.yaml:

acct_provider_name:
    default:
        profile_kwarg1: value1
        profile_kwarg2: value2
    another_profile_name:
        profile_kwarg1: value1
        profile_kwarg2: value2

Use the acct program to encrypt the credentials

acct encrypt credentials.yaml

The output of this command will be the fernet algorithm key used to encrypt your credentials.

output:

jIgQhT9j9g9-c5yZ47R95f-zpQ_KYzdrtXwXc5R7eKg=

Note

Alternatively, if the ACCT_KEY environment variable is set with a valid fernet key, it will be used by the acct encrypt command to encrypt the file.

After encrypting credentials.yaml, a new file will have been created called “credentials.yaml.fernet”. The contents of this file can be passed to a batch run to safely get provider credentials to idem.

cat credentials.yaml.fernet

output:

gAAAAABgo20bb2XCzM6fN82v7zSaDtVPitexSUk7nhO9MfAUQHvr_YKqjlzMC9NFG3IFt-nie7DqFQH9lRPuhdRrLYoojUBILQ==%

Note

It is not wise to send encrypted credentials and their decryption key together; use a pre-defined trusted fernet key at both endpoints of your idem app.

idem app example:

import asyncio
import os
import pop.hub
import uuid

hub = pop.hub.Hub()
hub.pop.sub.add(dyne_name="idem")
hub.pop.loop.create()

states = {"state name": {"test.succeed_without_changes": {"kwarg1": "value1"}}}
unencrypted_profiles = {
    "provider_name": {"yet_another_profile_name": {"kwarg1": "safe value"}}
}
acct_key = os.environ.get("ACCT_KEY", "jIgQhT9j9g9-c5yZ47R95f-zpQ_KYzdrtXwXc5R7eKg=")

hub.pop.Loop.run_until_complete(
    hub.idem.state.batch(
        states=states,
        profiles=unencrypted_profiles,
        encrypted_profiles="gAAAAABgo20bb2XCzM6fN82v7zSaDtVPitexSUk7nhO9MfAUQHvr_YKqjlzMC9NFG3IFt-nie7DqFQH9lRPuhdRrLYoojUBILQ==",
        acct_key=acct_key,
        default_acct_profile="default",
    )
)

Get status of internal batch run

Specify the “name” parameter in idem.state.batch to be able to retrieve the status of an internal run with hub.state.status.

import asyncio
import pop.hub
import uuid

hub = pop.hub.Hub()
hub.pop.sub.add(dyne_name="idem")
hub.pop.loop.create()

name = uuid.uuid4()
states = {"state name": {"test.succeed_without_changes": {"kwarg1": "value1"}}}

task = hub.pop.Loop.create_task(hub.idem.state.batch(states=states, name=name))

await asyncio.sleep(1)

status = hub.idem.state.status(name)
print(status)

stdout:

{
    "sls_sources": [
        "json://{'state name':{'test.succeed_without_changes':{'kwarg1':'value1'}}}"
    ],
    "test": False,
    "errors": [],
    "running": {},
    "acct_profile": "default",
    "status": 0,
    "status_name": "FINISHED",
}