blob: 34ea4b90338380b1d0316ab79471add589660078 [file] [log] [blame]
Ales Komarek166cc672016-07-27 14:17:22 +02001# -*- coding: utf-8 -*-
2'''
Ales Komareka4a9f572016-12-03 20:15:50 +01003Module for handling reclass metadata models.
Ales Komarek166cc672016-07-27 14:17:22 +02004
5'''
6
7from __future__ import absolute_import
8
9import logging
10import os
11import sys
Ales Komareka961df42016-11-21 21:50:24 +010012import six
Ales Komarek166cc672016-07-27 14:17:22 +020013import yaml
Ales Komareka961df42016-11-21 21:50:24 +010014import json
Ales Komarek166cc672016-07-27 14:17:22 +020015
Ales Komareka4a9f572016-12-03 20:15:50 +010016from reclass import get_storage, output
17from reclass.core import Core
18from reclass.config import find_and_read_configfile
Ales Komarek166cc672016-07-27 14:17:22 +020019
Ales Komareka4a9f572016-12-03 20:15:50 +010020LOG = logging.getLogger(__name__)
Ales Komarek166cc672016-07-27 14:17:22 +020021
Ales Komareka961df42016-11-21 21:50:24 +010022
Ales Komarek166cc672016-07-27 14:17:22 +020023def __virtual__():
24 '''
25 Only load this module if reclass
26 is installed on this minion.
27 '''
28 return 'reclass'
29
30
Ales Komareka4a9f572016-12-03 20:15:50 +010031def _get_nodes_dir():
32 defaults = find_and_read_configfile()
33 return os.path.join(defaults.get('inventory_base_uri'), 'nodes')
34
35
36def _get_classes_dir():
37 defaults = find_and_read_configfile()
38 return os.path.join(defaults.get('inventory_base_uri'), 'classes')
Ales Komarek166cc672016-07-27 14:17:22 +020039
40
41def node_create(name, path=None, cluster="default", environment="prd", classes=None, parameters=None, **kwargs):
42 '''
43 Create a reclass node
44
45 :param name: new node FQDN
46 :param path: custom path in nodes for new node
47 :param classes: classes given to the new node
48 :param parameters: parameters given to the new node
49 :param environment: node's environment
50 :param cluster: node's cluster
51
52 CLI Examples:
53
54 .. code-block:: bash
55
56 salt '*' reclass.node_create server.domain.com classes=[system.neco1, system.neco2]
57 salt '*' reclass.node_create namespace/test enabled=False
58
59 '''
60 ret = {}
61
62 node = node_get(name=name)
63
64 if node and not "Error" in node:
65 LOG.debug("node {0} exists".format(name))
66 ret[name] = node
67 return ret
68
69 host_name = name.split('.')[0]
70 domain_name = '.'.join(name.split('.')[1:])
71
72 if classes == None:
73 meta_classes = []
74 else:
Ales Komareka961df42016-11-21 21:50:24 +010075 if isinstance(classes, six.string_types):
76 meta_classes = json.loads(classes)
77 else:
78 meta_classes = classes
Ales Komarek166cc672016-07-27 14:17:22 +020079
80 if parameters == None:
81 meta_parameters = {}
82 else:
Ales Komareka961df42016-11-21 21:50:24 +010083 if isinstance(parameters, six.string_types):
84 meta_parameters = json.loads(parameters)
85 else:
86 meta_parameters = parameters
Ales Komarek166cc672016-07-27 14:17:22 +020087
88 node_meta = {
89 'classes': meta_classes,
90 'parameters': {
91 '_param': meta_parameters,
92 'linux': {
93 'system': {
94 'name': host_name,
95 'domain': domain_name,
96 'cluster': cluster,
97 'environment': environment,
98 }
99 }
100 }
101 }
102 LOG.debug(node_meta)
103
104 if path == None:
Ales Komareka4a9f572016-12-03 20:15:50 +0100105 file_path = os.path.join(_get_nodes_dir(), name + '.yml')
Ales Komarek166cc672016-07-27 14:17:22 +0200106 else:
Ales Komareka4a9f572016-12-03 20:15:50 +0100107 file_path = os.path.join(_get_nodes_dir(), path, name + '.yml')
Ales Komarek166cc672016-07-27 14:17:22 +0200108
109 with open(file_path, 'w') as node_file:
Ales Komareka961df42016-11-21 21:50:24 +0100110 node_file.write(yaml.safe_dump(node_meta, default_flow_style=False))
Ales Komarek71f94b02016-07-27 14:48:57 +0200111
Ales Komarek166cc672016-07-27 14:17:22 +0200112 return node_get(name)
113
Ales Komareka4a9f572016-12-03 20:15:50 +0100114
Ales Komarek166cc672016-07-27 14:17:22 +0200115def node_delete(name, **kwargs):
116 '''
117 Delete a reclass node
118
119 :params node: Node name
120
121 CLI Examples:
122
123 .. code-block:: bash
124
125 salt '*' reclass.node_delete demo01.domain.com
126 salt '*' reclass.node_delete name=demo01.domain.com
127 '''
128
129 node = node_get(name=name)
130
131 if 'Error' in node:
132 return {'Error': 'Unable to retreive node'}
133
134 if node[name]['path'] == '':
Ales Komareka4a9f572016-12-03 20:15:50 +0100135 file_path = os.path.join(_get_nodes_dir(), name + '.yml')
Ales Komarek166cc672016-07-27 14:17:22 +0200136 else:
Ales Komareka4a9f572016-12-03 20:15:50 +0100137 file_path = os.path.join(_get_nodes_dir(), node[name]['path'], name + '.yml')
Ales Komarek166cc672016-07-27 14:17:22 +0200138
139 os.remove(file_path)
140
141 ret = 'Node {0} deleted'.format(name)
142
143 return ret
144
145
146def node_get(name, path=None, **kwargs):
147 '''
148 Return a specific node
149
150 CLI Examples:
151
152 .. code-block:: bash
153
154 salt '*' reclass.node_get host01.domain.com
155 salt '*' reclass.node_get name=host02.domain.com
156 '''
157 ret = {}
158 nodes = node_list(**kwargs)
159
160 if not name in nodes:
161 return {'Error': 'Error in retrieving node'}
162 ret[name] = nodes[name]
163 return ret
164
165
166def node_list(**connection_args):
167 '''
168 Return a list of available nodes
169
170 CLI Example:
171
172 .. code-block:: bash
173
174 salt '*' reclass.node_list
175 '''
176 ret = {}
177
Ales Komareka4a9f572016-12-03 20:15:50 +0100178 for root, sub_folders, files in os.walk(_get_nodes_dir()):
Ales Komarek166cc672016-07-27 14:17:22 +0200179 for file in files:
180 file_path = os.path.join(root, file)
181 file_content = open(file_path, 'r')
182 file_data = yaml.load(file_content.read())
183 file_content.close()
184 if 'classes' in file_data:
185 classes = file_data.get('classes')
186 else:
187 classes = []
188 if 'parameters' in file_data:
189 if '_param' in file_data.get('parameters'):
190 parameters = file_data.get('parameters').get('_param')
191 else:
192 parameters = []
193 else:
194 parameters = []
195 name = file.replace('.yml', '')
196 host_name = name.split('.')[0]
197 domain_name = '.'.join(name.split('.')[1:])
Ales Komareka4a9f572016-12-03 20:15:50 +0100198 path = root.replace(_get_nodes_dir()+'/', '')
Ales Komarek166cc672016-07-27 14:17:22 +0200199 ret[name] = {
Ales Komareka4a9f572016-12-03 20:15:50 +0100200 'name': host_name,
201 'domain': domain_name,
202 'cluster': 'default',
203 'environment': 'prd',
204 'path': path,
205 'classes': classes,
206 'parameters': parameters
Ales Komarek166cc672016-07-27 14:17:22 +0200207 }
208
209 return ret
210
Ales Komareka4a9f572016-12-03 20:15:50 +0100211
Ales Komarek166cc672016-07-27 14:17:22 +0200212def node_update(name, classes=None, parameters=None, **connection_args):
213 '''
214 Update a node metadata information, classes and parameters.
215
216 CLI Examples:
217
218 .. code-block:: bash
219
220 salt '*' reclass.node_update name=nodename classes="[clas1, class2]"
221 '''
222 node = node_get(name=name)
223 if not node.has_key('Error'):
Ales Komarek71f94b02016-07-27 14:48:57 +0200224 node = node[name.split("/")[1]]
225 else:
226 return {'Error': 'Error in retrieving node'}
Ales Komareka4a9f572016-12-03 20:15:50 +0100227
228
229def inventory(**connection_args):
230 '''
231 Get all nodes in inventory and their associated services/roles classification.
232
233 CLI Examples:
234
235 .. code-block:: bash
236
237 salt '*' reclass.inventory
238 '''
239 defaults = find_and_read_configfile()
240 storage = get_storage(defaults['storage_type'], _get_nodes_dir(), _get_classes_dir())
241 reclass = Core(storage, None)
242 nodes = reclass.inventory()["nodes"]
243 output = {}
244
245 for node in nodes:
246 service_classification = []
247 role_classification = []
248 for service in nodes[node]['parameters']:
249 if service not in ['_param', 'private_keys', 'public_keys', 'known_hosts']:
250 service_classification.append(service)
251 for role in nodes[node]['parameters'][service]:
252 if role not in ['_support', '_orchestrate', 'common']:
253 role_classification.append('%s.%s' % (service, role))
254 output[node] = {
255 'roles': role_classification,
256 'services': service_classification,
257 }
258 return output