cefe42260ca7ae343e8f65b1799d60ef12079435
[osm/devops.git] / descriptor-packages / tools / charm-generator / generator / generators / ansible_generator.py
1 # Copyright 2019 Whitestack, LLC
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
13 # under the License.
14 #
15 # For those usages not covered by the Apache License, Version 2.0 please
16 # contact: esousa@whitestack.com or glavado@whitestack.com
17 ##
18
19 import functools
20 import logging
21 import os
22 import sys
23
24 from jinja2 import Environment, PackageLoader
25
26 from generator.generators.actions_generator import ActionsGenerator
27 from generator.generators.metadata_generator import MetadataGenerator
28
29
30 class AnsibleGenerator:
31 LOGGER = logging.getLogger()
32 ENV = Environment(loader=PackageLoader('generator.ansible-charm', 'templates'))
33
34 def __init__(self, metadata, license=None, options=None):
35 """
36 Creates the object to generate the ansible charm from templates.
37
38 Usage should be:
39
40 1) Create the object.
41 2) Run the generate method.
42
43 :param metadata: metadata information about the charm being generated.
44 :param license: information license to included in the charm being generated.
45 :param options: options to override the normal flow.
46 """
47 self.path = os.getcwd()
48 self.metadata = metadata
49 self.license = license
50 self.options = options
51 self.playbooks = AnsibleGenerator._fetch_all_playbooks(self.path)
52
53 playbooks_name = [playbook['file'] for playbook in self.playbooks]
54 AnsibleGenerator.LOGGER.debug('Playbooks found: %s', playbooks_name)
55
56 self.metadata_generator = MetadataGenerator(metadata=self.metadata, license=self.license, options=self.options)
57 self.actions_generator = ActionsGenerator(metadata=self.metadata, actions=self.playbooks, license=self.license,
58 options=self.options)
59
60 def generate(self):
61 """
62 Generates the Ansible Charm using templates.
63 """
64 AnsibleGenerator.LOGGER.info('Generating the Ansible Charm...')
65
66 # Generating metadata.yaml
67 self.metadata_generator.generate()
68 self.metadata = self.metadata_generator.get_metadata()
69
70 # Generating actions
71 self.actions_generator.generate()
72
73 self._generate_ansible_lib()
74 self._generate_layer_yaml_file()
75 self._generate_reactive_file()
76
77 AnsibleGenerator.LOGGER.info('Generated the Ansible Charm.')
78
79 @staticmethod
80 def _fetch_all_playbooks(path):
81 """
82 Walks over the playbooks directory, fetches the playbook's name.
83 It takes the file name and normalizes it to be used in the ansible charm.
84
85 :param path: path of the root of the charm.
86 :return: a list of dictionaries with the information about the playbooks.
87 """
88 playbooks_path = path + '/playbooks'
89
90 if os.path.isdir(playbooks_path) and len(os.listdir(playbooks_path)) != 0:
91 filenames = os.listdir(playbooks_path)
92
93 result = []
94 for file in filenames:
95 info = {
96 'action_name': file.replace('_', '-').replace('.yaml', ''),
97 'function_name': file.replace('-', '_').replace('.yaml', ''),
98 'file': file
99 }
100 result.append(info)
101
102 return result
103 else:
104 AnsibleGenerator.LOGGER.error('Playbooks directory should exist and be populated.')
105 sys.exit(-1)
106
107 def _generate_ansible_lib(self):
108 """
109 Generates the ansible lib file from a template.
110 """
111 AnsibleGenerator.LOGGER.debug('Creating ansible.py lib...')
112
113 lib_folder_path = self.path + '/lib/charms'
114 ansible_lib_path = lib_folder_path + '/libansible.py'
115
116 if not os.path.isdir(lib_folder_path):
117 os.makedirs(lib_folder_path)
118
119 ansible_lib_template = AnsibleGenerator.ENV.get_template('ansible_lib.py.j2')
120
121 with open(ansible_lib_path, 'w') as f:
122 f.write(ansible_lib_template.render(license=self.license))
123
124 AnsibleGenerator.LOGGER.debug('Created anisble.py lib.')
125
126 def _generate_layer_yaml_file(self):
127 """
128 Generates the layer.yaml file from a template.
129
130 Note: disables the venv environment.
131 """
132 AnsibleGenerator.LOGGER.debug('Creating layer.yaml...')
133
134 layer_yaml_path = self.path + '/layer.yaml'
135
136 layers = [{
137 'name': 'basic',
138 'options': [{
139 'name': 'use_venv',
140 'value': 'false'
141 }]}, {
142 'name': 'ansible-base'
143 }, {
144 'name': 'vnfproxy'
145 }]
146
147 layer_template = AnsibleGenerator.ENV.get_template('layer.yaml.j2')
148
149 with open(layer_yaml_path, 'w') as f:
150 f.write(layer_template.render(layers=layers, license=self.license))
151
152 AnsibleGenerator.LOGGER.debug('Created layer.yaml.')
153
154 def _generate_reactive_file(self):
155 """
156 Generates the Ansible reactive file from a template.
157 It takes all the playbook information and fills in the templates.
158
159 Note: renames the old charm file with a .bkp extension, so the history is preserved.
160 """
161 AnsibleGenerator.LOGGER.debug('Creating ansible charm: %s...', self.metadata['file'])
162
163 reactive_folder_path = self.path + '/reactive'
164 charm_file_path = reactive_folder_path + ('/%s' % self.metadata['file'])
165 ansible_charm_template = AnsibleGenerator.ENV.get_template('ansible_charm.py.j2')
166
167 ids = [int(f.split('.')[-1]) for f in os.listdir(reactive_folder_path)
168 if f.startswith('%s.bkp' % self.metadata['file'])]
169
170 id = 0
171 if ids:
172 id = functools.reduce(lambda x, y: x if (x > y) else y, ids)
173 id += 1
174
175 backup_charm_file_path = reactive_folder_path + ('/%s.bkp.%02d' % (self.metadata['file'], id))
176 os.rename(charm_file_path, backup_charm_file_path)
177
178 with open(charm_file_path, 'w') as f:
179 f.write(ansible_charm_template.render(charm_name=self.metadata['name'], playbooks=self.playbooks,
180 license=self.license))
181
182 AnsibleGenerator.LOGGER.debug('Created ansible charm: %s.', self.metadata['file'])