Difference between revisions of "Heat Mistral resources usage examples"
Prazumovsky (talk | contribs) |
|||
(30 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | == | + | == Creating resources using Heat template and check that they are available in Mistral service. == |
− | + | This case means creating stack with one Mistral Workflow resource, which allows to create nova server. After creating stack workflow can be executed. Workflow execution in Heat means sending signal to workflow resource with, perhaps, some data. This case checks workflow execution with and without data. | |
− | + | === Create Mistral workflow resource using Heat OS::Mistral::Workflow === | |
− | |||
− | + | heat_template_version: 2013-05-23 | |
− | type: | + | parameters: |
− | + | image: | |
− | - | + | type: string |
− | - | + | flavor: |
− | + | type: string | |
− | + | default: 2 | |
− | + | name: | |
+ | type: string | ||
+ | default: mistral-test | ||
+ | resources: | ||
+ | create_vm: | ||
+ | type: OS::Mistral::Workflow | ||
+ | properties: | ||
+ | type: direct | ||
+ | input: | ||
+ | name: { get_param: name } | ||
+ | image: { get_param: image } | ||
+ | flavor: { get_param: flavor } | ||
+ | output: | ||
+ | vm_id: <% $.vm_id %> | ||
+ | tasks: | ||
+ | - name: create_server | ||
+ | action: nova.servers_create name=<% $.name %> image=<% $.image %> flavor=<% $.flavor %> | ||
+ | publish: | ||
+ | vm_id: <% $.create_server.id %> | ||
+ | on_success: | ||
+ | - check_server_exists | ||
+ | - name: check_server_exists | ||
+ | action: nova.servers_get server=<% $.vm_id %> | ||
+ | publish: | ||
+ | server_exists: True | ||
+ | on_success: | ||
+ | - wait_instance | ||
+ | - name: wait_instance | ||
+ | action: nova.servers_find id=<% $.vm_id %> status='ACTIVE' | ||
+ | policies: | ||
+ | retry: | ||
+ | delay: 5 | ||
+ | count: 15 | ||
+ | outputs: | ||
+ | executions: | ||
+ | value: { get_attr: [create_vm, executions] } | ||
+ | data: | ||
+ | value: { get_attr: [create_vm, data] } | ||
− | + | === Create stack === | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | heat stack-create test -f template.yaml -P image=31d8eeaf-686e-4e95-bb27-765014b9f20b | |
− | + | {| class="wikitable" | |
− | + | |- | |
− | + | ! id !! stack_name !! stack_status !! creation_time | |
− | + | |- | |
− | + | | <small>45fef0d8-be8f-4d67-a105-aff2707f5ced</small> || <small>test</small> || <small>CREATE_COMPLETE</small> || <small>2015-02-16T12:58:52Z</small> | |
+ | |} | ||
− | + | === Execute workflow using command heat resource-signal === | |
− | |||
− | |||
− | |||
− | |||
− | |||
+ | heat resource-signal test create_vm | ||
+ | mistral execution-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! ID !! Workflow !! State !! Created at !! Updated at | ||
+ | |- | ||
+ | | <small>2cc27206-ee42-44ca-bf30-1907f90709e4</small> || <small>test-create_vm-6mk5u42i4dqa</small> || <small>SUCCESS</small> || <small>2015-02-16 13:01:37</small> || <small>2015-02-16 13:02:01</small> | ||
+ | |} | ||
+ | nova list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! ID !! Name !! Status !! Task State !! Power State !! Networks | ||
+ | |- | ||
+ | | <small>853d9117-d4e1-4454-a066-ec3dd5863193</small> || <small>mistral-test</small> || <small>ACTIVE</small> || <small>-</small> || <small>Running</small> || <small>private=10.0.0.39</small> | ||
+ | |} | ||
− | === | + | === Execute workflow using resource-signal with non-default workflow input === |
+ | heat resource-signal test create_vm -D '{"input": {"image": "6e8ee0ce-1a53-4dc7-a97e-6332badbb3fa"}}' | ||
+ | mistral execution-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! ID !! Workflow !! State !! Created at !! Updated at | ||
+ | |- | ||
+ | | <small>2cc27206-ee42-44ca-bf30-1907f90709e4</small> || <small>test-create_vm-6mk5u42i4dqa</small> || <small>SUCCESS</small> || <small>2015-02-16 13:01:37</small> || <small>2015-02-16 13:02:01</small> | ||
+ | |- | ||
+ | | <small>f67c611c-adf7-4ad6-b5ab-27cc5fe79c34</small> || <small>test-create_vm-6mk5u42i4dqa</small> || <small>SUCCESS</small> || <small>2015-02-16 13:08:23</small> || <small>2015-02-16 13:08:45</small> | ||
+ | |} | ||
− | + | === Check stack outputs === | |
+ | heat stack-show test | ||
− | + | | | { | |
− | + | | | "output_value": { | |
− | + | | | "input": { | |
− | + | | | "image": "31d8eeaf-686e-4e95-bb27-765014b9f20b", | |
+ | | | "name": "mistral-test", | ||
+ | | | "flavor": 2 | ||
+ | | | }, | ||
+ | | | "name": "test-create_vm-6mk5u42i4dqa" | ||
+ | | | }, | ||
+ | | | "description": "No description given", | ||
+ | | | "output_key": "data" | ||
+ | | | }, | ||
+ | | | { | ||
+ | | | "output_value": [ | ||
+ | | | { | ||
+ | | | "workflow_name": "test-create_vm-6mk5u42i4dqa", | ||
+ | | | "created_at": "2015-02-16 13:08:23", | ||
+ | | | "updated_at": "2015-02-16 13:08:45", | ||
+ | | | "state": "SUCCESS", | ||
+ | | | "input": { | ||
+ | | | "image": "6e8ee0ce-1a53-4dc7-a97e-6332badbb3fa", | ||
+ | | | "name": "mistral-test", | ||
+ | | | "flavor": 2 | ||
+ | | | }, | ||
+ | | | "output": { | ||
+ | | | "vm_id": "d7f33c8e-6855-4d17-a39b-325323f6eaee" | ||
+ | | | }, | ||
+ | | | "id": "f67c611c-adf7-4ad6-b5ab-27cc5fe79c34" | ||
+ | | | }, | ||
+ | | | { | ||
+ | | | "workflow_name": "test-create_vm-6mk5u42i4dqa", | ||
+ | | | "created_at": "2015-02-16 13:01:37", | ||
+ | | | "updated_at": "2015-02-16 13:02:01", | ||
+ | | | "state": "SUCCESS", | ||
+ | | | "input": { | ||
+ | | | "image": "31d8eeaf-686e-4e95-bb27-765014b9f20b", | ||
+ | | | "name": "mistral-test", | ||
+ | | | "flavor": 2 | ||
+ | | | }, | ||
+ | | | "output": { | ||
+ | | | "vm_id": "853d9117-d4e1-4454-a066-ec3dd5863193" | ||
+ | | | }, | ||
+ | | | "id": "2cc27206-ee42-44ca-bf30-1907f90709e4" | ||
+ | | | } | ||
+ | | | ], | ||
+ | | | "description": "No description given", | ||
+ | | | "output_key": "executions" | ||
+ | | | } | ||
+ | | | ] | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | == Using Ceilometer Alarm with Mistral workflow in Heat. == | |
− | |||
− | |||
− | |||
− | |||
− | + | In this case stack creates with Mistral workflow, which allows to create nova server, and Ceilometer alarm, which send signal to execute workflow. After stack creation alarm get state 'alarm' and sends signal to workflow resource. It executed and creates nova server. | |
− | |||
− | |||
+ | === Create Heat template (template.yaml) which uses Mistral workflow and Ceilometer alarm resources === | ||
+ | heat_template_version: 2013-05-23 | ||
+ | resources: | ||
+ | workflow: | ||
+ | type: OS::Mistral::Workflow | ||
+ | properties: | ||
+ | type: direct | ||
+ | tasks: | ||
+ | - name: alarm | ||
+ | action: std.echo output='alarm!' | ||
+ | publish: | ||
+ | state: 'alarm!' | ||
+ | alarm: | ||
+ | type: OS::Ceilometer::Alarm | ||
+ | properties: | ||
+ | meter_name: instance | ||
+ | statistic: count | ||
+ | period: 60 | ||
+ | evaluation_periods: 1 | ||
+ | threshold: 100 | ||
+ | alarm_actions: | ||
+ | - {get_attr: [workflow, alarm_url] } | ||
+ | comparison_operator: lt | ||
+ | === Create Heat stack using template template.yaml === | ||
+ | heat stack-create test -f heat-templates/mistral-and-ceilometer.yaml | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! id !! stack_name !! stack_status !! creation_time | ||
+ | |- | ||
+ | | <small>7f59798f-212a-4dd3-b3c8-a85a23cb3101</small> || <small>test</small> || <small>CREATE_IN_PROGRESS</small> || <small>2015-02-17T07:23:42Z</small> | ||
+ | |} | ||
+ | mistral workflow-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! Name !! Tags !! Input !! Created at !! Updated at | ||
+ | |- | ||
+ | | <small>std.create_instance</small> || <small><none></small> || <small>name, image_id, flavor_id...</small> || <small>2015-02-05 14:35:25</small> || <small>None</small> | ||
+ | |- | ||
+ | | <small>std.delete_instance</small> || <small><none></small> || <small>instance_id</small> || <small>2015-02-05 14:35:25</small> || <small>None</small> | ||
+ | |- | ||
+ | | <small>test-workflow-7y5jqbwjksy2</small> || <small><none></small> || <small>None</small> || <small>2015-02-17 07:23:42</small> || <small>None</small> | ||
+ | |} | ||
+ | ceilometer alarm-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! Alarm ID !! Name !! State !! Enabled !! Continuous !! Alarm condition !! Time constraints | ||
+ | |- | ||
+ | | <small>14016498-00c1-4e12-8076-1c4f14f02a67</small> || <small>test-alarm-v7we7aapuvsn</small> || <small>insufficient data</small> || <small>True</small> || <small>True</small> || <small>instance < 100.0 during 1 x 60s</small> || <small>None</small> | ||
+ | |} | ||
− | === | + | === Wait until Ceilometer alarm get state 'alarm' === |
+ | ceilometer alarm-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! Alarm ID !! Name !! State !! Enabled !! Continuous !! Alarm condition !! Time constraints | ||
+ | |- | ||
+ | | <small>14016498-00c1-4e12-8076-1c4f14f02a67</small> || <small>test-alarm-v7we7aapuvsn</small> || <small>alarm</small> || <small>True</small> || <small>True</small> || <small>instance < 100.0 during 1 x 60s</small> || <small>None</small> | ||
+ | |} | ||
+ | mistral execution-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! ID !! Workflow !! State !! Created at !! Updated at | ||
+ | |- | ||
+ | | <small>85cff77d-3da5-423b-a4ca-fb8be4a9ce2f</small> || <small>test-workflow-7y5jqbwjksy2</small> || <small>SUCCESS</small> || <small>2015-02-17 07:31:35</small> || <small>2015-02-17 07:31:35</small> | ||
+ | |} | ||
− | + | === Check execution output (it must equals 'alarm!') === | |
+ | mistral execution-get-output 85cff77d-3da5-423b-a4ca-fb8be4a9ce2f | ||
+ | ... | ||
+ | "state": "alarm!", | ||
+ | "alarm": { | ||
+ | "state": "alarm!" | ||
+ | }, | ||
+ | ... | ||
− | |||
− | + | == Testing autoscaling using Mistral resources. == | |
− | + | This case shows how to use mistral resources for autoscale testing. In this stack workflows are used to get ip of the server and to load/release cpu and triggers allow to execute these workflows (every 10 minutes by default). | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | === Create template heat_autoscaling_nova.yaml with Mistral resources, Ceilometer alarms and Heat autoscaling group === | |
− | + | heat_template_version: 2014-10-16 | |
− | + | parameters: | |
− | + | InstanceType: | |
− | | | + | type: string |
− | + | default: m1.heat | |
+ | ImageId: | ||
+ | type: string | ||
+ | default: cirros-0.3.2-x86_64-uec | ||
+ | User: | ||
+ | type: string | ||
+ | default: cirros | ||
+ | Password: | ||
+ | type: string | ||
+ | default: 'cubswin:)' | ||
+ | Pattern_release: | ||
+ | type: string | ||
+ | default: "0,20,40 * * * *" | ||
+ | description: Time to execute workflow wf_release_cpu | ||
+ | Pattern_load: | ||
+ | type: string | ||
+ | default: "10,30,50 * * * *" | ||
+ | description: Time to execute workflow wf_load_cpu | ||
+ | |||
+ | resources: | ||
+ | my_asg: | ||
+ | type: OS::Heat::AutoScalingGroup | ||
+ | properties: | ||
+ | resource: | ||
+ | type: server_with_ip.yaml | ||
+ | properties: | ||
+ | image: { get_param: ImageId } | ||
+ | flavor: { get_param: InstanceType } | ||
+ | security_group: {get_resource: security_group} | ||
+ | metadata: {"metering.stack": {get_param: "OS::stack_id"}} | ||
+ | min_size: 1 | ||
+ | max_size: 2 | ||
+ | scale_up_policy: | ||
+ | type: OS::Heat::ScalingPolicy | ||
+ | properties: | ||
+ | adjustment_type: change_in_capacity | ||
+ | auto_scaling_group_id: {get_resource: my_asg} | ||
+ | cooldown: 60 | ||
+ | scaling_adjustment: 1 | ||
+ | scale_down_policy: | ||
+ | type: OS::Heat::ScalingPolicy | ||
+ | properties: | ||
+ | adjustment_type: change_in_capacity | ||
+ | auto_scaling_group_id: {get_resource: my_asg} | ||
+ | cooldown: 60 | ||
+ | scaling_adjustment: '-1' | ||
+ | cpu_alarm_high: | ||
+ | type: OS::Ceilometer::Alarm | ||
+ | properties: | ||
+ | description: Scale-up if the average CPU > 50% for 1 minute | ||
+ | meter_name: cpu_util | ||
+ | statistic: avg | ||
+ | period: 60 | ||
+ | evaluation_periods: 1 | ||
+ | threshold: 50 | ||
+ | alarm_actions: | ||
+ | - {get_attr: [scale_up_policy, alarm_url]} | ||
+ | matching_metadata: {'metadata.user_metadata.stack': {get_param: "OS::stack_id"}} | ||
+ | comparison_operator: gt | ||
+ | cpu_alarm_low: | ||
+ | type: OS::Ceilometer::Alarm | ||
+ | properties: | ||
+ | description: Scale-down if the average CPU < 15% for 1 minutes | ||
+ | meter_name: cpu_util | ||
+ | statistic: avg | ||
+ | period: 60 | ||
+ | evaluation_periods: 1 | ||
+ | threshold: 15 | ||
+ | alarm_actions: | ||
+ | - {get_attr: [scale_down_policy, alarm_url]} | ||
+ | matching_metadata: {'metadata.user_metadata.stack': {get_param: "OS::stack_id"}} | ||
+ | comparison_operator: lt | ||
+ | security_group: | ||
+ | type: AWS::EC2::SecurityGroup | ||
+ | properties: | ||
+ | GroupDescription: 'Enable SSH access' | ||
+ | SecurityGroupIngress: | ||
+ | - IpProtocol: 'tcp' | ||
+ | FromPort: '22' | ||
+ | ToPort : '22' | ||
+ | CidrIp : '0.0.0.0/0' | ||
+ | wf_load_cpu: | ||
+ | type: OS::Mistral::Workflow | ||
+ | properties: | ||
+ | type: direct | ||
+ | tasks: | ||
+ | - name: get_output | ||
+ | action: heat.stacks_get stack_id=<% $.stack_id %> | ||
+ | publish: | ||
+ | vm_ip: <% $.get_output._info.outputs[0].output_value %> | ||
+ | on_success: | ||
+ | - run_ssh | ||
+ | - name: run_ssh | ||
+ | action: std.ssh cmd='cat /dev/urandom | gzip -9 > /dev/null &' host=<% $.vm_ip %> username=<% $.user %> password=<% $.password %> | ||
+ | input: {'user': {get_param: User}, 'password': {get_param: Password}, 'stack_id': {get_param: "OS::stack_id"}} | ||
+ | wf_release_cpu: | ||
+ | type: OS::Mistral::Workflow | ||
+ | properties: | ||
+ | type: direct | ||
+ | tasks: | ||
+ | - name: get_output | ||
+ | action: heat.stacks_get stack_id=<% $.stack_id %> | ||
+ | publish: | ||
+ | vm_ip: <% $.get_output._info.outputs[0].output_value %> | ||
+ | on_success: | ||
+ | - run_ssh | ||
+ | - name: run_ssh | ||
+ | action: std.ssh cmd="kill -9 $(ps aux | grep 'cat /dev/urandom' | awk '{print $1}')" host=<% $.vm_ip %> username=<% $.user %> password=<% $.password %> | ||
+ | input: {'user': {get_param: User}, 'password': {get_param: Password}, 'stack_id': {get_param: "OS::stack_id"}} | ||
+ | trigger_load_cpu: | ||
+ | type: OS::Mistral::CronTrigger | ||
+ | properties: | ||
+ | pattern: {get_param: Pattern_load} | ||
+ | workflow: {get_attr: [wf_load_cpu, data]} | ||
+ | trigger_release_cpu: | ||
+ | type: OS::Mistral::CronTrigger | ||
+ | properties: | ||
+ | pattern: {get_param: Pattern_release} | ||
+ | workflow: {get_attr: [wf_release_cpu, data]} | ||
+ | outputs: | ||
+ | ip: | ||
+ | value: {'Fn::Select': ['0', {get_attr: [my_asg, outputs_list, ip]}]} | ||
+ | |||
+ | === Create template server_with_ip.yaml for nested stack === | ||
+ | heat_template_version: 2013-05-23 | ||
+ | parameters: | ||
+ | image: | ||
+ | type: string | ||
+ | flavor: | ||
+ | type: string | ||
+ | security_group: | ||
+ | type: string | ||
+ | metadata: | ||
+ | type: json | ||
+ | resources: | ||
+ | server: | ||
+ | type: OS::Nova::Server | ||
+ | properties: | ||
+ | flavor: {get_param: flavor} | ||
+ | image: {get_param: image} | ||
+ | metadata: {get_param: metadata} | ||
+ | security_groups: | ||
+ | - get_param: security_group | ||
+ | floating_ip: | ||
+ | type: OS::Nova::FloatingIP | ||
+ | floating_ip_association: | ||
+ | type: OS::Nova::FloatingIPAssociation | ||
+ | properties: | ||
+ | floating_ip: {get_resource: floating_ip} | ||
+ | server_id: {get_resource: server} | ||
+ | outputs: | ||
+ | ip: | ||
+ | value: {get_attr: [floating_ip, ip]} | ||
+ | server_id: | ||
+ | value: {get_resource: server} | ||
+ | |||
+ | === Create stack === | ||
+ | heat stack-create test-asg -f heat_autoscaling_nova.yaml | ||
+ | |||
+ | === Check that resources were created === | ||
+ | heat stack-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! id !! stack_name !! stack_status !! creation_time | ||
+ | |- | ||
+ | | <small>8e1b54a1-eefe-43e1-a316-7397e904e328</small> || <small>test-asg</small> || <small>CREATE_COMPLETE</small> || <small>2015-02-10T15:45:29Z</small> | ||
+ | |} | ||
+ | nova list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! ID !! Name !! Status !! Task State !! Power State !! Networks | ||
+ | |- | ||
+ | | <small>b2e9edcd-da08-4e02-92b4-79c6f1c87203</small> || <small>te-fpjq-mgcxiz3lglm4-jza3vpraqlrs-server-y7jdd3voh4no</small> || <small>ACTIVE</small> || <small>-</small> || <small>Running</small> || <small>private=10.0.0.2, 172.24.4.1</small> | ||
+ | |} | ||
+ | ceilometer alarm-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! Alarm ID !! Name !! State !! Enabled !! Continuous !! Alarm condition !! Time constraints | ||
+ | |- | ||
+ | | <small>2f338088-d74c-41b6-baf1-185ad3fbe2cc</small> || <small>test-asg-cpu_alarm_high-rh5l5jerjhs6</small> || <small>ok</small> || <small>True</small> || <small>True</small> || <small>cpu_util > 50.0 during 1 x 60s</small> || <small>None</small> | ||
+ | |- | ||
+ | | <small>5053d1c6-66f0-4a4a-a52a-24d3e8881c4d</small> || <small>test-asg-cpu_alarm_low-n6rvsykaaiba</small> || <small>ok</small> || <small>True</small> || <small>True</small> || <small>cpu_util < 15.0 during 1 x 60s</small> || <small>None</small> | ||
+ | |} | ||
+ | mistral workflow-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! Name !! Tags !! Input !! Created at !! Updated at | ||
+ | |- | ||
+ | | <small>std.create_instance</small> || <small><none></small> || <small>name, image_id, flavor_id...</small> || <small>2015-02-05 14:35:25</small> || <small>None</small> | ||
+ | |- | ||
+ | | <small>std.delete_instance</small> || <small><none></small> || <small>instance_id</small> || <small>2015-02-05 14:35:25</small> || <small>None</small> | ||
+ | |- | ||
+ | | <small>test-asg.wf_load_cpu.load_vm</small> || <small><none></small> || <small>vm_ip, user, password</small> || <small>2015-02-10 15:45:53</small> || <small>None</small> | ||
+ | |- | ||
+ | | <small>test-asg.wf_release_cpu.release_vm</small> || <small><none></small> || <small>vm_ip, user, password</small> || <small>2015-02-10 15:45:51</small> || <small>None</small> | ||
+ | |} | ||
+ | mistral cron-trigger-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! Name !! Pattern !! Workflow !! Next execution time !! Created at !! Updated at | ||
+ | |- | ||
+ | | <small>test-asg-trigger_load_cpu-isepguoldk6y</small> || <small>10,30,50 * * * *</small> || <small>test-asg.wf_load_cpu.load_vm</small> || <small>2015-02-10 10:50:00</small> || <small>2015-02-10 15:45:59</small> || <small>None</small> | ||
+ | |- | ||
+ | | <small>test-asg-trigger_release_cpu-nvcj3ycphg4g</small> || <small>0,20,40 * * * *</small> || <small>test-asg.wf_release_cpu.release_vm</small> || <small>2015-02-10 11:00:00</small> || <small>2015-02-10 15:45:56</small> || <small>None</small> | ||
+ | |} | ||
+ | |||
+ | === Wait for 10:50 (next execution time of trigger_load_cpu) and check again === | ||
+ | ceilometer alarm-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! Alarm ID !! Name !! State !! Enabled !! Continuous !! Alarm condition !! Time constraints | ||
+ | |- | ||
+ | | <small>2f338088-d74c-41b6-baf1-185ad3fbe2cc</small> || <small>test-asg-cpu_alarm_high-rh5l5jerjhs6</small> || <small>alarm</small> || <small>True</small> || <small>True</small> || <small>cpu_util > 50.0 during 1 x 60s</small> || <small>None</small> | ||
+ | |- | ||
+ | | <small>5053d1c6-66f0-4a4a-a52a-24d3e8881c4d</small> || <small>test-asg-cpu_alarm_low-n6rvsykaaiba</small> || <small>ok</small> || <small>True</small> || <small>True</small> || <small>cpu_util < 15.0 during 1 x 60s</small> || <small>None</small> | ||
+ | |} | ||
+ | nova list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! ID !! Name !! Status !! Task State !! Power State !! Networks | ||
+ | |- | ||
+ | | <small>b2e9edcd-da08-4e02-92b4-79c6f1c87203</small> || <small>te-fpjq-mgcxiz3lglm4-jza3vpraqlrs-server-y7jdd3voh4no</small> || <small>ACTIVE</small> || <small>-</small> || <small>Running</small> || <small>private=10.0.0.2, 172.24.4.1</small> | ||
+ | |- | ||
+ | | <small>8ffbd4ac-435a-4d9d-80cc-23940302fadd</small> || <small>te-fpjq-oj6r53u24m4g-kdiexra2fs5b-server-mbhtpfvi3nys</small> || <small>ACTIVE</small> || <small>-</small> || <small>Running</small> || <small>private=10.0.0.3, 172.24.4.2</small> | ||
+ | |} | ||
+ | |||
+ | === Wait for 11:00 (next execution time of trigger_release_cpu) === | ||
+ | ceilometer alarm-list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! Alarm ID !! Name !! State !! Enabled !! Continuous !! Alarm condition !! Time constraints | ||
+ | |- | ||
+ | | <small>2f338088-d74c-41b6-baf1-185ad3fbe2cc</small> || <small>test-asg-cpu_alarm_high-rh5l5jerjhs6</small> || <small>ok</small> || <small>True</small> || <small>True</small> || <small>cpu_util > 50.0 during 1 x 60s</small> || <small>None</small> | ||
+ | |- | ||
+ | | <small>5053d1c6-66f0-4a4a-a52a-24d3e8881c4d</small> || <small>test-asg-cpu_alarm_low-n6rvsykaaiba</small> || <small>alarm</small> || <small>True</small> || <small>True</small> || <small>cpu_util < 15.0 during 1 x 60s</small> || <small>None</small> | ||
+ | |} | ||
+ | nova list | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! ID !! Name !! Status !! Task State !! Power State !! Networks | ||
+ | |- | ||
+ | | <small>8ffbd4ac-435a-4d9d-80cc-23940302fadd</small> || <small>te-fpjq-oj6r53u24m4g-kdiexra2fs5b-server-mbhtpfvi3nys</small> || <small>ACTIVE</small> || <small>-</small> || <small>Running</small> || <small>private=10.0.0.3, 172.24.4.2</small> | ||
+ | |} | ||
+ | |||
+ | |||
+ | == Heat templates using Mistral resources examples == | ||
+ | |||
+ | === Mistral Workflow resource using property name === | ||
+ | |||
+ | This template create stack with Workflow resource named stack_name-workflow-test_workflow. | ||
+ | |||
+ | heat_template_version: 2013-05-23 | ||
+ | resources: | ||
+ | workflow: | ||
+ | type: OS::Mistral::Workflow | ||
+ | properties: | ||
+ | type: direct | ||
+ | name: test_workflow | ||
+ | description: Just testing workflow resource. | ||
+ | input: | ||
+ | phrase: Hello! | ||
+ | output: | ||
+ | out: <% $.word %> | ||
+ | tasks: | ||
+ | - name: hello | ||
+ | action: std.echo output=<% $.phrase %> | ||
+ | publish: | ||
+ | word: <% $.hello %> | ||
+ | outputs: | ||
+ | exec: | ||
+ | value: { get_attr: [workflow, executions] } | ||
+ | |||
+ | === Two Mistral Workflows with referencing by intrinsic function get_resource === | ||
+ | |||
+ | This template create stack with two Workflow resources, one of them references to another by intrinsic function get_resource. | ||
+ | |||
+ | heat_template_version: 2013-05-23 | ||
+ | resources: | ||
+ | wf1: | ||
+ | type: OS::Mistral::Workflow | ||
+ | properties: | ||
+ | type: direct | ||
+ | tasks: | ||
+ | - name: hello! | ||
+ | action: std.noop | ||
+ | wf2: | ||
+ | type: OS::Mistral::Workflow | ||
+ | properties: | ||
+ | type: direct | ||
+ | tasks: | ||
+ | - name: call | ||
+ | workflow: { get_resource: wf1 } | ||
+ | outputs: | ||
+ | name: | ||
+ | value: {get_attr: [wf2, data]} | ||
+ | |||
+ | === Reverse-type Mistral Workflow === | ||
+ | |||
+ | This template shows how to use reverse-type Workflows. If you want to execute this Workflow, you need to provide param task_name in resourse signal data, i.e.: | ||
+ | |||
+ | heat resource_signal test_stack create_vm -D '{"params": {"task_name": "create_vm"}}' | ||
+ | |||
+ | Template: | ||
+ | heat_template_version: 2013-05-23 | ||
+ | parameters: | ||
+ | image_id: | ||
+ | type: string | ||
+ | flavor: | ||
+ | type: string | ||
+ | default: 2 | ||
+ | resources: | ||
+ | create_vm: | ||
+ | type: OS::Mistral::Workflow | ||
+ | properties: | ||
+ | type: reverse | ||
+ | input: | ||
+ | vm_name: test | ||
+ | image_id: { get_param: image_id } | ||
+ | flavor_id: { get_param: flavor } | ||
+ | output: | ||
+ | result: <% $.vm_id %> | ||
+ | tasks: | ||
+ | - name: create_vm | ||
+ | action: nova.servers_create name=<% $.vm_name %> image=<% $.image_id %> flavor=<% $.flavor_id %> | ||
+ | publish: | ||
+ | vm_id: <% $.create_vm.id %> | ||
+ | - name: search_for_ip | ||
+ | action: nova.floating_ips_findall instance_id=null | ||
+ | publish: | ||
+ | vm_ip: <% $.search_for_ip[0].ip %> | ||
+ | - name: associate_ip | ||
+ | action: nova.servers_add_floating_ip server=<% $.vm_id %> address=<% $.vm_ip %> | ||
+ | requires: | ||
+ | - search_for_ip | ||
+ | - name: send_email | ||
+ | action: std.noop | ||
+ | publish: | ||
+ | vm_id: <% $.vm_id %> | ||
+ | vm_ip: <% $.vm_ip %> | ||
+ | requires: [create_vm, associate_ip] |
Latest revision as of 14:56, 10 March 2015
Contents
- 1 Creating resources using Heat template and check that they are available in Mistral service.
- 2 Using Ceilometer Alarm with Mistral workflow in Heat.
- 3 Testing autoscaling using Mistral resources.
- 3.1 Create template heat_autoscaling_nova.yaml with Mistral resources, Ceilometer alarms and Heat autoscaling group
- 3.2 Create template server_with_ip.yaml for nested stack
- 3.3 Create stack
- 3.4 Check that resources were created
- 3.5 Wait for 10:50 (next execution time of trigger_load_cpu) and check again
- 3.6 Wait for 11:00 (next execution time of trigger_release_cpu)
- 4 Heat templates using Mistral resources examples
Creating resources using Heat template and check that they are available in Mistral service.
This case means creating stack with one Mistral Workflow resource, which allows to create nova server. After creating stack workflow can be executed. Workflow execution in Heat means sending signal to workflow resource with, perhaps, some data. This case checks workflow execution with and without data.
Create Mistral workflow resource using Heat OS::Mistral::Workflow
heat_template_version: 2013-05-23 parameters: image: type: string flavor: type: string default: 2 name: type: string default: mistral-test resources: create_vm: type: OS::Mistral::Workflow properties: type: direct input: name: { get_param: name } image: { get_param: image } flavor: { get_param: flavor } output: vm_id: <% $.vm_id %> tasks: - name: create_server action: nova.servers_create name=<% $.name %> image=<% $.image %> flavor=<% $.flavor %> publish: vm_id: <% $.create_server.id %> on_success: - check_server_exists - name: check_server_exists action: nova.servers_get server=<% $.vm_id %> publish: server_exists: True on_success: - wait_instance - name: wait_instance action: nova.servers_find id=<% $.vm_id %> status='ACTIVE' policies: retry: delay: 5 count: 15 outputs: executions: value: { get_attr: [create_vm, executions] } data: value: { get_attr: [create_vm, data] }
Create stack
heat stack-create test -f template.yaml -P image=31d8eeaf-686e-4e95-bb27-765014b9f20b
id | stack_name | stack_status | creation_time |
---|---|---|---|
45fef0d8-be8f-4d67-a105-aff2707f5ced | test | CREATE_COMPLETE | 2015-02-16T12:58:52Z |
Execute workflow using command heat resource-signal
heat resource-signal test create_vm mistral execution-list
ID | Workflow | State | Created at | Updated at |
---|---|---|---|---|
2cc27206-ee42-44ca-bf30-1907f90709e4 | test-create_vm-6mk5u42i4dqa | SUCCESS | 2015-02-16 13:01:37 | 2015-02-16 13:02:01 |
nova list
ID | Name | Status | Task State | Power State | Networks |
---|---|---|---|---|---|
853d9117-d4e1-4454-a066-ec3dd5863193 | mistral-test | ACTIVE | - | Running | private=10.0.0.39 |
Execute workflow using resource-signal with non-default workflow input
heat resource-signal test create_vm -D '{"input": {"image": "6e8ee0ce-1a53-4dc7-a97e-6332badbb3fa"}}' mistral execution-list
ID | Workflow | State | Created at | Updated at |
---|---|---|---|---|
2cc27206-ee42-44ca-bf30-1907f90709e4 | test-create_vm-6mk5u42i4dqa | SUCCESS | 2015-02-16 13:01:37 | 2015-02-16 13:02:01 |
f67c611c-adf7-4ad6-b5ab-27cc5fe79c34 | test-create_vm-6mk5u42i4dqa | SUCCESS | 2015-02-16 13:08:23 | 2015-02-16 13:08:45 |
Check stack outputs
heat stack-show test
| | { | | "output_value": { | | "input": { | | "image": "31d8eeaf-686e-4e95-bb27-765014b9f20b", | | "name": "mistral-test", | | "flavor": 2 | | }, | | "name": "test-create_vm-6mk5u42i4dqa" | | }, | | "description": "No description given", | | "output_key": "data" | | }, | | { | | "output_value": [ | | { | | "workflow_name": "test-create_vm-6mk5u42i4dqa", | | "created_at": "2015-02-16 13:08:23", | | "updated_at": "2015-02-16 13:08:45", | | "state": "SUCCESS", | | "input": { | | "image": "6e8ee0ce-1a53-4dc7-a97e-6332badbb3fa", | | "name": "mistral-test", | | "flavor": 2 | | }, | | "output": { | | "vm_id": "d7f33c8e-6855-4d17-a39b-325323f6eaee" | | }, | | "id": "f67c611c-adf7-4ad6-b5ab-27cc5fe79c34" | | }, | | { | | "workflow_name": "test-create_vm-6mk5u42i4dqa", | | "created_at": "2015-02-16 13:01:37", | | "updated_at": "2015-02-16 13:02:01", | | "state": "SUCCESS", | | "input": { | | "image": "31d8eeaf-686e-4e95-bb27-765014b9f20b", | | "name": "mistral-test", | | "flavor": 2 | | }, | | "output": { | | "vm_id": "853d9117-d4e1-4454-a066-ec3dd5863193" | | }, | | "id": "2cc27206-ee42-44ca-bf30-1907f90709e4" | | } | | ], | | "description": "No description given", | | "output_key": "executions" | | } | | ]
Using Ceilometer Alarm with Mistral workflow in Heat.
In this case stack creates with Mistral workflow, which allows to create nova server, and Ceilometer alarm, which send signal to execute workflow. After stack creation alarm get state 'alarm' and sends signal to workflow resource. It executed and creates nova server.
Create Heat template (template.yaml) which uses Mistral workflow and Ceilometer alarm resources
heat_template_version: 2013-05-23 resources: workflow: type: OS::Mistral::Workflow properties: type: direct tasks: - name: alarm action: std.echo output='alarm!' publish: state: 'alarm!' alarm: type: OS::Ceilometer::Alarm properties: meter_name: instance statistic: count period: 60 evaluation_periods: 1 threshold: 100 alarm_actions: - {get_attr: [workflow, alarm_url] } comparison_operator: lt
Create Heat stack using template template.yaml
heat stack-create test -f heat-templates/mistral-and-ceilometer.yaml
id | stack_name | stack_status | creation_time |
---|---|---|---|
7f59798f-212a-4dd3-b3c8-a85a23cb3101 | test | CREATE_IN_PROGRESS | 2015-02-17T07:23:42Z |
mistral workflow-list
Name | Tags | Input | Created at | Updated at |
---|---|---|---|---|
std.create_instance | <none> | name, image_id, flavor_id... | 2015-02-05 14:35:25 | None |
std.delete_instance | <none> | instance_id | 2015-02-05 14:35:25 | None |
test-workflow-7y5jqbwjksy2 | <none> | None | 2015-02-17 07:23:42 | None |
ceilometer alarm-list
Alarm ID | Name | State | Enabled | Continuous | Alarm condition | Time constraints |
---|---|---|---|---|---|---|
14016498-00c1-4e12-8076-1c4f14f02a67 | test-alarm-v7we7aapuvsn | insufficient data | True | True | instance < 100.0 during 1 x 60s | None |
Wait until Ceilometer alarm get state 'alarm'
ceilometer alarm-list
Alarm ID | Name | State | Enabled | Continuous | Alarm condition | Time constraints |
---|---|---|---|---|---|---|
14016498-00c1-4e12-8076-1c4f14f02a67 | test-alarm-v7we7aapuvsn | alarm | True | True | instance < 100.0 during 1 x 60s | None |
mistral execution-list
ID | Workflow | State | Created at | Updated at |
---|---|---|---|---|
85cff77d-3da5-423b-a4ca-fb8be4a9ce2f | test-workflow-7y5jqbwjksy2 | SUCCESS | 2015-02-17 07:31:35 | 2015-02-17 07:31:35 |
Check execution output (it must equals 'alarm!')
mistral execution-get-output 85cff77d-3da5-423b-a4ca-fb8be4a9ce2f ... "state": "alarm!", "alarm": { "state": "alarm!" }, ...
Testing autoscaling using Mistral resources.
This case shows how to use mistral resources for autoscale testing. In this stack workflows are used to get ip of the server and to load/release cpu and triggers allow to execute these workflows (every 10 minutes by default).
Create template heat_autoscaling_nova.yaml with Mistral resources, Ceilometer alarms and Heat autoscaling group
heat_template_version: 2014-10-16 parameters: InstanceType: type: string default: m1.heat ImageId: type: string default: cirros-0.3.2-x86_64-uec User: type: string default: cirros Password: type: string default: 'cubswin:)' Pattern_release: type: string default: "0,20,40 * * * *" description: Time to execute workflow wf_release_cpu Pattern_load: type: string default: "10,30,50 * * * *" description: Time to execute workflow wf_load_cpu resources: my_asg: type: OS::Heat::AutoScalingGroup properties: resource: type: server_with_ip.yaml properties: image: { get_param: ImageId } flavor: { get_param: InstanceType } security_group: {get_resource: security_group} metadata: {"metering.stack": {get_param: "OS::stack_id"}} min_size: 1 max_size: 2 scale_up_policy: type: OS::Heat::ScalingPolicy properties: adjustment_type: change_in_capacity auto_scaling_group_id: {get_resource: my_asg} cooldown: 60 scaling_adjustment: 1 scale_down_policy: type: OS::Heat::ScalingPolicy properties: adjustment_type: change_in_capacity auto_scaling_group_id: {get_resource: my_asg} cooldown: 60 scaling_adjustment: '-1' cpu_alarm_high: type: OS::Ceilometer::Alarm properties: description: Scale-up if the average CPU > 50% for 1 minute meter_name: cpu_util statistic: avg period: 60 evaluation_periods: 1 threshold: 50 alarm_actions: - {get_attr: [scale_up_policy, alarm_url]} matching_metadata: {'metadata.user_metadata.stack': {get_param: "OS::stack_id"}} comparison_operator: gt cpu_alarm_low: type: OS::Ceilometer::Alarm properties: description: Scale-down if the average CPU < 15% for 1 minutes meter_name: cpu_util statistic: avg period: 60 evaluation_periods: 1 threshold: 15 alarm_actions: - {get_attr: [scale_down_policy, alarm_url]} matching_metadata: {'metadata.user_metadata.stack': {get_param: "OS::stack_id"}} comparison_operator: lt security_group: type: AWS::EC2::SecurityGroup properties: GroupDescription: 'Enable SSH access' SecurityGroupIngress: - IpProtocol: 'tcp' FromPort: '22' ToPort : '22' CidrIp : '0.0.0.0/0' wf_load_cpu: type: OS::Mistral::Workflow properties: type: direct tasks: - name: get_output action: heat.stacks_get stack_id=<% $.stack_id %> publish: vm_ip: <% $.get_output._info.outputs[0].output_value %> on_success: - run_ssh - name: run_ssh action: std.ssh cmd='cat /dev/urandom | gzip -9 > /dev/null &' host=<% $.vm_ip %> username=<% $.user %> password=<% $.password %> input: {'user': {get_param: User}, 'password': {get_param: Password}, 'stack_id': {get_param: "OS::stack_id"}} wf_release_cpu: type: OS::Mistral::Workflow properties: type: direct tasks: - name: get_output action: heat.stacks_get stack_id=<% $.stack_id %> publish: vm_ip: <% $.get_output._info.outputs[0].output_value %> on_success: - run_ssh - name: run_ssh action: std.ssh cmd="kill -9 $(ps aux | grep 'cat /dev/urandom' | awk '{print $1}')" host=<% $.vm_ip %> username=<% $.user %> password=<% $.password %> input: {'user': {get_param: User}, 'password': {get_param: Password}, 'stack_id': {get_param: "OS::stack_id"}} trigger_load_cpu: type: OS::Mistral::CronTrigger properties: pattern: {get_param: Pattern_load} workflow: {get_attr: [wf_load_cpu, data]} trigger_release_cpu: type: OS::Mistral::CronTrigger properties: pattern: {get_param: Pattern_release} workflow: {get_attr: [wf_release_cpu, data]} outputs: ip: value: {'Fn::Select': ['0', {get_attr: [my_asg, outputs_list, ip]}]}
Create template server_with_ip.yaml for nested stack
heat_template_version: 2013-05-23 parameters: image: type: string flavor: type: string security_group: type: string metadata: type: json resources: server: type: OS::Nova::Server properties: flavor: {get_param: flavor} image: {get_param: image} metadata: {get_param: metadata} security_groups: - get_param: security_group floating_ip: type: OS::Nova::FloatingIP floating_ip_association: type: OS::Nova::FloatingIPAssociation properties: floating_ip: {get_resource: floating_ip} server_id: {get_resource: server} outputs: ip: value: {get_attr: [floating_ip, ip]} server_id: value: {get_resource: server}
Create stack
heat stack-create test-asg -f heat_autoscaling_nova.yaml
Check that resources were created
heat stack-list
id | stack_name | stack_status | creation_time |
---|---|---|---|
8e1b54a1-eefe-43e1-a316-7397e904e328 | test-asg | CREATE_COMPLETE | 2015-02-10T15:45:29Z |
nova list
ID | Name | Status | Task State | Power State | Networks |
---|---|---|---|---|---|
b2e9edcd-da08-4e02-92b4-79c6f1c87203 | te-fpjq-mgcxiz3lglm4-jza3vpraqlrs-server-y7jdd3voh4no | ACTIVE | - | Running | private=10.0.0.2, 172.24.4.1 |
ceilometer alarm-list
Alarm ID | Name | State | Enabled | Continuous | Alarm condition | Time constraints |
---|---|---|---|---|---|---|
2f338088-d74c-41b6-baf1-185ad3fbe2cc | test-asg-cpu_alarm_high-rh5l5jerjhs6 | ok | True | True | cpu_util > 50.0 during 1 x 60s | None |
5053d1c6-66f0-4a4a-a52a-24d3e8881c4d | test-asg-cpu_alarm_low-n6rvsykaaiba | ok | True | True | cpu_util < 15.0 during 1 x 60s | None |
mistral workflow-list
Name | Tags | Input | Created at | Updated at |
---|---|---|---|---|
std.create_instance | <none> | name, image_id, flavor_id... | 2015-02-05 14:35:25 | None |
std.delete_instance | <none> | instance_id | 2015-02-05 14:35:25 | None |
test-asg.wf_load_cpu.load_vm | <none> | vm_ip, user, password | 2015-02-10 15:45:53 | None |
test-asg.wf_release_cpu.release_vm | <none> | vm_ip, user, password | 2015-02-10 15:45:51 | None |
mistral cron-trigger-list
Name | Pattern | Workflow | Next execution time | Created at | Updated at |
---|---|---|---|---|---|
test-asg-trigger_load_cpu-isepguoldk6y | 10,30,50 * * * * | test-asg.wf_load_cpu.load_vm | 2015-02-10 10:50:00 | 2015-02-10 15:45:59 | None |
test-asg-trigger_release_cpu-nvcj3ycphg4g | 0,20,40 * * * * | test-asg.wf_release_cpu.release_vm | 2015-02-10 11:00:00 | 2015-02-10 15:45:56 | None |
Wait for 10:50 (next execution time of trigger_load_cpu) and check again
ceilometer alarm-list
Alarm ID | Name | State | Enabled | Continuous | Alarm condition | Time constraints |
---|---|---|---|---|---|---|
2f338088-d74c-41b6-baf1-185ad3fbe2cc | test-asg-cpu_alarm_high-rh5l5jerjhs6 | alarm | True | True | cpu_util > 50.0 during 1 x 60s | None |
5053d1c6-66f0-4a4a-a52a-24d3e8881c4d | test-asg-cpu_alarm_low-n6rvsykaaiba | ok | True | True | cpu_util < 15.0 during 1 x 60s | None |
nova list
ID | Name | Status | Task State | Power State | Networks |
---|---|---|---|---|---|
b2e9edcd-da08-4e02-92b4-79c6f1c87203 | te-fpjq-mgcxiz3lglm4-jza3vpraqlrs-server-y7jdd3voh4no | ACTIVE | - | Running | private=10.0.0.2, 172.24.4.1 |
8ffbd4ac-435a-4d9d-80cc-23940302fadd | te-fpjq-oj6r53u24m4g-kdiexra2fs5b-server-mbhtpfvi3nys | ACTIVE | - | Running | private=10.0.0.3, 172.24.4.2 |
Wait for 11:00 (next execution time of trigger_release_cpu)
ceilometer alarm-list
Alarm ID | Name | State | Enabled | Continuous | Alarm condition | Time constraints |
---|---|---|---|---|---|---|
2f338088-d74c-41b6-baf1-185ad3fbe2cc | test-asg-cpu_alarm_high-rh5l5jerjhs6 | ok | True | True | cpu_util > 50.0 during 1 x 60s | None |
5053d1c6-66f0-4a4a-a52a-24d3e8881c4d | test-asg-cpu_alarm_low-n6rvsykaaiba | alarm | True | True | cpu_util < 15.0 during 1 x 60s | None |
nova list
ID | Name | Status | Task State | Power State | Networks |
---|---|---|---|---|---|
8ffbd4ac-435a-4d9d-80cc-23940302fadd | te-fpjq-oj6r53u24m4g-kdiexra2fs5b-server-mbhtpfvi3nys | ACTIVE | - | Running | private=10.0.0.3, 172.24.4.2 |
Heat templates using Mistral resources examples
Mistral Workflow resource using property name
This template create stack with Workflow resource named stack_name-workflow-test_workflow.
heat_template_version: 2013-05-23 resources: workflow: type: OS::Mistral::Workflow properties: type: direct name: test_workflow description: Just testing workflow resource. input: phrase: Hello! output: out: <% $.word %> tasks: - name: hello action: std.echo output=<% $.phrase %> publish: word: <% $.hello %> outputs: exec: value: { get_attr: [workflow, executions] }
Two Mistral Workflows with referencing by intrinsic function get_resource
This template create stack with two Workflow resources, one of them references to another by intrinsic function get_resource.
heat_template_version: 2013-05-23 resources: wf1: type: OS::Mistral::Workflow properties: type: direct tasks: - name: hello! action: std.noop wf2: type: OS::Mistral::Workflow properties: type: direct tasks: - name: call workflow: { get_resource: wf1 } outputs: name: value: {get_attr: [wf2, data]}
Reverse-type Mistral Workflow
This template shows how to use reverse-type Workflows. If you want to execute this Workflow, you need to provide param task_name in resourse signal data, i.e.:
heat resource_signal test_stack create_vm -D '{"params": {"task_name": "create_vm"}}'
Template:
heat_template_version: 2013-05-23 parameters: image_id: type: string flavor: type: string default: 2 resources: create_vm: type: OS::Mistral::Workflow properties: type: reverse input: vm_name: test image_id: { get_param: image_id } flavor_id: { get_param: flavor } output: result: <% $.vm_id %> tasks: - name: create_vm action: nova.servers_create name=<% $.vm_name %> image=<% $.image_id %> flavor=<% $.flavor_id %> publish: vm_id: <% $.create_vm.id %> - name: search_for_ip action: nova.floating_ips_findall instance_id=null publish: vm_ip: <% $.search_for_ip[0].ip %> - name: associate_ip action: nova.servers_add_floating_ip server=<% $.vm_id %> address=<% $.vm_ip %> requires: - search_for_ip - name: send_email action: std.noop publish: vm_id: <% $.vm_id %> vm_ip: <% $.vm_ip %> requires: [create_vm, associate_ip]