1 # Copyright 2019 Whitestack, LLC
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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
15 # For those usages not covered by the Apache License, Version 2.0 please
16 # contact: esousa@whitestack.com or glavado@whitestack.com
24 from jinja2
import Environment
, PackageLoader
26 from generator
.generators
.actions_generator
import ActionsGenerator
27 from generator
.generators
.metadata_generator
import MetadataGenerator
30 class AnsibleGenerator
:
31 LOGGER
= logging
.getLogger()
32 ENV
= Environment(loader
=PackageLoader('generator.ansible-charm', 'templates'))
34 def __init__(self
, metadata
, license
=None, options
=None):
36 Creates the object to generate the ansible charm from templates.
41 2) Run the generate method.
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.
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
)
53 playbooks_name
= [playbook
['file'] for playbook
in self
.playbooks
]
54 AnsibleGenerator
.LOGGER
.debug('Playbooks found: %s', playbooks_name
)
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
,
62 Generates the Ansible Charm using templates.
64 AnsibleGenerator
.LOGGER
.info('Generating the Ansible Charm...')
66 # Generating metadata.yaml
67 self
.metadata_generator
.generate()
68 self
.metadata
= self
.metadata_generator
.get_metadata()
71 self
.actions_generator
.generate()
73 self
._generate
_ansible
_lib
()
74 self
._generate
_layer
_yaml
_file
()
75 self
._generate
_reactive
_file
()
77 AnsibleGenerator
.LOGGER
.info('Generated the Ansible Charm.')
80 def _fetch_all_playbooks(path
):
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.
85 :param path: path of the root of the charm.
86 :return: a list of dictionaries with the information about the playbooks.
88 playbooks_path
= path
+ '/playbooks'
90 if os
.path
.isdir(playbooks_path
) and len(os
.listdir(playbooks_path
)) != 0:
91 filenames
= os
.listdir(playbooks_path
)
94 for file in filenames
:
96 'action_name': file.replace('_', '-').replace('.yaml', ''),
97 'function_name': file.replace('-', '_').replace('.yaml', ''),
104 AnsibleGenerator
.LOGGER
.error('Playbooks directory should exist and be populated.')
107 def _generate_ansible_lib(self
):
109 Generates the ansible lib file from a template.
111 AnsibleGenerator
.LOGGER
.debug('Creating ansible.py lib...')
113 lib_folder_path
= self
.path
+ '/lib/charms'
114 ansible_lib_path
= lib_folder_path
+ '/libansible.py'
116 if not os
.path
.isdir(lib_folder_path
):
117 os
.makedirs(lib_folder_path
)
119 ansible_lib_template
= AnsibleGenerator
.ENV
.get_template('ansible_lib.py.j2')
121 with
open(ansible_lib_path
, 'w') as f
:
122 f
.write(ansible_lib_template
.render(license
=self
.license
))
124 AnsibleGenerator
.LOGGER
.debug('Created anisble.py lib.')
126 def _generate_layer_yaml_file(self
):
128 Generates the layer.yaml file from a template.
130 Note: disables the venv environment.
132 AnsibleGenerator
.LOGGER
.debug('Creating layer.yaml...')
134 layer_yaml_path
= self
.path
+ '/layer.yaml'
142 'name': 'ansible-base'
147 layer_template
= AnsibleGenerator
.ENV
.get_template('layer.yaml.j2')
149 with
open(layer_yaml_path
, 'w') as f
:
150 f
.write(layer_template
.render(layers
=layers
, license
=self
.license
))
152 AnsibleGenerator
.LOGGER
.debug('Created layer.yaml.')
154 def _generate_reactive_file(self
):
156 Generates the Ansible reactive file from a template.
157 It takes all the playbook information and fills in the templates.
159 Note: renames the old charm file with a .bkp extension, so the history is preserved.
161 AnsibleGenerator
.LOGGER
.debug('Creating ansible charm: %s...', self
.metadata
['file'])
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')
167 ids
= [int(f
.split('.')[-1]) for f
in os
.listdir(reactive_folder_path
)
168 if f
.startswith('%s.bkp' % self
.metadata
['file'])]
172 id = functools
.reduce(lambda x
, y
: x
if (x
> y
) else y
, ids
)
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
)
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
))
182 AnsibleGenerator
.LOGGER
.debug('Created ansible charm: %s.', self
.metadata
['file'])