blob: 70924ca149bbca1e8ebd4e47e72258636cd61627 [file] [log] [blame]
Vasyl Saienkof9ee1582020-03-02 16:53:41 +02001#!/usr/bin/python3
2#
3# Copyright 2018 Mirantis, Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17
18"""Prepare metadata python module
19
Dennis Dmitrievb12d2342020-03-12 19:36:24 +020020The module is aimed to prepare system files (networking configs etc)
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020021based on lab metadata.
Dennis Dmitrievb12d2342020-03-12 19:36:24 +020022Shell environment variables can be used in the metadata as Jinja2 variables.
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020023
24Example:
25 python prepare-metadata --metadata-file '/etc/lab-metadata.yaml'
26
27Example of lab-metadata.yaml
28
29'52:54:00:10:94:78':
30 write_files:
31 - path: '/tmp/123.yaml'
32 content: |
33 foo: bar
Dennis Dmitrievb12d2342020-03-12 19:36:24 +020034 bee: {{ PUBLIC_INTERFACE_IP }}
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020035
36Attributes:
37 metadata-file - The file with metadata
38"""
39
40
41__version__ = '1.0'
42
43import argparse
Dennis Dmitrievb12d2342020-03-12 19:36:24 +020044import jinja2
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020045import os
46import yaml
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020047import netifaces
48import sys
49
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020050
51def main():
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020052
53 parser = argparse.ArgumentParser(
54 description=('Render system files based on metadata')
55 )
56
57 group = parser.add_argument_group()
58 group.add_argument(
59 '--metadata-file',
60 help='The path to metadata file.',
61 required=True
62 )
63 args = parser.parse_args()
64
Dennis Dmitrievb12d2342020-03-12 19:36:24 +020065 metadata = yaml.safe_load(render_template(args.metadata_file))
66
Vasyl Saienkoc719b5c2020-03-05 19:14:26 +020067 if not metadata:
Dennis Dmitrievb12d2342020-03-12 19:36:24 +020068 print("The metadata is empty")
Vasyl Saienkoc719b5c2020-03-05 19:14:26 +020069 return
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020070 node_meta = get_node_metadata(metadata)
71 if node_meta is not None:
Dennis Dmitrievb12d2342020-03-12 19:36:24 +020072 print(f"Processing node_metadata: {node_meta}")
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020073 create_files(node_meta.get('write_files', []))
74 else:
Dennis Dmitrievb12d2342020-03-12 19:36:24 +020075 print("No matches to MACs for node_metadata found")
Vasyl Saienkof9ee1582020-03-02 16:53:41 +020076
77def get_interface_mac(iface_name):
78 mac = None
79 ifaddresses = netifaces.ifaddresses(iface_name)
80 link = ifaddresses.get(netifaces.AF_LINK, [])
81 if link:
82 return link[0]['addr']
83
84def get_node_macs():
85 ifaces = netifaces.interfaces()
86 macs = [get_interface_mac(iface_name) for iface_name in ifaces]
87 return [mac for mac in macs if mac is not None]
88
89def get_node_metadata(metadata):
90 for mac in get_node_macs():
91 if mac in metadata:
92 return metadata[mac]
93
94def create_files(files_meta):
95 for file_meta in files_meta:
96 path = file_meta['path']
97 content = file_meta['content']
98 permissions = int(str(file_meta.get('permissions', '644')), base=8)
99 with open(path, "w") as f:
100 f.write(content)
101 os.chmod(path, permissions)
102
Dennis Dmitrievb12d2342020-03-12 19:36:24 +0200103def render_template(file_path):
104 """Render a Jinja2 template file
105
106 In the template:
107 {{ SOME_ENV_NAME }} : Insert an environment variable into the template
108
109 :param file_path: str, path to the jinja2 template
110 """
111 print("Reading template {0}".format(file_path))
112
113 path, filename = os.path.split(file_path)
114 environment = jinja2.Environment(
115 loader=jinja2.FileSystemLoader([path, os.path.dirname(path)],
116 followlinks=True))
117 template = environment.get_template(filename).render(os.environ)
118
119 return template
120
Vasyl Saienkof9ee1582020-03-02 16:53:41 +0200121if __name__ == '__main__':
122 try:
123 main()
124 except Exception as e:
Dennis Dmitrievb12d2342020-03-12 19:36:24 +0200125 print(f"Failed to apply image layout: {e}")
Vasyl Saienkof9ee1582020-03-02 16:53:41 +0200126 sys.exit(1)