ae367a02e65f9720b4b12ba1387a762a38a026d5
[snaps.git] / snaps / openstack / utils / heat_utils.py
1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 import logging
16
17 import yaml
18 from heatclient.client import Client
19 from heatclient.common.template_format import yaml_loader
20 from oslo_serialization import jsonutils
21
22 from snaps import file_utils
23 from snaps.domain.stack import Stack
24
25 from snaps.openstack.utils import keystone_utils
26
27 __author__ = 'spisarski'
28
29 logger = logging.getLogger('heat_utils')
30
31
32 def heat_client(os_creds):
33     """
34     Retrieves the Heat client
35     :param os_creds: the OpenStack credentials
36     :return: the client
37     """
38     logger.debug('Retrieving Nova Client')
39     return Client(os_creds.heat_api_version,
40                   session=keystone_utils.keystone_session(os_creds),
41                   region_name=os_creds.region_name)
42
43
44 def get_stack_by_name(heat_cli, stack_name):
45     """
46     Returns a domain Stack object
47     :param heat_cli: the OpenStack heat client
48     :param stack_name: the name of the heat stack
49     :return: the Stack domain object else None
50     """
51     stacks = heat_cli.stacks.list(**{'name': stack_name})
52     for stack in stacks:
53         return Stack(name=stack.identifier, stack_id=stack.id)
54
55     return None
56
57
58 def get_stack_by_id(heat_cli, stack_id):
59     """
60     Returns a domain Stack object for a given ID
61     :param heat_cli: the OpenStack heat client
62     :param stack_id: the ID of the heat stack to retrieve
63     :return: the Stack domain object else None
64     """
65     stack = heat_cli.stacks.get(stack_id)
66     return Stack(name=stack.identifier, stack_id=stack.id)
67
68
69 def get_stack_status(heat_cli, stack_id):
70     """
71     Returns the current status of the Heat stack
72     :param heat_cli: the OpenStack heat client
73     :param stack_id: the ID of the heat stack to retrieve
74     :return:
75     """
76     return heat_cli.stacks.get(stack_id).stack_status
77
78
79 def get_stack_outputs(heat_cli, stack_id):
80     """
81     Returns a domain Stack object for a given ID
82     :param heat_cli: the OpenStack heat client
83     :param stack_id: the ID of the heat stack to retrieve
84     :return: the Stack domain object else None
85     """
86     stack = heat_cli.stacks.get(stack_id)
87     return stack.outputs
88
89
90 def create_stack(heat_cli, stack_settings):
91     """
92     Executes an Ansible playbook to the given host
93     :param heat_cli: the OpenStack heat client object
94     :param stack_settings: the stack configuration
95     :return: the Stack domain object
96     """
97     args = dict()
98
99     if stack_settings.template:
100         args['template'] = stack_settings.template
101     else:
102         args['template'] = parse_heat_template_str(
103             file_utils.read_file(stack_settings.template_path))
104     args['stack_name'] = stack_settings.name
105
106     if stack_settings.env_values:
107         args['parameters'] = stack_settings.env_values
108
109     stack = heat_cli.stacks.create(**args)
110
111     return get_stack_by_id(heat_cli, stack_id=stack['stack']['id'])
112
113
114 def delete_stack(heat_cli, stack):
115     """
116     Deletes the Heat stack
117     :param heat_cli: the OpenStack heat client object
118     :param stack: the OpenStack Heat stack object
119     """
120     heat_cli.stacks.delete(stack.id)
121
122
123 def parse_heat_template_str(tmpl_str):
124     """
125     Takes a heat template string, performs some simple validation and returns a
126     dict containing the parsed structure. This function supports both JSON and
127     YAML Heat template formats.
128     """
129     if tmpl_str.startswith('{'):
130         tpl = jsonutils.loads(tmpl_str)
131     else:
132         try:
133             tpl = yaml.load(tmpl_str, Loader=yaml_loader)
134         except yaml.YAMLError as yea:
135             raise ValueError(yea)
136         else:
137             if tpl is None:
138                 tpl = {}
139     # Looking for supported version keys in the loaded template
140     if not ('HeatTemplateFormatVersion' in tpl or
141             'heat_template_version' in tpl or
142             'AWSTemplateFormatVersion' in tpl):
143         raise ValueError("Template format version not found.")
144     return tpl