Skip to content

Commit

Permalink
feat: include pillar in resource model
Browse files Browse the repository at this point in the history
  • Loading branch information
blu-base committed Jul 14, 2024
1 parent d752af6 commit 5f2d643
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 9 deletions.
93 changes: 84 additions & 9 deletions contents/salt_resource_model_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,32 @@ def prepare_grains(data: dict) -> set:
return needed_grains | needed_tags | needed_attributes


def collect_minions_grains(data, all_needed_grains):
def prepare_pillar(data: dict) -> set:
"""
Prepare pillar for tags and attributes.
"""
needed_tags = string_to_unique_set(data.get('pillar-tags', None))
needed_attributes = string_to_unique_set(data.get('pillar-attributes', None))

log.debug(f'Tag pillar: {needed_tags}')
log.debug(f'Attribute pillar: {needed_attributes}')

return needed_tags | needed_attributes

def login(data):
# Login to the API
client = Pepper(api_url=data['url'], ignore_ssl_errors=not data['verify_ssl'])
try:
response = client.login(username=data['user'], password=data['password'], eauth=data['eauth'])
except PepperException as exception:
print(str(exception))
sys.exit(1)
log.debug(f'Logging into API: {response}')

return client


def collect_minions_grains(client, data, all_needed_grains):
"""
Execute low state API call and return minions response.
"""
Expand All @@ -84,14 +109,38 @@ def collect_minions_grains(data, all_needed_grains):

log.debug(f'Compiled low_state: {low_state}')

# Login to the API
client = Pepper(api_url=data['url'], ignore_ssl_errors=not data['verify_ssl'])
# Send payload
try:
response = client.login(username=data['user'], password=data['password'], eauth=data['eauth'])
response = client.low(lowstate=[low_state])
except PepperException as exception:
print(str(exception))
sys.exit(1)
log.debug(f'Logging into API: {response}')
log.debug(f'Received raw response: {response}')

minions = response.get('return', [{}])[0]
return minions


def collect_minions_pillar(client, data, all_needed_pillar):
"""
Execute low state API call and return minions response.
"""
# Prepare payload
low_state = {
'client': 'local',
'tgt': data['tgt'],
'fun': 'pillar.item',
'arg': list(all_needed_pillar),
'kwarg': {},
'full_return': True,
}

if data['timeout'] is not None:
low_state['kwarg']['timeout'] = data['timeout']
if data['gather-timeout'] is not None:
low_state['kwarg']['gather_job_timeout'] = data['gather-timeout']

log.debug(f'Compiled low_state: {low_state}')

# Send payload
try:
Expand Down Expand Up @@ -154,15 +203,15 @@ def process_attributes(metadata, needed_attributes, reserved_keys):
return processed_attributes


def generate_resource_model(minions, data):
def generate_resource_model(minions_grains, minions_pillar, data):
"""
Generate resource model from minions and grains data.
"""
reserved_keys = {'nodename', 'hostname', 'username', 'description', 'tags', 'osFamily', 'osArch', 'osName',
'osVersion', 'editUrl', 'remoteUrl'}

resource_model = {}
for minion, ret in minions.items():
for minion, ret in minions_grains.items():
nodename = minion if data['prefix'] is None else f"{data['prefix']}{minion}"

if not isinstance(ret, dict) or ret.get('ret') is None:
Expand All @@ -186,6 +235,19 @@ def generate_resource_model(minions, data):

resource_model[nodename] = model

# process pillar for valid nodes
for nodename, value in resource_model.items():
minion = value['hostname']
pillar = minions_pillar.get(minion, {}).get('ret', {})

# extend existing tags
pillar_tags = process_tags(pillar, string_to_unique_set(data['tags']))
resource_model[nodename]['tags'] += pillar_tags

# append attributes
processed_attributes = process_attributes(pillar, string_to_unique_set(data['pillar-attributes']), reserved_keys)
resource_model.update({nodename: processed_attributes})

return resource_model


Expand All @@ -200,6 +262,8 @@ def main():
DataItem('tgt', 'RD_CONFIG_TGT', 'str'),
DataItem('tags', 'RD_CONFIG_TAGS', 'str'),
DataItem('attributes', 'RD_CONFIG_ATTRIBUTES', 'str'),
DataItem('pillar-tags', 'RD_CONFIG_PILLAR_TAGS', 'str'),
DataItem('pillar-attributes', 'RD_CONFIG_PILLAR_ATTRIBUTES', 'str'),
DataItem('prefix', 'RD_CONFIG_PREFIX', 'str'),
DataItem('timeout', 'RD_CONFIG_TIMEOUT', 'int'),
DataItem('gather-timeout', 'RD_CONFIG_GATHER_TIMEOUT', 'int'),
Expand All @@ -222,10 +286,21 @@ def main():

# queue the Salt-API
all_needed_grains = prepare_grains(data)
minions = collect_minions_grains(data, all_needed_grains)
all_needed_pillar = prepare_pillar(data)



# open session with Salt-API
client = login(data)

# collect metadata
grains = collect_minions_grains(client, data, all_needed_grains)
pillar = {}
if len(all_needed_pillar) > 0:
pillar = collect_minions_pillar(client, data, all_needed_pillar)

# compile the Rundeck Resource Model
resource_model = generate_resource_model(minions, data)
resource_model = generate_resource_model(grains, pillar, data)

# print response to stdout for Rundeck to pickup
print(json.dumps(resource_model))
Expand Down
11 changes: 11 additions & 0 deletions plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,17 @@ providers:
description: 'Create node attributes from grains and their values. use comma-separated list for multiple grains. Nested values of grains are not supported, but nested keys are, such as systemd.version .'
scope: Project
default: 'master'
- type: String
name: pillar-tags
title: 'Node tags from pillar'
description: 'Create node tags from the values of pillar. Use comma-separated list for multiple grains.'
scope: Project
- type: String
name: pillar-attributes
title: 'Node attributes from pillar'
description: 'Create node attributes from pillar and their values. use comma-separated list for multiple grains. Nested values of grains are not supported, but nested keys are, such as systemd.version.'
scope: Project
default: 'master'
- type: Integer
name: timeout
title: 'Minion timeout'
Expand Down

0 comments on commit 5f2d643

Please sign in to comment.