def test_circular_get_property_from_outputs(self): yaml = """ node_types: vm_type: properties: b: { type: string } c: { type: string } node_templates: vm: type: vm_type properties: b: { get_property: [SELF, c] } c: [ { get_property: [SELF, b ] }, 2 ] outputs: o: value: a: 1 b: { get_property: [vm, b] } """ try: prepare_deployment_plan(self.parse(yaml)) self.fail() except RuntimeError as e: self.assertIn('Circular get_property function call detected', str(e))
def test_input_value_data_type_validation_raises(self): yaml = self.BASIC_VERSION_SECTION_DSL_1_2 + """ inputs: some_input: type: a data_types: a: properties: b: type: b b: properties: c: type: c c: properties: d: type: integer """ plan = self.parse_1_2(yaml) with self.assertRaisesRegex(DSLParsingException, r'b\.c\.d') as cm: prepare_deployment_plan( plan, inputs={'some_input': { 'b': { 'c': { 'd': 'should_be_int' } } }}) self.assertEqual(ERROR_INPUT_VIOLATES_DATA_TYPE_SCHEMA, cm.exception.err_code)
def test_get_property_from_get_input_missing_key(self): yaml = """ inputs: dict_input: {} node_types: vm_type: properties: a: { type: string } b: { type: string } node_templates: vm1: type: vm_type properties: a: {get_input: dict_input} b: {get_property: [SELF, a, key]} """ try: prepare_deployment_plan(self.parse(yaml), inputs={'dict_input': { 'other_key': 42 }}) self.fail() except KeyError as e: self.assertIn('vm1.properties.a.key', e.message)
def test_missing_input(self): yaml = """ inputs: port: {} name_i: {} name_j: {} node_types: webserver_type: properties: port: {} name: {} name2: {} node_templates: webserver: type: webserver_type properties: port: { get_input: port } name: { get_input: name_i } name2: { get_input: [name_j, attr1, 0] } """ with self.assertRaises(MissingRequiredInputError) as cm: prepare_deployment_plan(self.parse(yaml), inputs={'port': '8080'}) msg = str(cm.exception).split('-')[0] # get first part of message self.assertIn('name_i', msg) self.assertIn('name_j', msg) self.assertNotIn('port', msg) with self.assertRaises(MissingRequiredInputError) as cm: prepare_deployment_plan(self.parse(yaml), inputs={}) msg = str(cm.exception).split('-')[0] # get first part of message self.assertIn('name_j', msg) self.assertIn('name_i', msg) self.assertIn('port', msg)
def test_circular_get_property_from_outputs(self): yaml = """ node_types: vm_type: properties: b: { type: string } c: { type: string } node_templates: vm: type: vm_type properties: b: { get_property: [SELF, c] } c: [ { get_property: [SELF, b ] }, 2 ] outputs: o: value: a: 1 b: { get_property: [vm, b] } """ try: prepare_deployment_plan(self.parse(yaml)) self.fail() except RuntimeError, e: self.assertIn('Circular get_property function call detected', str(e))
def test_node_template_properties_with_invalid_node_property_cycle(self): yaml = """ node_types: type: properties: property1: {} property2: {} node_templates: node1: type: type properties: property1: { concat: [one, { get_property: [node2, property1] }, three] } property2: value1 node2: type: type properties: property1: { concat: [one, { get_property: [node1, property1] }, three] } property2: value2 """ with ExpectedException(RuntimeError, '.*Circular.*'): prepare_deployment_plan(self.parse_1_1(yaml))
def test_input_value_data_type_validation_successful(self): yaml = self.BASIC_VERSION_SECTION_DSL_1_2 + """ inputs: some_input: type: a data_types: a: properties: b: type: b b: properties: c: type: c c: properties: d: type: integer """ prepare_deployment_plan( self.parse_1_2(yaml), inputs={'some_input': { 'b': { 'c': { 'd': 123 } } }})
def test_func_integrations(self): yaml = """ inputs: some_input: default: some_node some_input2: default: some_input node_types: some_type: properties: prop1: {} concat_prop: {} node_templates: some_node: type: some_type properties: prop1: 4 concat_prop: concat: - get_property: - get_input: get_input: some_input2 - prop1 - 2 """ parsed = prepare_deployment_plan(self.parse_1_1(yaml)) some_node = self.get_node_by_name(parsed, 'some_node') self.assertEqual('42', some_node['properties']['concat_prop']) yaml = """ inputs: dummy_input: default: some_node some_nodesome_node: default: some_nodesome_node node_types: some_type: properties: prop: {} dummy_prop: {} node_templates: some_node: type: some_type properties: dummy_prop: dummy_value prop: get_attribute: - get_input: dummy_input - concat: - get_attribute: [ some_node, dummy_prop ] - get_input: concat: - get_input: dummy_input - get_input: dummy_input """ prepare_deployment_plan(self.parse_1_1(yaml))
def test_get_secret_list_secret_does_not_exist(self): yaml = """ outputs: secret: value: { get_secret: [missing_secret, test] } """ parsed = self.parse_1_3(yaml) get_secret_not_found = Mock(side_effect=NotFoundException) with self.assertRaisesRegex(exceptions.UnknownSecretError, "Required secret.*missing_secret.*"): prepare_deployment_plan(parsed, get_secret_not_found)
def _test_validate_value_type_mismatch_with_deployment_plan( self, type_name, value): yaml = self.BASIC_VERSION_SECTION_DSL_1_2 + """ inputs: some_input: type: {0} """.format(type_name) message_regex = ( "Property type validation failed.*type is '{0}'".format(type_name)) plan = self.parse(yaml) with self.assertRaisesRegex(DSLParsingException, message_regex): prepare_deployment_plan(plan, inputs={'some_input': value})
def _test_autocorrect_value_mismatch(self, type_name, input_value): yaml = self.BASIC_VERSION_SECTION_DSL_1_2 + """ inputs: some_input: type: {0} """.format(type_name) message_regex = ( "Property type validation failed.*type is '{0}'".format(type_name)) plan = self.parse(yaml) self.assertEqual(plan[consts.INPUTS]['some_input'][consts.TYPE], type_name) with self.assertRaisesRegex(DSLParsingException, message_regex): prepare_deployment_plan(plan, inputs={'some_input': input_value})
def test_invalid_concat(self): yaml = """ node_types: type: properties: property: {} node_templates: node: type: type properties: property: { concat: 1 } """ with ExpectedException(ValueError, '.*Illegal.*concat.*'): prepare_deployment_plan(self.parse_1_1(yaml))
def test_get_property_doesnt_accept_runtime_func_as_args(self): yaml = """ node_types: some_type: properties: prop: {} dummy_prop: {} node_templates: some_node: type: some_type properties: dummy_prop: dummy_value prop: get_property: - get_attribute: - some_node - dummy_prop - shouldn't matter """ with self.assertRaisesRegexp( exceptions.FunctionValidationError, 'Runtime function .+ cannot be nested within a non-runtime ' 'function \\(found in .+\\)'): prepare_deployment_plan(self.parse(yaml)) yaml = """ node_types: some_type: properties: prop: {} dummy_prop: {} node_templates: some_node: type: some_type properties: dummy_prop: dummy_value prop: get_property: - concat: - get_attribute: - some_node - dummy_prop - shouldn't matter """ with self.assertRaisesRegexp( exceptions.FunctionValidationError, 'Runtime function .+ cannot be nested within a non-runtime ' 'function \\(found in .+\\)'): prepare_deployment_plan(self.parse_1_1(yaml))
def test_recursive(self): yaml = """ inputs: i: default: 1 node_types: vm_type: properties: a: { type: string } b: { type: string } c: { type: string } x: { type: string } y: { type: string } z: { type: string } node_templates: vm: type: vm_type properties: a: 0 b: { get_property: [ SELF, a ] } c: { get_property: [ SELF, b ] } x: { get_property: [ SELF, z ] } y: { get_property: [ SELF, x ] } z: { get_input: i } """ parsed = prepare_deployment_plan(self.parse(yaml)) vm = self.get_node_by_name(parsed, 'vm') self.assertEqual(0, vm['properties']['b']) self.assertEqual(1, vm['properties']['x']) self.assertEqual(1, vm['properties']['y']) self.assertEqual(1, vm['properties']['z'])
def test_recursive_get_property_in_outputs(self): yaml = """ node_types: vm_type: properties: a: { type: string } b: { type: string } c: { type: string } node_templates: vm: type: vm_type properties: a: 1 b: { get_property: [SELF, c] } c: [ { get_property: [SELF, a ] }, 2 ] outputs: o: value: a: { get_property: [vm, b] } b: [0, { get_property: [vm, b] }] """ parsed = prepare_deployment_plan(self.parse(yaml)) outputs = parsed.outputs self.assertEqual(1, outputs['o']['value']['a'][0]) self.assertEqual(2, outputs['o']['value']['a'][1]) self.assertEqual(0, outputs['o']['value']['b'][0]) self.assertEqual(1, outputs['o']['value']['b'][1][0]) self.assertEqual(2, outputs['o']['value']['b'][1][1])
def test_get_property_from_get_input_runtime(self): yaml = """ inputs: dict_input: {} node_types: vm_type: properties: a: { type: string } b: { type: string } node_templates: vm1: type: vm_type properties: a: {get_input: dict_input} b: {get_property: [SELF, a, key]} """ inputs = {'dict_input': {'key': 'secret'}} plan = prepare_deployment_plan( self.parse(yaml), inputs=inputs, runtime_only_evaluation=True) # with runtime-only-evaluation, the property isn't evaluated at # prepare_deployment_plan time self.assertEqual( {'get_property': ['SELF', 'a', 'key']}, plan['nodes'][0]['properties']['b']) evaluated = functions.evaluate_node_functions( plan['nodes'][0], self._mock_evaluation_storage(inputs=inputs) ) self.assertEqual('secret', evaluated['properties']['b'])
def test_get_property_another_node_runtime(self): yaml = """ node_types: vm_type: properties: a: { type: string } c: { type: string } node_templates: vm1: type: vm_type properties: a: {get_property: [vm2, c]} c: secret1 vm2: type: vm_type properties: a: xxx c: secret2 """ plan = prepare_deployment_plan( self.parse(yaml), runtime_only_evaluation=True) plan_node = next(n for n in plan['nodes'] if n['name'] == 'vm1') self.assertEqual(plan_node['properties']['a'], {'get_property': ['vm2', 'c']}) node = functions.evaluate_node_functions( plan_node, self._mock_evaluation_storage(nodes=plan['nodes'])) self.assertEqual(node['properties']['a'], 'secret2')
def test_node_template_capabilities(self): yaml = """ node_templates: node: type: type capabilities: scalable: properties: default_instances: { get_property: [node, prop1] } max_instances: { get_property: [SELF, prop1] } min_instances: { get_input: my_input } inputs: my_input: default: 20 node_types: type: properties: prop1: default: 10 """ parsed = prepare_deployment_plan(self.parse_1_3(yaml)) node = self.get_node_by_name(parsed, 'node') self.assertEqual({ 'default_instances': 10, 'min_instances': 20, 'max_instances': 10, 'current_instances': 10, 'planned_instances': 10, }, node['capabilities']['scalable']['properties'])
def test_basic_namespace_multi_import(self): layer1_yaml = """ node_types: test_type: properties: key: default: value node_templates: node: type: test_type """ layer1_file_name = self.make_yaml_file(layer1_yaml) layer2_yaml = self.BASIC_VERSION_SECTION_DSL_1_3 + """ imports: - {0}--{1} """.format('middle_test', layer1_file_name) layer2_file_name = self.make_yaml_file(layer2_yaml) main_yaml = self.BASIC_VERSION_SECTION_DSL_1_3 + """ imports: - {0}--{1} """.format('test', layer2_file_name) main_yaml += """ outputs: port: description: the port value: { get_attribute: [test--middle_test--node, key] } """ plan = prepare_deployment_plan(self.parse(main_yaml)) self.assertEqual({'get_attribute': ['test--middle_test--node', 'key']}, plan[constants.OUTPUTS]['port']['value'])
def test_recursive_get_property_in_outputs(self): imported_yaml = """ node_types: vm_type: properties: a: { type: string } b: { type: string } c: { type: string } node_templates: vm: type: vm_type properties: a: 1 b: { get_property: [SELF, c] } c: [ { get_property: [SELF, a ] }, 2 ] outputs: o: value: a: { get_property: [vm, b] } b: [0, { get_property: [vm, b] }] """ import_file_name = self.make_yaml_file(imported_yaml) main_yaml = self.BASIC_VERSION_SECTION_DSL_1_3 + """ imports: - {0}--{1} """.format('test', import_file_name) plan = prepare_deployment_plan(self.parse(main_yaml)) output_value = plan.outputs['test--o']['value'] self.assertEqual(1, output_value['a'][0]) self.assertEqual(2, output_value['a'][1]) self.assertEqual(0, output_value['b'][0]) self.assertEqual(1, output_value['b'][1][0]) self.assertEqual(2, output_value['b'][1][1])
def test_inputs_provided_to_plan(self): yaml = """ inputs: port: default: 9000 port2: default: [{'a': [9000]}] node_types: webserver_type: properties: port: {} port2: {} node_templates: webserver: type: webserver_type properties: port: { get_input: port } port2: { get_input: [port2, 0, 'a', 0] } """ parsed = prepare_deployment_plan(self.parse(yaml), inputs={ 'port': 8000, 'port2': [{ 'a': [8000] }] }) self.assertEqual(8000, parsed['nodes'][0]['properties']['port']) self.assertEqual(8000, parsed['nodes'][0]['properties']['port2'])
def test_outputs(self): yaml = """ node_types: type: properties: property: {} node_templates: node: type: type properties: property: value outputs: output1: value: { concat: [one, {get_property: [node, property]}, three] } output2: value: - item1 - { concat: [one, {get_property: [node, property]}, three] } output3: value: { concat: [one, {get_property: [node, property]}, {get_attribute: [node, attribute]}] } """ parsed = prepare_deployment_plan(self.parse_1_1(yaml)) outputs = parsed['outputs'] self.assertEqual('onevaluethree', outputs['output1']['value']) self.assertEqual('onevaluethree', outputs['output2']['value'][1]) self.assertEqual({'concat': ['one', 'value', {'get_attribute': ['node', 'attribute']}]}, outputs['output3']['value'])
def test_get_property_from_get_secret_runtime(self): yaml = """ node_types: vm_type: properties: secret1_value: { type: string } b: { type: string } node_templates: vm1: type: vm_type properties: secret1_value: secret b: {get_property: [SELF, {get_secret: secret1} ]} """ storage = self._mock_evaluation_storage() plan = prepare_deployment_plan( self.parse(yaml), get_secret_method=storage.get_secret, runtime_only_evaluation=True) self.assertEqual( {'get_property': ['SELF', {'get_secret': 'secret1'}]}, plan['nodes'][0]['properties']['b']) evaluated = functions.evaluate_node_functions( plan['nodes'][0], storage ) self.assertEqual('secret', evaluated['properties']['b'])
def test_outputs_valid_output(self): yaml = """ node_templates: {} outputs: port0: description: p0 value: 1234 port1: description: p1 value: some_port port2: description: p2 value: {} port3: description: p3 value: [] port4: value: false """ parsed = self.parse(yaml) outputs = parsed['outputs'] self.assertEqual(5, len(parsed['outputs'])) self.assertEqual('p0', outputs['port0']['description']) self.assertEqual(1234, outputs['port0']['value']) self.assertEqual('p1', outputs['port1']['description']) self.assertEqual('some_port', outputs['port1']['value']) self.assertEqual('p2', outputs['port2']['description']) self.assertEqual({}, outputs['port2']['value']) self.assertEqual('p3', outputs['port3']['description']) self.assertEqual([], outputs['port3']['value']) self.assertNotIn('description', outputs['port4']) self.assertFalse(outputs['port4']['value']) prepared = prepare_deployment_plan(parsed) self.assertEqual(parsed['outputs'], prepared['outputs'])
def test_policies_properties(self): yaml = """ node_templates: node: type: type inputs: my_input: default: 20 node_types: type: properties: prop1: default: 10 groups: group: members: [node] policies: policy: type: cloudify.policies.scaling targets: [group] properties: default_instances: { get_property: [node, prop1] } min_instances: { get_input: my_input } """ parsed = prepare_deployment_plan(self.parse_1_3(yaml)) expected = { 'default_instances': 10, 'min_instances': 20, 'max_instances': -1, 'current_instances': 10, 'planned_instances': 10, } self.assertEqual(expected, parsed['scaling_groups']['group']['properties']) self.assertEqual(expected, parsed['policies']['policy']['properties'])
def test_node_template_properties(self): yaml = """ node_types: vm_type: properties: ip: {} ip_duplicate: {} server_type: properties: endpoint: {} node_templates: vm: type: vm_type properties: ip: 10.0.0.1 ip_duplicate: { get_property: [ SELF, ip ] } server: type: server_type properties: endpoint: { get_property: [ vm, ip ] } """ parsed = prepare_deployment_plan(self.parse(yaml)) vm = self.get_node_by_name(parsed, 'vm') self.assertEqual('10.0.0.1', vm['properties']['ip_duplicate']) server = self.get_node_by_name(parsed, 'server') self.assertEqual('10.0.0.1', server['properties']['endpoint'])
def test_relationship_operation_inputs(self): yaml = """ plugins: p: executor: central_deployment_agent install: false node_types: type: properties: property: {} relationships: cloudify.relationships.contained_in: {} node_templates: node: type: type properties: property: value relationships: - type: cloudify.relationships.contained_in target: node2 source_interfaces: interface: op: implementation: p.task inputs: input1: { concat: [one, { get_property: [SOURCE, property] }, three] } input2: key1: value1 key2: { concat: [one, { get_property: [SOURCE, property] }, three] } key3: - item1 - { concat: [one, {get_property: [TARGET, property]}, three] } input3: { concat: [one, {get_property: [SOURCE, property] }, {get_attribute: [SOURCE, attribute] }]} node2: type: type properties: property: value2 """ parsed = prepare_deployment_plan(self.parse_1_1(yaml)) inputs = self.get_node_by_name(parsed, 'node')['relationships'][0][ 'source_operations']['interface.op']['inputs'] self.assertEqual('onevaluethree', inputs['input1']) self.assertEqual('onevaluethree', inputs['input2']['key2']) self.assertEqual('onevalue2three', inputs['input2']['key3'][1]) self.assertEqual( { 'concat': [ 'one', 'value', {'get_attribute': ['SOURCE', 'attribute']}] }, inputs['input3'])
def test_get_property_from_get_input_data_type(self): yaml = """ inputs: dict_input: type: nested default: key: secret data_types: nested: properties: key: {} node_types: vm_type: properties: a: { type: string } b: { type: string } node_templates: vm1: type: vm_type properties: a: {get_input: dict_input} b: {get_property: [SELF, a, key]} """ plan = prepare_deployment_plan(self.parse_1_2(yaml)) self.assertEqual('secret', plan['nodes'][0]['properties']['b'])
def test_func_integrations_1_0(self): yaml = """ inputs: some_input: default: some_node node_types: some_type: properties: prop1: {} prop2: {} node_templates: some_node: type: some_type properties: prop1: 4 prop2: get_attribute: - get_property: - get_input: some_input - prop1 - 2 """ parsed = prepare_deployment_plan(self.parse(yaml)) some_node = self.get_node_by_name(parsed, 'some_node') self.assertDictEqual( {'get_attribute': [4, 2]}, some_node['properties']['prop2'])
def test_func_integrations_within_list(self): yaml = """ inputs: some_input: default: some_node node_types: some_type: properties: prop1: {} concat_prop: {} node_templates: some_node: type: some_type properties: prop1: 4 concat_prop: - concat: - get_property: - get_input: some_input - prop1 - 2 """ parsed = prepare_deployment_plan(self.parse_1_1(yaml)) some_node = self.get_node_by_name(parsed, 'some_node') self.assertEqual(['42'], some_node['properties']['concat_prop'])
def test_node_template_interfaces(self): yaml = """ plugins: plugin: executor: central_deployment_agent install: false node_types: vm_type: properties: ip: type: string node_templates: vm: type: vm_type properties: ip: 10.0.0.1 interfaces: interface: op: implementation: plugin.op inputs: x: { get_property: [vm, ip] } """ parsed = prepare_deployment_plan(self.parse(yaml)) vm = self.get_node_by_name(parsed, 'vm') self.assertEqual('10.0.0.1', vm['operations']['op']['inputs']['x']) self.assertEqual('10.0.0.1', vm['operations']['interface.op']['inputs']['x'])
def test_outputs_valid_output(self): yaml = """ node_templates: {} outputs: port0: description: p0 value: 1234 port1: description: p1 value: some_port port2: description: p2 value: {} port3: description: p3 value: [] port4: description: p4 value: false """ parsed = self.parse(yaml) outputs = parsed['outputs'] self.assertEqual(5, len(parsed['outputs'])) self.assertEqual('p0', outputs['port0']['description']) self.assertEqual(1234, outputs['port0']['value']) self.assertEqual('p1', outputs['port1']['description']) self.assertEqual('some_port', outputs['port1']['value']) self.assertEqual('p2', outputs['port2']['description']) self.assertEqual({}, outputs['port2']['value']) self.assertEqual('p3', outputs['port3']['description']) self.assertEqual([], outputs['port3']['value']) self.assertEqual('p4', outputs['port4']['description']) self.assertFalse(outputs['port4']['value']) prepared = prepare_deployment_plan(parsed) self.assertEqual(parsed['outputs'], prepared['outputs'])
def test_get_property_from_namespaced_node(self): imported_yaml = """ node_types: test_type: properties: key: default: value node_templates: node: type: test_type """ import_file_name = self.make_yaml_file(imported_yaml) main_yaml = self.BASIC_VERSION_SECTION_DSL_1_3 + """ imports: - {0}--{1} """.format('test', import_file_name) main_yaml += """ outputs: port: description: the port value: { get_property: [test--node, key] } """ plan = prepare_deployment_plan(self.parse(main_yaml)) self.assertEqual('value', plan[constants.OUTPUTS]['port']['value'])
def test_node_template_properties_simple(self): yaml = """ node_types: type: properties: property: {} node_templates: node: type: type properties: property: { get_secret: secret } """ parsed = prepare_deployment_plan(self.parse_1_3(yaml), self._get_secret_mock) node = self.get_node_by_name(parsed, 'node') self.assertEqual({'get_secret': 'secret'}, node['properties']['property']) functions.evaluate_functions( parsed, {}, None, None, None, self._get_secret_mock ) self.assertEqual(node['properties']['property'], 'secret_value')
def test_invalid_version(self): yaml = """ node_types: type: properties: property: {} node_templates: node: type: type properties: property: { concat: [1, 2] } """ with ExpectedException(exceptions.FunctionEvaluationError, '.*version 1_1 or greater.*'): prepare_deployment_plan(self.parse( yaml, dsl_version=self.BASIC_VERSION_SECTION_DSL_1_0))
def create_deployment(self, blueprint_id, deployment_id, inputs=None): blueprint = self.get_blueprint(blueprint_id) plan = blueprint.plan try: deployment_plan = tasks.prepare_deployment_plan(plan, inputs) except parser_exceptions.MissingRequiredInputError, e: raise manager_exceptions.MissingRequiredDeploymentInputError( str(e))
def test_circular_self_get_property(self): yaml = """ node_types: vm_type: properties: a: { type: string } node_templates: vm: type: vm_type properties: a: [ { get_property: [SELF, a ] } ] """ try: prepare_deployment_plan(self.parse(yaml)) self.fail() except RuntimeError, e: self.assertIn('Circular get_property function call detected', str(e))
def test_relationship_operation_inputs(self): yaml = """ plugins: p: executor: central_deployment_agent install: false node_types: type: properties: property: {} relationships: cloudify.relationships.contained_in: {} node_templates: node: type: type properties: property: value relationships: - type: cloudify.relationships.contained_in target: node2 source_interfaces: interface: op: implementation: p.task inputs: input1: { concat: [one, { get_property: [SOURCE, property] }, three] } input2: key1: value1 key2: { concat: [one, { get_property: [SOURCE, property] }, three] } key3: - item1 - { concat: [one, {get_property: [TARGET, property]}, three] } input3: { concat: [one, {get_property: [SOURCE, property] }, {get_attribute: [SOURCE, attribute] }]} node2: type: type properties: property: value2 """ parsed = prepare_deployment_plan(self.parse_1_1(yaml)) inputs = self.get_node_by_name(parsed, 'node')['relationships'][0][ 'source_operations']['interface.op']['inputs'] self.assertEqual('onevaluethree', inputs['input1']) self.assertEqual('onevaluethree', inputs['input2']['key2']) self.assertEqual('onevalue2three', inputs['input2']['key3'][1]) self.assertEqual({'concat': ['one', 'value', {'get_attribute': ['SOURCE', 'attribute']}]}, inputs['input3'])
def test_nested_property_path(self): yaml = """ node_types: vm_type: properties: endpoint: {} a: { type: integer } b: {} c: {} server_type: properties: port: { type: integer } node_templates: vm: type: vm_type properties: endpoint: url: protocol: http port: 80 names: [site1, site2, site3] pairs: - key: key1 value: value1 - key: key2 value: value2 a: { get_property: [ SELF, endpoint, port ] } b: { get_property: [ SELF, endpoint, names, 0 ] } c: { get_property: [ SELF, endpoint, pairs, 1 , key] } server: type: server_type properties: port: { get_property: [ vm, endpoint, port ] } outputs: a: value: { get_property: [ vm, endpoint, port ] } b: value: { get_property: [ vm, endpoint, url, protocol ] } c: value: { get_property: [ vm, endpoint, names, 1 ] } d: value: { get_property: [ vm, endpoint, pairs, 1, value] } """ parsed = prepare_deployment_plan(self.parse(yaml)) vm = self.get_node_by_name(parsed, 'vm') self.assertEqual(80, vm['properties']['a']) self.assertEqual('site1', vm['properties']['b']) self.assertEqual('key2', vm['properties']['c']) server = self.get_node_by_name(parsed, 'server') self.assertEqual(80, server['properties']['port']) outputs = parsed.outputs self.assertEqual(80, outputs['a']['value']) self.assertEqual('http', outputs['b']['value']) self.assertEqual('site2', outputs['c']['value']) self.assertEqual('value2', outputs['d']['value'])
def test_invalid_nested_property2(self): yaml = """ node_types: vm_type: properties: a: {} b: {} node_templates: vm: type: vm_type properties: a: [1,2,3] b: { get_property: [SELF, a, b] } """ try: prepare_deployment_plan(self.parse(yaml)) self.fail() except TypeError, e: self.assertIn('is expected b to be an int but it is a str', str(e))
def test_circular_get_property_with_nesting(self): yaml = """ node_types: vm_type: properties: b: { type: string } c: { type: string } node_templates: vm: type: vm_type properties: b: { get_property: [SELF, c] } c: [ { get_property: [SELF, b ] }, 2 ] """ try: prepare_deployment_plan(self.parse(yaml)) self.fail() except RuntimeError as e: self.assertIn('Circular get_property function call detected', str(e))
def test_invalid_nested_property1(self): yaml = """ node_types: vm_type: properties: a: { type: string } node_templates: vm: type: vm_type properties: a: a0: { get_property: [ SELF, a, notfound ] } """ try: prepare_deployment_plan(self.parse(yaml)) self.fail() except KeyError, e: self.assertIn( "Node template property 'vm.properties.a.notfound' " "referenced from 'vm.properties.a.a0' doesn't exist.", str(e))
def test_invalid_nested_property3(self): yaml = """ node_types: vm_type: properties: a: {} b: {} node_templates: vm: type: vm_type properties: a: [1,2,3] b: { get_property: [SELF, a, 10] } """ try: prepare_deployment_plan(self.parse(yaml)) self.fail() except IndexError, e: self.assertIn('index is out of range. Got 10 but list size is 3', str(e))
def _parse_plan(blueprint_path, inputs, ignored_modules): if dsl_parser is None: raise ImportError('cloudify-dsl-parser must be installed to ' 'execute local workflows. ' '(e.g. "pip install cloudify-dsl-parser")') plan = dsl_tasks.prepare_deployment_plan( dsl_parser.parse_from_path(blueprint_path), inputs=inputs) nodes = [Node(node) for node in plan['nodes']] node_instances = [NodeInstance(instance) for instance in plan['node_instances']] _prepare_nodes_and_instances(nodes, node_instances, ignored_modules) return plan, nodes, node_instances
def test_circular_nested_property_path(self): yaml = """ node_types: vm_type: properties: a: { type: string } b: { type: string } node_templates: vm: type: vm_type properties: a: a0: { get_property: [ SELF, b, b0 ] } b: b0: { get_property: [ SELF, a, a0 ] } """ try: prepare_deployment_plan(self.parse(yaml)) self.fail() except RuntimeError as e: self.assertIn('Circular get_property function call detected:', str(e))
def test_not_circular_nested_property_path(self): yaml = """ node_types: vm_type: properties: a: { type: string } b: { type: string } node_templates: vm1: type: vm_type properties: a: { get_property: [ vm2, a ] } b: bla1 vm2: type: vm_type properties: a: b3: b4: { get_property: [ vm1, b ] } b: bla2 """ prepare_deployment_plan(self.parse(yaml))
def test_get_property_from_get_input_missing_key(self): yaml = """ inputs: dict_input: {} node_types: vm_type: properties: a: { type: string } b: { type: string } node_templates: vm1: type: vm_type properties: a: {get_input: dict_input} b: {get_property: [SELF, a, key]} """ try: prepare_deployment_plan( self.parse(yaml), inputs={'dict_input': {'other_key': 42}}) self.fail() except KeyError as e: self.assertIn('vm1.properties.a.key', e.message)
def stage_deployment_update(self, deployment_id, app_dir, app_blueprint, additional_inputs): """Stage a deployment update :param app_blueprint: :param app_dir: :param deployment_id: the deployment id for the update :return: """ # enables reverting to original blueprint resources deployment = self.sm.get_deployment(deployment_id) blueprint_id = deployment.blueprint_id # enables reverting to original blueprint resources file_server_base_url = \ '{0}/'.format(config.instance().file_server_base_uri) blueprint_resource_dir = os.path.join(file_server_base_url, 'blueprints', blueprint_id) app_path = os.path.join(file_server_base_url, app_dir, app_blueprint) # parsing the blueprint from here try: plan = tasks.parse_dsl( app_path, resources_base_url=file_server_base_url, additional_resources=[blueprint_resource_dir], **app_context.get_parser_context()) except parser_exceptions.DSLParsingException as ex: raise manager_exceptions.InvalidBlueprintError( 'Invalid blueprint - {0}'.format(ex)) # Updating the new inputs with the deployment inputs # (overriding old values and adding new ones) inputs = copy.deepcopy(deployment.inputs) inputs.update(additional_inputs) # applying intrinsic functions try: prepared_plan = tasks.prepare_deployment_plan(plan, inputs=inputs) except parser_exceptions.MissingRequiredInputError, e: raise manager_exceptions.MissingRequiredDeploymentInputError( str(e))
def test_node_template_properties_simple(self): yaml = """ node_types: type: properties: property: {} node_templates: node: type: type properties: property: { concat: [one, two, three] } """ parsed = prepare_deployment_plan(self.parse_1_1(yaml)) node = self.get_node_by_name(parsed, 'node') self.assertEqual('onetwothree', node['properties']['property'])
def stage_deployment_update(self, deployment_id, app_dir, app_blueprint, additional_inputs, new_blueprint_id=None, preview=False): # enables reverting to original blueprint resources deployment = self.sm.get(models.Deployment, deployment_id) old_blueprint = deployment.blueprint file_server_root = config.instance.file_server_root blueprint_resource_dir = os.path.join(file_server_root, 'blueprints', old_blueprint.tenant_name, old_blueprint.id) # The dsl parser expects a URL blueprint_resource_dir_url = 'file:{0}'.format(blueprint_resource_dir) app_path = os.path.join(file_server_root, app_dir, app_blueprint) # parsing the blueprint from here try: plan = tasks.parse_dsl( app_path, resources_base_path=file_server_root, additional_resources=[blueprint_resource_dir_url], **app_context.get_parser_context() ) except parser_exceptions.DSLParsingException as ex: raise manager_exceptions.InvalidBlueprintError( 'Invalid blueprint - {0}'.format(ex)) # Updating the new inputs with the deployment inputs # (overriding old values and adding new ones) old_inputs = copy.deepcopy(deployment.inputs) new_inputs = {k: old_inputs[k] for k in plan.inputs.keys() if k in old_inputs} new_inputs.update(additional_inputs) # applying intrinsic functions try: prepared_plan = tasks.prepare_deployment_plan(plan, get_secret_method(), inputs=new_inputs) except parser_exceptions.MissingRequiredInputError, e: raise manager_exceptions.MissingRequiredDeploymentInputError( str(e))
def _parse_plan(blueprint_path, inputs, ignored_modules, resolver, validate_version): if dsl_parser is None: raise ImportError('cloudify-dsl-parser must be installed to ' 'execute local workflows. ' '(e.g. "pip install cloudify-dsl-parser") [{0}]' .format(_import_error)) plan = dsl_tasks.prepare_deployment_plan( dsl_parser.parse_from_path( dsl_file_path=blueprint_path, resolver=resolver, validate_version=validate_version), inputs=inputs) nodes = [Node(node) for node in plan['nodes']] node_instances = [NodeInstance(instance) for instance in plan['node_instances']] _prepare_nodes_and_instances(nodes, node_instances, ignored_modules) return plan, nodes, node_instances