Created
September 8, 2014 13:06
-
-
Save tomassedovic/6e7f18021f83b87b9f9c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
USAGE: python import.py path/to/overcloud.yaml | |
Load the overcloud.yaml and figure out the top-level resources (i.e. ones that | |
don't represent a role). | |
Figure out which parameters these top-level resources use. | |
Build a mapping of property -> value for each non-trivial property in | |
the role (i.e. one that can't be generated by Tuskar as {get_param: XYZ}). | |
This could be wrapped up in a function within Tuskar. We would | |
(optionally) run it during the initialisation phase. Our load-roles | |
script would use the "overcloud.yaml" as well. It would be introspected | |
by this code. | |
Tuskar would then be able to add the necessary parameters, resources, | |
outputs and set the right properties for each role when generating the plan. | |
Assumptions: | |
* The users aren't able to add new roles after the initial upload | |
* The Role resources in the input template are either ResourceGroup or AutoScalingGroup | |
and the inner resource's type has the "OS::TripleO::" prefix | |
* The Role resources generated by Tuskar have identical names to the ones in the | |
input template (if not, the top-level resources would have to be updated, too) | |
''' | |
import sys | |
import yaml | |
parsed_plan_structure = yaml.safe_load(open(sys.argv[1])) | |
STANDALONE_PARAMETERS = set() | |
ROLES = set() | |
STANDALONE_RESOURCES = set() | |
OUTPUTS = set(parsed_plan_structure.get('outputs', {}).keys()) | |
# Mapping from a role's property (input) to a call involving a top-level | |
# resource or parameter: | |
INPUT_MAP = {} | |
def is_resource(resource): | |
return 'type' in resource and 'properties' in resource | |
def is_role(resource): | |
scaling_groups = ('OS::Heat::ResourceGroup', 'OS::Heat::AutoScalingGroup') | |
if is_resource(resource) and resource['type'] in scaling_groups: | |
inner = role_inner_resource(resource) | |
return 'OS::TripleO::' in inner['type'] | |
else: | |
return False | |
def role_inner_resource(role): | |
properties = role.get('properties', {}) | |
inner = properties.get('resource_def', {}) or properties.get('resource', {}) | |
assert is_resource(inner) | |
return inner | |
def get_all_params_from_resource(resource): | |
params = [] | |
if not hasattr(resource, 'items'): | |
return params | |
for k, v in resource.items(): | |
if k == 'get_param': | |
params.append(v) | |
else: | |
params.extend(get_all_params_from_resource(v)) | |
return params | |
# Sort resources to "role" / "standalone resource" buckets | |
for name, resource in parsed_plan_structure.get('resources', {}).items(): | |
assert is_resource(resource) | |
if is_role(resource): | |
ROLES.add(name) | |
else: | |
STANDALONE_RESOURCES.add(name) | |
# No resource should be both a role and standalone | |
assert len(ROLES.intersection(STANDALONE_RESOURCES)) == 0 | |
# Pick out the top-level parameters (i.e. ones not connected to any role) | |
for name in STANDALONE_RESOURCES: | |
resource = parsed_plan_structure['resources'][name] | |
params = get_all_params_from_resource(resource) | |
STANDALONE_PARAMETERS.update(params) | |
# Generate the property map for each role | |
for role_name in ROLES: | |
role = parsed_plan_structure['resources'][role_name] | |
role_input_map = {} | |
inner_props = role_inner_resource(role).get('properties', {}) | |
for prop, value in inner_props.items(): | |
# value is {'get_param': a_role_specific_parameter} | |
if hasattr(value, 'get'): | |
param = value.get('get_param') | |
if (param and param not in STANDALONE_PARAMETERS): | |
continue # this will be generated by Tuskar | |
# value is more complex than {'get_param'} or refers a top-level parameter | |
# Tuskar has no way of knowing how to generate this so we just store the value | |
role_input_map[prop] = value | |
INPUT_MAP[role_name] = role_input_map | |
print "Top-level parameters:\n\t", '\n\t'.join(STANDALONE_PARAMETERS) | |
print "\nRoles:\n\t", '\n\t'.join(ROLES) | |
print "\nTop-level resources:\n\t", '\n\t'.join(STANDALONE_RESOURCES) | |
print "\nOutputs:\n\t", '\n\t'.join(OUTPUTS) | |
for role, mappings in INPUT_MAP.items(): | |
print "\nInput map for role %s:" % role | |
for key, value in mappings.items(): | |
print "\t%s -> %s" % (key, value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment