昨今、クラウド基盤でのオートメーション化に注目が集まっている気がします。
いまいち、「Heatで何ができるのか?」理解が難しい側面があると思います。
そこで、実際に、Heatを動作させて理解を深めたいと思います。
◼︎ Heatとは
Heatとは、OpenStack Orchestrationを担うプロジェクトだそうです。
テンプレートに実現したい構成要素を定義して、heat-api / engineを介してリソースをデプロイすることができます。
◼︎ Heatを動作させてみる
本来、OpenStack Orchestrationでは自動的に各種リソース構築することを目的にしているため、適切にテンプレートを定義することが肝になるのですが、今回は、Heat動作原理を理解することを目的としているので、テンプレートも極力簡単なものにしました。
##(1) networkリソースを作成する
実用性は、全くありませんが、敢えて、heat clientからnetworkリソースを作成してみます。
neutron clientを使えば、事足りるのですが、、、
なお、heatコマンドを起動する際に、debugオプションを指定すると、heatclient <-> heat-api間でのやり取りが確認できるようになります。
- テンプレートを定義する
heat_template_version: 2013-05-23
description: sample heat for neutron
parameters:
sample_net_name:
type: string
description: Name of Sample network to be created
default: sample_network
resources:
sample_net:
type: OS::Neutron::Net
properties:
name: { get_param: sample_net_name }
outputs:
status:
description: status of sample_net
value: { get_attr: [ sample_net, status ] }
- heat clientから、スタックを作成する
[root@openstack ~(keystone_admin)]# heat --debug stack-create Sample-Net-Stack --template-file sample.yaml --parameters "sample_net_name=Sample"
DEBUG (session) REQ: curl -g -i -X GET http://192.168.195.156:5000/v2.0 -H "Accept: application/json" -H "User-Agent: python-keystoneclient"
INFO (connectionpool) Starting new HTTP connection (1): 192.168.195.156
DEBUG (connectionpool) "GET /v2.0 HTTP/1.1" 200 232
DEBUG (session) RESP: [200] content-length: 232 content-encoding: gzip vary: X-Auth-Token,Accept-Encoding server: Apache/2.4.6 (CentOS) connection: close date: Fri, 01 Apr 2016 21:37:11 GMT content-type: application/json x-openstack-request-id: req-d8d527b0-9203-49a6-8dd0-28267fc04653
RESP BODY: {"version": {"status": "stable", "updated": "2014-04-17T00:00:00Z", "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v2.0+json"}], "id": "v2.0", "links": [{"href": "http://192.168.195.156:5000/v2.0/", "rel": "self"}, {"href": "http://docs.openstack.org/", "type": "text/html", "rel": "describedby"}]}}
DEBUG (v2) Making authentication request to http://192.168.195.156:5000/v2.0/tokens
INFO (connectionpool) Resetting dropped connection: 192.168.195.156
DEBUG (connectionpool) "POST /v2.0/tokens HTTP/1.1" 200 1218
DEBUG (session) REQ: curl -g -i -X POST http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks -H "User-Agent: python-heatclient" -H "Content-Type: application/json" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}2a277e6af39fa24e20659058fda13e9b85af4e09" -d '{"files": {}, "disable_rollback": true, "parameters": {"sample_net_name": "Sample"}, "stack_name": "Sample-Net-Stack", "environment": {}, "template": {"outputs": {"status": {"description": "status of sample_net", "value": {"get_attr": ["sample_net", "status"]}}}, "heat_template_version": "2013-05-23", "description": "sample heat for neutron", "parameters": {"sample_net_name": {"default": "sample_network", "type": "string", "description": "Name of Sample network to be created"}}, "resources": {"sample_net": {"type": "OS::Neutron::Net", "properties": {"name": {"get_param": "sample_net_name"}}}}}}'
INFO (connectionpool) Starting new HTTP connection (1): 192.168.195.156
DEBUG (connectionpool) "POST /v1/342863e5919743709dbfa58c83db9f46/stacks HTTP/1.1" 201 221
DEBUG (session) RESP: [201] content-length: 221 connection: keep-alive location: http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160 date: Fri, 01 Apr 2016 21:37:11 GMT content-type: application/json x-openstack-request-id: req-d5cc38c7-731b-459a-b64e-66d13a64c9f0
RESP BODY: {"stack": {"id": "febaed44-4e04-4c01-bb27-db69f993b160", "links": [{"href": "http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160", "rel": "self"}]}}
DEBUG (session) REQ: curl -g -i -X GET http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks? -H "User-Agent: python-heatclient" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}2a277e6af39fa24e20659058fda13e9b85af4e09"
DEBUG (connectionpool) "GET /v1/342863e5919743709dbfa58c83db9f46/stacks HTTP/1.1" 200 539
DEBUG (session) RESP: [200] date: Fri, 01 Apr 2016 21:37:11 GMT connection: keep-alive content-type: application/json; charset=UTF-8 content-length: 539 x-openstack-request-id: req-7a780bb8-c865-4635-90d3-a7c8c45bb670
RESP BODY: {"stacks": [{"description": "sample heat for neutron", "parent": null, "stack_status_reason": "", "stack_name": "Sample-Net-Stack", "stack_user_project_id": "a25007f332484727bf62b725fdc07a12", "tags": null, "creation_time": "2016-04-01T21:37:11", "links": [{"href": "http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160", "rel": "self"}], "updated_time": null, "stack_owner": null, "stack_status": "CREATE_IN_PROGRESS", "id": "febaed44-4e04-4c01-bb27-db69f993b160"}]}
+--------------------------------------+------------------+--------------------+---------------------+--------------+
| id | stack_name | stack_status | creation_time | updated_time |
+--------------------------------------+------------------+--------------------+---------------------+--------------+
| febaed44-4e04-4c01-bb27-db69f993b160 | Sample-Net-Stack | CREATE_IN_PROGRESS | 2016-04-01T21:37:11 | None |
+--------------------------------------+------------------+--------------------+---------------------+--------------+
- heat-engineでのスタック作成に関わる動作をログ確認しておく
2016-04-02 06:37:11.435 4328 INFO heat.engine.service [req-d5cc38c7-731b-459a-b64e-66d13a64c9f0 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Creating stack Sample-Net-Stack
2016-04-02 06:37:11.450 4328 INFO heat.engine.resource [req-d5cc38c7-731b-459a-b64e-66d13a64c9f0 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Validating Net "sample_net"
2016-04-02 06:37:11.455 4328 WARNING heat.common.context [req-d5cc38c7-731b-459a-b64e-66d13a64c9f0 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Using the keystone_authtoken user as the heat trustee user directly is deprecated. Please add the trustee credentials you need to the trustee section of your heat.conf file.
2016-04-02 06:37:11.652 4328 INFO heat.engine.stack [-] Stack CREATE IN_PROGRESS (Sample-Net-Stack): Stack CREATE started
2016-04-02 06:37:11.678 4328 INFO heat.engine.resource [-] creating Net "sample_net" Stack "Sample-Net-Stack" [febaed44-4e04-4c01-bb27-db69f993b160]
2016-04-02 06:37:12.035 4328 INFO heat.engine.stack [-] Stack CREATE COMPLETE (Sample-Net-Stack): Stack CREATE completed successfully
- スタックが作成されたことを確認しておく
[root@openstack ~(keystone_admin)]# heat stack-list
+--------------------------------------+------------------+-----------------+---------------------+--------------+
| id | stack_name | stack_status | creation_time | updated_time |
+--------------------------------------+------------------+-----------------+---------------------+--------------+
| febaed44-4e04-4c01-bb27-db69f993b160 | Sample-Net-Stack | CREATE_COMPLETE | 2016-04-01T21:37:11 | None |
+--------------------------------------+------------------+-----------------+---------------------+--------------+
- スタックの詳細を確認しておく
[root@openstack ~(keystone_admin)]# heat stack-show Sample-Net-Stack
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
| Property | Value |
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
| capabilities | [] |
| creation_time | 2016-04-01T21:37:11 |
| description | sample heat for neutron |
| disable_rollback | True |
| id | febaed44-4e04-4c01-bb27-db69f993b160 |
| links | http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160 (self) |
| notification_topics | [] |
| outputs | [ |
| | { |
| | "output_value": "ACTIVE", |
| | "description": "status of sample_net", |
| | "output_key": "status" |
| | } |
| | ] |
| parameters | { |
| | "OS::project_id": "342863e5919743709dbfa58c83db9f46", |
| | "sample_net_name": "Sample", |
| | "OS::stack_id": "febaed44-4e04-4c01-bb27-db69f993b160", |
| | "OS::stack_name": "Sample-Net-Stack" |
| | } |
| parent | None |
| stack_name | Sample-Net-Stack |
| stack_owner | None |
| stack_status | CREATE_COMPLETE |
| stack_status_reason | Stack CREATE completed successfully |
| stack_user_project_id | a25007f332484727bf62b725fdc07a12 |
| tags | None |
| template_description | sample heat for neutron |
| timeout_mins | None |
| updated_time | None |
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
- networkリソースが想定どおり作成できたことも確認しておく
[root@openstack ~(keystone_admin)]# neutron net-list
+--------------------------------------+---------+-----------------------------------------------------+
| id | name | subnets |
+--------------------------------------+---------+-----------------------------------------------------+
| 71d8b3d8-8c3e-4645-9bde-f138c4bf5007 | Sample | |
| ca95cfe6-aeff-45a0-9fea-6d26c6740eae | private | 0d9a5b56-a873-4695-be6e-3fa52d8735fb 10.0.0.0/24 |
| b3ca79cd-aa72-46d5-97bd-29722222c161 | public | 86562c5f-1f24-4032-a247-5b16b456789d 192.168.0.0/24 |
+--------------------------------------+---------+-----------------------------------------------------+
[root@openstack ~(keystone_admin)]# neutron net-show 71d8b3d8-8c3e-4645-9bde-f138c4bf5007
+---------------------------+--------------------------------------+
| Field | Value |
+---------------------------+--------------------------------------+
| admin_state_up | True |
| id | 71d8b3d8-8c3e-4645-9bde-f138c4bf5007 |
| mtu | 0 |
| name | Sample |
| provider:network_type | vxlan |
| provider:physical_network | |
| provider:segmentation_id | 62 |
| router:external | False |
| shared | False |
| status | ACTIVE |
| subnets | |
| tenant_id | 342863e5919743709dbfa58c83db9f46 |
+---------------------------+--------------------------------------+
- なお、必要に応じて、スタック作成で使用したテンプレートを確認できる
[root@openstack ~(keystone_admin)]# heat template-show Sample-Net-Stack
description: sample heat for neutron
heat_template_version: '2013-05-23'
outputs:
status:
description: status of sample_net
value:
get_attr: [sample_net, status]
parameters:
sample_net_name: {default: sample_network, description: Name of Sample network to
be created, type: string}
resources:
sample_net:
properties:
name: {get_param: sample_net_name}
type: OS::Neutron::Net
- さらに、スタックが、どのようなリソースで構成されているかも確認できる
[root@openstack ~(keystone_admin)]# heat resource-list Sample-Net-Stack
+---------------+--------------------------------------+------------------+-----------------+---------------------+
| resource_name | physical_resource_id | resource_type | resource_status | updated_time |
+---------------+--------------------------------------+------------------+-----------------+---------------------+
| sample_net | 71d8b3d8-8c3e-4645-9bde-f138c4bf5007 | OS::Neutron::Net | CREATE_COMPLETE | 2016-04-01T21:37:11 |
+---------------+--------------------------------------+------------------+-----------------+---------------------+
##(2) networkリソースを更新する
ここでは、リソース名を変更("Sample" -> "rename_of_Sample")してみます。
- heat clientから、スタックを更新する
[root@openstack ~(keystone_admin)]# heat --debug stack-update Sample-Net-Stack --template-file sample.yaml --parameters "sample_net_name=rename_of_Sample"
DEBUG (session) REQ: curl -g -i -X GET http://192.168.195.156:5000/v2.0 -H "Accept: application/json" -H "User-Agent: python-keystoneclient"
INFO (connectionpool) Starting new HTTP connection (1): 192.168.195.156
DEBUG (connectionpool) "GET /v2.0 HTTP/1.1" 200 232
DEBUG (session) RESP: [200] content-length: 232 content-encoding: gzip vary: X-Auth-Token,Accept-Encoding server: Apache/2.4.6 (CentOS) connection: close date: Fri, 01 Apr 2016 21:51:06 GMT content-type: application/json x-openstack-request-id: req-0c6f115f-b48c-4a21-9991-328efdb9f281
RESP BODY: {"version": {"status": "stable", "updated": "2014-04-17T00:00:00Z", "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v2.0+json"}], "id": "v2.0", "links": [{"href": "http://192.168.195.156:5000/v2.0/", "rel": "self"}, {"href": "http://docs.openstack.org/", "type": "text/html", "rel": "describedby"}]}}
DEBUG (v2) Making authentication request to http://192.168.195.156:5000/v2.0/tokens
INFO (connectionpool) Resetting dropped connection: 192.168.195.156
DEBUG (connectionpool) "POST /v2.0/tokens HTTP/1.1" 200 1216
DEBUG (session) REQ: curl -g -i -X PUT http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack -H "User-Agent: python-heatclient" -H "Content-Type: application/json" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}ab97d8e2a14a61aa14f81a8501240b7fe2f73153" -d '{"files": {}, "environment": {}, "template": {"outputs": {"status": {"description": "status of sample_net", "value": {"get_attr": ["sample_net", "status"]}}}, "heat_template_version": "2013-05-23", "description": "sample heat for neutron", "parameters": {"sample_net_name": {"default": "sample_network", "type": "string", "description": "Name of Sample network to be created"}}, "resources": {"sample_net": {"type": "OS::Neutron::Net", "properties": {"name": {"get_param": "sample_net_name"}}}}}, "parameters": {"sample_net_name": "rename_of_Sample"}}'
INFO (connectionpool) Starting new HTTP connection (1): 192.168.195.156
DEBUG (connectionpool) "PUT /v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack HTTP/1.1" 302 204
DEBUG (session) RESP: [302] content-length: 204 connection: keep-alive location: http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160 date: Fri, 01 Apr 2016 21:51:06 GMT content-type: text/plain; charset=UTF-8 x-openstack-request-id: req-c25c2545-5aed-45cb-a2d1-0e8bca885760
RESP BODY: 302 Found
The resource was found at http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160; you should be redirected automatically.
DEBUG (connectionpool) "PUT /v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160 HTTP/1.1" 202 58
DEBUG (session) RESP: [202] date: Fri, 01 Apr 2016 21:51:06 GMT connection: keep-alive content-type: text/plain; charset=UTF-8 content-length: 58 x-openstack-request-id: req-2451d5df-2812-4245-bc91-f73384677318
RESP BODY: 202 Accepted
The request is accepted for processing.
DEBUG (session) REQ: curl -g -i -X GET http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks? -H "User-Agent: python-heatclient" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}ab97d8e2a14a61aa14f81a8501240b7fe2f73153"
DEBUG (connectionpool) "GET /v1/342863e5919743709dbfa58c83db9f46/stacks HTTP/1.1" 200 576
DEBUG (session) RESP: [200] date: Fri, 01 Apr 2016 21:51:06 GMT connection: keep-alive content-type: application/json; charset=UTF-8 content-length: 576 x-openstack-request-id: req-56c31baf-cb50-4eca-9f97-5ff1574e48c4
RESP BODY: {"stacks": [{"description": "sample heat for neutron", "parent": null, "stack_status_reason": "Stack UPDATE started", "stack_name": "Sample-Net-Stack", "stack_user_project_id": "a25007f332484727bf62b725fdc07a12", "tags": null, "creation_time": "2016-04-01T21:37:11", "links": [{"href": "http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160", "rel": "self"}], "updated_time": "2016-04-01T21:51:06", "stack_owner": null, "stack_status": "UPDATE_IN_PROGRESS", "id": "febaed44-4e04-4c01-bb27-db69f993b160"}]}
+--------------------------------------+------------------+--------------------+---------------------+---------------------+
| id | stack_name | stack_status | creation_time | updated_time |
+--------------------------------------+------------------+--------------------+---------------------+---------------------+
| febaed44-4e04-4c01-bb27-db69f993b160 | Sample-Net-Stack | UPDATE_IN_PROGRESS | 2016-04-01T21:37:11 | 2016-04-01T21:51:06 |
+--------------------------------------+------------------+--------------------+---------------------+---------------------+
- heat-engineでのスタック更新に関わる動作をログ確認しておく
2016-04-02 06:51:06.239 4328 INFO heat.engine.service [req-2451d5df-2812-4245-bc91-f73384677318 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Updating stack Sample-Net-Stack
2016-04-02 06:51:06.252 4328 INFO heat.engine.resource [req-2451d5df-2812-4245-bc91-f73384677318 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Validating Net "sample_net"
2016-04-02 06:51:06.331 4328 INFO heat.engine.resource [-] updating Net "sample_net" [71d8b3d8-8c3e-4645-9bde-f138c4bf5007] Stack "Sample-Net-Stack" [febaed44-4e04-4c01-bb27-db69f993b160]
2016-04-02 06:51:07.603 4328 INFO heat.engine.update [-] Resource sample_net for stack Sample-Net-Stack updated
2016-04-02 06:51:08.619 4328 INFO heat.engine.stack [-] Stack DELETE IN_PROGRESS (Sample-Net-Stack): Stack DELETE started
2016-04-02 06:51:08.652 4328 INFO heat.engine.stack [-] Stack DELETE COMPLETE (Sample-Net-Stack): Stack DELETE completed successfully
2016-04-02 06:51:08.714 4328 INFO heat.engine.stack [-] Stack UPDATE COMPLETE (Sample-Net-Stack): Stack UPDATE completed successfully
- スタックが更新されたことを確認しておく
[root@openstack ~(keystone_admin)]# heat stack-show Sample-Net-Stack
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
| Property | Value |
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
| capabilities | [] |
| creation_time | 2016-04-01T21:37:11 |
| description | sample heat for neutron |
| disable_rollback | True |
| id | febaed44-4e04-4c01-bb27-db69f993b160 |
| links | http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160 (self) |
| notification_topics | [] |
| outputs | [ |
| | { |
| | "output_value": "ACTIVE", |
| | "description": "status of sample_net", |
| | "output_key": "status" |
| | } |
| | ] |
| parameters | { |
| | "OS::project_id": "342863e5919743709dbfa58c83db9f46", |
| | "sample_net_name": "rename_of_Sample", |
| | "OS::stack_id": "febaed44-4e04-4c01-bb27-db69f993b160", |
| | "OS::stack_name": "Sample-Net-Stack" |
| | } |
| parent | None |
| stack_name | Sample-Net-Stack |
| stack_owner | None |
| stack_status | UPDATE_COMPLETE |
| stack_status_reason | Stack UPDATE completed successfully |
| stack_user_project_id | a25007f332484727bf62b725fdc07a12 |
| tags | None |
| template_description | sample heat for neutron |
| timeout_mins | None |
| updated_time | 2016-04-01T21:51:06 |
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
- networkリソースが想定どおり更新されたかを確認しておく
[root@openstack ~(keystone_admin)]# neutron net-show 71d8b3d8-8c3e-4645-9bde-f138c4bf5007
+---------------------------+--------------------------------------+
| Field | Value |
+---------------------------+--------------------------------------+
| admin_state_up | True |
| id | 71d8b3d8-8c3e-4645-9bde-f138c4bf5007 |
| mtu | 0 |
| name | rename_of_Sample |
| provider:network_type | vxlan |
| provider:physical_network | |
| provider:segmentation_id | 62 |
| router:external | False |
| shared | False |
| status | ACTIVE |
| subnets | |
| tenant_id | 342863e5919743709dbfa58c83db9f46 |
+---------------------------+--------------------------------------+
##(3) networkリソースを削除する
ここでは、スタック"Sample-Net-Stack"を削除してみます。
- heat clientから、スタックを削除する
[root@openstack ~(keystone_admin)]# heat --debug stack-delete Sample-Net-Stack
DEBUG (session) REQ: curl -g -i -X GET http://192.168.195.156:5000/v2.0 -H "Accept: application/json" -H "User-Agent: python-keystoneclient"
INFO (connectionpool) Starting new HTTP connection (1): 192.168.195.156
DEBUG (connectionpool) "GET /v2.0 HTTP/1.1" 200 232
DEBUG (session) RESP: [200] content-length: 232 content-encoding: gzip vary: X-Auth-Token,Accept-Encoding server: Apache/2.4.6 (CentOS) connection: close date: Fri, 01 Apr 2016 21:57:38 GMT content-type: application/json x-openstack-request-id: req-33db888b-d2bd-43a9-ae64-a9b8c905057e
RESP BODY: {"version": {"status": "stable", "updated": "2014-04-17T00:00:00Z", "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v2.0+json"}], "id": "v2.0", "links": [{"href": "http://192.168.195.156:5000/v2.0/", "rel": "self"}, {"href": "http://docs.openstack.org/", "type": "text/html", "rel": "describedby"}]}}
DEBUG (v2) Making authentication request to http://192.168.195.156:5000/v2.0/tokens
INFO (connectionpool) Resetting dropped connection: 192.168.195.156
DEBUG (connectionpool) "POST /v2.0/tokens HTTP/1.1" 200 1220
DEBUG (session) REQ: curl -g -i -X DELETE http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack -H "User-Agent: python-heatclient" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}c991f40a0dff946bac929cd3229b18e77ee5d020"
INFO (connectionpool) Starting new HTTP connection (1): 192.168.195.156
DEBUG (connectionpool) "DELETE /v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack HTTP/1.1" 302 204
DEBUG (session) RESP: [302] content-length: 204 connection: keep-alive location: http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160 date: Fri, 01 Apr 2016 21:57:38 GMT content-type: text/plain; charset=UTF-8 x-openstack-request-id: req-4fa73b20-8a06-4987-90c1-59f6417346c2
RESP BODY: 302 Found
The resource was found at http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160; you should be redirected automatically.
DEBUG (connectionpool) "DELETE /v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160 HTTP/1.1" 204 0
DEBUG (session) RESP: [204] date: Fri, 01 Apr 2016 21:57:38 GMT connection: keep-alive content-type: text/html; charset=UTF-8 content-length: 0 x-openstack-request-id: req-be5a73cc-0bb9-4d54-ab3e-ae764c98e7fc
DEBUG (session) REQ: curl -g -i -X GET http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks? -H "User-Agent: python-heatclient" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}c991f40a0dff946bac929cd3229b18e77ee5d020"
DEBUG (connectionpool) "GET /v1/342863e5919743709dbfa58c83db9f46/stacks HTTP/1.1" 200 576
DEBUG (session) RESP: [200] date: Fri, 01 Apr 2016 21:57:38 GMT connection: keep-alive content-type: application/json; charset=UTF-8 content-length: 576 x-openstack-request-id: req-d0adc96f-b87d-421e-a68d-914e9dca989b
RESP BODY: {"stacks": [{"description": "sample heat for neutron", "parent": null, "stack_status_reason": "Stack DELETE started", "stack_name": "Sample-Net-Stack", "stack_user_project_id": "a25007f332484727bf62b725fdc07a12", "tags": null, "creation_time": "2016-04-01T21:37:11", "links": [{"href": "http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/febaed44-4e04-4c01-bb27-db69f993b160", "rel": "self"}], "updated_time": "2016-04-01T21:51:06", "stack_owner": null, "stack_status": "DELETE_IN_PROGRESS", "id": "febaed44-4e04-4c01-bb27-db69f993b160"}]}
+--------------------------------------+------------------+--------------------+---------------------+---------------------+
| id | stack_name | stack_status | creation_time | updated_time |
+--------------------------------------+------------------+--------------------+---------------------+---------------------+
| febaed44-4e04-4c01-bb27-db69f993b160 | Sample-Net-Stack | DELETE_IN_PROGRESS | 2016-04-01T21:37:11 | 2016-04-01T21:51:06 |
+--------------------------------------+------------------+--------------------+---------------------+---------------------+
- heat-engineでのスタック削除に関わる動作をログ確認しておく
2016-04-02 06:57:38.414 4327 INFO heat.engine.service [req-be5a73cc-0bb9-4d54-ab3e-ae764c98e7fc fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Deleting stack Sample-Net-Stack
2016-04-02 06:57:38.464 4327 INFO heat.engine.stack [-] Stack DELETE IN_PROGRESS (Sample-Net-Stack): Stack DELETE started
2016-04-02 06:57:38.500 4327 INFO heat.engine.resource [-] deleting Net "sample_net" [71d8b3d8-8c3e-4645-9bde-f138c4bf5007] Stack "Sample-Net-Stack" [febaed44-4e04-4c01-bb27-db69f993b160]
2016-04-02 06:57:38.932 4327 INFO heat.engine.stack [-] Stack DELETE COMPLETE (Sample-Net-Stack): Stack DELETE completed successfully
- networkリソースが削除されたことを確認しておく
[root@openstack ~(keystone_admin)]# neutron net-show 71d8b3d8-8c3e-4645-9bde-f138c4bf5007
Unable to find network with name '71d8b3d8-8c3e-4645-9bde-f138c4bf5007'
◼︎ "heat-engine"の基本動作を探ってみる
heat-engineの基本動作を理解するには、Heat Resource Plug-in Development Guideが、とても役立ちます。
(1) neutronリソースのタイプを確認する。
テンプレートを作成した際に、スタックのタイプも併せて定義しました。(再掲)
heat_template_version: 2013-05-23
description: sample heat for neutron
parameters:
sample_net_name:
type: string
description: Name of Sample network to be created
default: sample_network
resources:
sample_net:
type: OS::Neutron::Net
properties:
name: { get_param: sample_net_name }
outputs:
status:
description: status of sample_net
value: { get_attr: [ sample_net, status ] }
そして、スタックを作成すると、heat-engine側では、リソースタイプが"OS::Neutron::Net"として保管されているようです。
[root@openstack ~(keystone_admin)]# heat resource-list Sample-Net-Stack
+---------------+--------------------------------------+------------------+-----------------+---------------------+
| resource_name | physical_resource_id | resource_type | resource_status | updated_time |
+---------------+--------------------------------------+------------------+-----------------+---------------------+
| sample_net | 71d8b3d8-8c3e-4645-9bde-f138c4bf5007 | OS::Neutron::Net | CREATE_COMPLETE | 2016-04-01T21:37:11 |
+---------------+--------------------------------------+------------------+-----------------+---------------------+
(2) neutronリソースの動作ロジックを確認してみる。
それでは、networkリソース"OS::Neutron::Net"の中身を深堀してみましょう。
class Net(neutron.NeutronResource):
"""A resource for managing Neutron net.
A network is a virtual isolated layer-2 broadcast domain which is typically
reserved to the tenant who created it, unless the network has been
explicitly configured to be shared.
"""
PROPERTIES = (
NAME, VALUE_SPECS, ADMIN_STATE_UP, TENANT_ID, SHARED,
DHCP_AGENT_IDS, PORT_SECURITY_ENABLED, QOS_POLICY,
) = (
'name', 'value_specs', 'admin_state_up', 'tenant_id', 'shared',
'dhcp_agent_ids', 'port_security_enabled', 'qos_policy',
)
ATTRIBUTES = (
STATUS, NAME_ATTR, SUBNETS, ADMIN_STATE_UP_ATTR, TENANT_ID_ATTR,
PORT_SECURITY_ENABLED_ATTR, MTU_ATTR, QOS_POLICY_ATTR,
) = (
"status", "name", "subnets", "admin_state_up", "tenant_id",
"port_security_enabled", "mtu", 'qos_policy_id',
)
... (snip)
def handle_create(self):
props = self.prepare_properties(
self.properties,
self.physical_resource_name())
dhcp_agent_ids = props.pop(self.DHCP_AGENT_IDS, None)
qos_policy = props.pop(self.QOS_POLICY, None)
if qos_policy:
props['qos_policy_id'] = self.client_plugin().get_qos_policy_id(
qos_policy)
net = self.client().create_network({'network': props})['network']
self.resource_id_set(net['id'])
if dhcp_agent_ids:
self._replace_dhcp_agents(dhcp_agent_ids)
def _show_resource(self):
return self.client().show_network(
self.resource_id)['network']
def check_create_complete(self, *args):
attributes = self._show_resource()
return self.is_built(attributes)
... (snip)
def resource_mapping():
return {
'OS::Neutron::Net': Net,
}
'OS::Neutron::Net'のマッピング情報により、pythonクラス"Net"が選定されて、handle_createメソッドが起動されるようです。同メソッド内では、neutron clientを活用してnetworkリソースを作成します。そして、networkリソース作成結果をneutron clientから受信して、最終的に、リソース作成結果のstatus判定が行われます。実際は、neutron.pyで行われます。
... (snip)
@staticmethod
def is_built(attributes):
status = attributes['status']
if status == 'BUILD':
return False
if status in ('ACTIVE', 'DOWN'):
return True
elif status == 'ERROR':
raise exception.ResourceInError(
resource_status=status)
else:
raise exception.ResourceUnknownStatus(
resource_status=status,
result=_('Resource is not built'))
(3) heat-engine内部を改造する(ダミーneutronクライアント化)
本来、heat-engineでは、networkリソース作成処理は、neutron clientに処理を委ねます。
ここでは、敢えて、neutron client処理をダミー化してみます。
- resource_id: "aaaaaaa-aaaa-aaaaaaaae-aaaaaaaaaaaa"
- status: "ACTIVE"
def handle_create(self):
props = self.prepare_properties(
self.properties,
self.physical_resource_name())
dhcp_agent_ids = props.pop(self.DHCP_AGENT_IDS, None)
# net = self.client().create_network({'network': props})['network']
# self.resource_id_set(net['id'])
self.resource_id_set('aaaaaaaa-aaaa-aaaaaaaae-aaaaaaaaaaaa')
if dhcp_agent_ids:
self._replace_dhcp_agents(dhcp_agent_ids)
def _show_resource(self):
# return self.client().show_network(
# self.resource_id)['network']
result = {"status": "ACTIVE", "name": "Sample", "id": "aaaaaaa-aaaa-aaaaaaaae-aaaaaaaaaaaa"}
return result
def check_create_complete(self, *args):
attributes = self._show_resource()
return self.is_built(attributes)
(4) heat clientから、スタックを作成する
- スタックを作成する
[root@openstack ~(keystone_admin)]# heat stack-create Sample-Net-Stack --template-file sample.yaml --parameters "sample_net_name=Sample"
+--------------------------------------+------------------+--------------------+---------------------+--------------+
| id | stack_name | stack_status | creation_time | updated_time |
+--------------------------------------+------------------+--------------------+---------------------+--------------+
| 81bad99a-f9b3-4aa2-bc1a-3d704fc7e03c | Sample-Net-Stack | CREATE_IN_PROGRESS | 2016-04-02T11:06:52 | None |
+--------------------------------------+------------------+--------------------+---------------------+--------------+
- heat-engineでのスタック作成に関わる動作をログ確認しておく
2016-04-02 20:06:52.674 4391 INFO heat.engine.service [req-0b044edb-b1d9-4f15-ba5d-c1e8172688f9 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Creating stack Sample-Net-Stack
2016-04-02 20:06:52.690 4391 INFO heat.engine.resource [req-0b044edb-b1d9-4f15-ba5d-c1e8172688f9 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Validating Net "sample_net"
2016-04-02 20:06:52.697 4391 WARNING heat.common.context [req-0b044edb-b1d9-4f15-ba5d-c1e8172688f9 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Using the keystone_authtoken user as the heat trustee user directly is deprecated. Please add the trustee credentials you need to the trustee section of your heat.conf file.
2016-04-02 20:06:53.082 4391 INFO heat.engine.stack [-] Stack CREATE IN_PROGRESS (Sample-Net-Stack): Stack CREATE started
2016-04-02 20:06:53.097 4391 INFO heat.engine.resource [-] creating Net "sample_net" Stack "Sample-Net-Stack" [81bad99a-f9b3-4aa2-bc1a-3d704fc7e03c]
2016-04-02 20:06:53.184 4391 INFO heat.engine.stack [-] Stack CREATE COMPLETE (Sample-Net-Stack): Stack CREATE completed successfully
- スタックの詳細を確認しておく
[root@openstack ~(keystone_admin)]# heat stack-show Sample-Net-Stack
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
| Property | Value |
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
| capabilities | [] |
| creation_time | 2016-04-02T11:06:52 |
| description | sample heat for neutron |
| disable_rollback | True |
| id | 81bad99a-f9b3-4aa2-bc1a-3d704fc7e03c |
| links | http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/81bad99a-f9b3-4aa2-bc1a-3d704fc7e03c (self) |
| notification_topics | [] |
| outputs | [ |
| | { |
| | "output_value": "ACTIVE", |
| | "description": "status of sample_net", |
| | "output_key": "status" |
| | } |
| | ] |
| parameters | { |
| | "OS::project_id": "342863e5919743709dbfa58c83db9f46", |
| | "sample_net_name": "Sample", |
| | "OS::stack_id": "81bad99a-f9b3-4aa2-bc1a-3d704fc7e03c", |
| | "OS::stack_name": "Sample-Net-Stack" |
| | } |
| parent | None |
| stack_name | Sample-Net-Stack |
| stack_owner | None |
| stack_status | CREATE_COMPLETE |
| stack_status_reason | Stack CREATE completed successfully |
| stack_user_project_id | cc0e1d6305cc4ce1b633b6047f41be23 |
| tags | None |
| template_description | sample heat for neutron |
| timeout_mins | None |
| updated_time | None |
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
- networkリソースは作成されていないことを確認しておく
[root@openstack ~(keystone_admin)]# neutron net-list
+--------------------------------------+---------+-----------------------------------------------------+
| id | name | subnets |
+--------------------------------------+---------+-----------------------------------------------------+
| ca95cfe6-aeff-45a0-9fea-6d26c6740eae | private | 0d9a5b56-a873-4695-be6e-3fa52d8735fb 10.0.0.0/24 |
| b3ca79cd-aa72-46d5-97bd-29722222c161 | public | 86562c5f-1f24-4032-a247-5b16b456789d 192.168.0.0/24 |
+--------------------------------------+---------+-----------------------------------------------------+
- スタックが、ダミー化されたnetworkリソースで構成されていることを確認する
[root@openstack ~(keystone_admin)]# heat resource-list Sample-Net-Stack
+---------------+--------------------------------------+------------------+-----------------+---------------------+
| resource_name | physical_resource_id | resource_type | resource_status | updated_time |
+---------------+--------------------------------------+------------------+-----------------+---------------------+
| sample_net | aaaaaaaa-aaaa-aaaaaaaae-aaaaaaaaaaaa | OS::Neutron::Net | CREATE_COMPLETE | 2016-04-02T11:06:53 |
+---------------+--------------------------------------+------------------+-----------------+---------------------+
以上より、neutronリソースが実際には存在していないが、heat-engine上では、"ACTIVE"なnetworkリソースとしてスタックにて構成されていることが確認できました。
◼︎ "heat-engine"の異常判定動作を探ってみる
heat-engineでのオーケストレーション処理中に、異常発生した場合のstack処理の扱いを確認しておきます。
(1) heat-engine内部を改造する(stack判定処理の異常終了化)
stack作成後の処理結果判定時には、check_create_completeメソッドが呼ばれます。
この時、処理結果の判定中において、強引に異常終了させてみます。
def handle_create(self):
props = self.prepare_properties(
self.properties,
self.physical_resource_name())
dhcp_agent_ids = props.pop(self.DHCP_AGENT_IDS, None)
# net = self.client().create_network({'network': props})['network']
# self.resource_id_set(net['id'])
self.resource_id_set('aaaaaaaa-aaaa-aaaaaaaae-aaaaaaaaaaaa')
if dhcp_agent_ids:
self._replace_dhcp_agents(dhcp_agent_ids)
def _show_resource(self):
# return self.client().show_network(
# self.resource_id)['network']
result = {"status": "ACTIVE", "name": "Sample", "id": "aaaaaaa-aaaa-aaaaaaaae-aaaaaaaaaaaa"}
# return result
raise
def check_create_complete(self, *args):
attributes = self._show_resource()
return self.is_built(attributes)
(2) heat clientから、スタックを作成する
- スタックを作成する
[root@openstack ~(keystone_admin)]# heat stack-create Sample-Net-Stack --template-file sample.yaml --parameters "sample_net_name=Sample"
+--------------------------------------+------------------+--------------------+---------------------+--------------+
| id | stack_name | stack_status | creation_time | updated_time |
+--------------------------------------+------------------+--------------------+---------------------+--------------+
| da58dc2c-7cc2-4308-90f3-fe29ffcf00c0 | Sample-Net-Stack | CREATE_IN_PROGRESS | 2016-04-16T21:35:20 | None |
+--------------------------------------+------------------+--------------------+---------------------+--------------+
- heat-engineでのスタック作成に関わる動作をログ確認しておく
2016-04-17 06:35:19.928 4307 INFO heat.engine.service [req-53ceef8d-4678-4bfe-8beb-f110f5a7c560 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Creating stack Sample-Net-Stack
2016-04-17 06:35:19.949 4307 INFO heat.engine.resource [req-53ceef8d-4678-4bfe-8beb-f110f5a7c560 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Validating Net "sample_net"
2016-04-17 06:35:19.957 4307 WARNING heat.common.context [req-53ceef8d-4678-4bfe-8beb-f110f5a7c560 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Using the keystone_authtoken user as the heat trustee user directly is deprecated. Please add the trustee credentials you need to the trustee section of your heat.conf file.
2016-04-17 06:35:20.333 4308 INFO oslo.messaging._drivers.impl_rabbit [req-115109c6-edd8-4db2-adb9-7846206ab0e5 fe37fdae0108485fa17b7a81f066510b 342863e5919743709dbfa58c83db9f46] Connecting to AMQP server on localhost:5672
2016-04-17 06:35:20.334 4307 INFO heat.engine.stack [-] Stack CREATE IN_PROGRESS (Sample-Net-Stack): Stack CREATE started
2016-04-17 06:35:20.351 4307 INFO heat.engine.resource [-] creating Net "sample_net" Stack "Sample-Net-Stack" [da58dc2c-7cc2-4308-90f3-fe29ffcf00c0]
2016-04-17 06:35:20.390 4307 INFO heat.engine.resource [-] CREATE: Net "sample_net" [aaaaaaaa-aaaa-aaaaaaaae-aaaaaaaaaaaa] Stack "Sample-Net-Stack" [da58dc2c-7cc2-4308-90f3-fe29ffcf00c0]
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource Traceback (most recent call last):
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource File "/usr/lib/python2.7/site-packages/heat/engine/resource.py", line 612, in _action_recorder
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource yield
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource File "/usr/lib/python2.7/site-packages/heat/engine/resource.py", line 682, in _do_action
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource yield self.action_handler_task(action, args=handler_args)
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource File "/usr/lib/python2.7/site-packages/heat/engine/scheduler.py", line 309, in wrapper
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource step = next(subtask)
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource File "/usr/lib/python2.7/site-packages/heat/engine/resource.py", line 656, in action_handler_task
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource while not check(handler_data):
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource File "/usr/lib/python2.7/site-packages/heat/engine/resources/openstack/neutron/net.py", line 146, in check_create_complete
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource attributes = self._show_resource()
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource File "/usr/lib/python2.7/site-packages/heat/engine/resources/openstack/neutron/net.py", line 143, in _show_resource
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource raise
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource TypeError: exceptions must be old-style classes or derived from BaseException, not NoneType
2016-04-17 06:35:20.390 4307 ERROR heat.engine.resource
2016-04-17 06:35:21.421 4307 INFO heat.engine.service [-] Stack create failed, status FAILED
2016-04-17 06:35:21.437 4307 INFO heat.engine.stack [-] Stack CREATE FAILED (Sample-Net-Stack): Resource CREATE failed: TypeError: resources.sample_net: exceptions must be old-style classes or derived from BaseException, not NoneType
- スタック作成が失敗したことを確認する
[root@openstack ~(keystone_admin)]# heat stack-list
+--------------------------------------+------------------+---------------+---------------------+--------------+
| id | stack_name | stack_status | creation_time | updated_time |
+--------------------------------------+------------------+---------------+---------------------+--------------+
| da58dc2c-7cc2-4308-90f3-fe29ffcf00c0 | Sample-Net-Stack | CREATE_FAILED | 2016-04-16T21:35:20 | None |
+--------------------------------------+------------------+---------------+---------------------+--------------+
- スタックの処理結果の詳細を確認する
[root@openstack ~(keystone_admin)]# heat stack-show Sample-Net-Stack
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
| Property | Value |
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
| capabilities | [] |
| creation_time | 2016-04-16T21:35:20 |
| description | sample heat for neutron |
| disable_rollback | True |
| id | da58dc2c-7cc2-4308-90f3-fe29ffcf00c0 |
| links | http://192.168.195.156:8004/v1/342863e5919743709dbfa58c83db9f46/stacks/Sample-Net-Stack/da58dc2c-7cc2-4308-90f3-fe29ffcf00c0 (self) |
| notification_topics | [] |
| outputs | [ |
| | { |
| | "output_value": null, |
| | "output_error": "exceptions must be old-style classes or derived from BaseException, not NoneType", |
| | "description": "status of sample_net", |
| | "output_key": "status" |
| | } |
| | ] |
| parameters | { |
| | "OS::project_id": "342863e5919743709dbfa58c83db9f46", |
| | "sample_net_name": "Sample", |
| | "OS::stack_id": "da58dc2c-7cc2-4308-90f3-fe29ffcf00c0", |
| | "OS::stack_name": "Sample-Net-Stack" |
| | } |
| parent | None |
| stack_name | Sample-Net-Stack |
| stack_owner | None |
| stack_status | CREATE_FAILED |
| stack_status_reason | Resource CREATE failed: TypeError: |
| | resources.sample_net: exceptions must be old-style |
| | classes or derived from BaseException, not NoneType |
| stack_user_project_id | eeb7b61462f9454a93217735e3150ee0 |
| tags | None |
| template_description | sample heat for neutron |
| timeout_mins | None |
| updated_time | None |
+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------+
- networkリソースも作成が失敗したことを確認しておく
[root@openstack ~(keystone_admin)]# heat resource-list Sample-Net-Stack
+---------------+--------------------------------------+------------------+-----------------+---------------------+
| resource_name | physical_resource_id | resource_type | resource_status | updated_time |
+---------------+--------------------------------------+------------------+-----------------+---------------------+
| sample_net | aaaaaaaa-aaaa-aaaaaaaae-aaaaaaaaaaaa | OS::Neutron::Net | CREATE_FAILED | 2016-04-16T21:35:20 |
+---------------+--------------------------------------+------------------+-----------------+---------------------+
以上より、heat-engineでのオーケストレーション処理中に、異常発生した場合のstack処理の判定結果が期待通り動作している様子を確認することができました。
◼︎ 終わりに...
今後、クラウド基盤では、円滑なるオートメーション化を目的に、様々な技術刷新が図られていくと予想されます。その際には、多種多様なAPIを束ねる役割のOpenStack Heatも、どんどんに重要な位置付けになっていくのでしょうか。
これからのクラウドエンジニアには、クラウド基盤の構築に併せて、自由自在にオートメーション化を実現できるスキル習得が必要になってくると感じております。手始めに、Templateを自由自在に作成できるスキル習得に頑張りたいと思います。