blob: 12e7ba9844877e24acc7949dc9ea63f0a7fe6077 [file] [log] [blame]
Ales Komarek166cc672016-07-27 14:17:22 +02001# -*- coding: utf-8 -*-
2'''
3Management of reclass metadata
4==============================
5
6.. code-block:: yaml
7
8 node01:
9 reclass.node_present:
10 - name: hostaname.domain.com
11 - path: _generated
12 - cluster: default
13 - environment: prd
14 - classes:
15 - neco.service.neco
16 - neco2.class.neco.dal
17 - parameters:
18 neco: value1
19 neco2: value2
20
Adam Tengler8a1cf402017-05-16 10:59:35 +000021.. code-block:: yaml
22
23 node_meta_01:
24 reclass.cluster_meta_present:
25 - name: my_key
26 - value: my_value
Ales Komarek166cc672016-07-27 14:17:22 +020027'''
Adam Tengler8a1cf402017-05-16 10:59:35 +000028from __future__ import absolute_import
29
Adam Tengler805666d2017-05-15 16:01:13 +000030import json
Adam Tengler8a1cf402017-05-16 10:59:35 +000031import os
Adam Tengler805666d2017-05-15 16:01:13 +000032import six
Ales Komarek166cc672016-07-27 14:17:22 +020033
Adam Tengler8a1cf402017-05-16 10:59:35 +000034from reclass.config import find_and_read_configfile
35
Ales Komarek166cc672016-07-27 14:17:22 +020036
37def __virtual__():
38 '''
Adam Tengler805666d2017-05-15 16:01:13 +000039 Only load if the reclass module is in __salt__
Ales Komarek166cc672016-07-27 14:17:22 +020040 '''
Adam Tengler805666d2017-05-15 16:01:13 +000041 return 'reclass' if 'reclass.node_list' in __salt__ else False
42
43
Adam Tengler8a1cf402017-05-16 10:59:35 +000044def _get_classes_dir():
45 defaults = find_and_read_configfile()
46 return os.path.join(defaults.get('inventory_base_uri'), 'classes')
47
48
49def _get_cluster_dir():
50 classes_dir = _get_classes_dir()
51 return os.path.join(classes_dir, 'cluster')
52
53
Adam Tengler805666d2017-05-15 16:01:13 +000054def node_present(name, path=None, cluster="default", environment="prd", classes=None, parameters=None, **kwargs):
55 '''
56 Ensure that the reclass node exists
57
58 :param name: new node FQDN
59 :param path: custom path in nodes for new node
60 :param classes: classes given to the new node
61 :param parameters: parameters given to the new node
62 :param environment: node's environment
63 :param cluster: node's cluster
64
65 '''
66 ret = {'name': name,
67 'changes': {},
68 'result': True,
69 'comment': 'Node "{0}" already exists and it is in correct state'.format(name)}
70
71 # Check if node is already present
72 node = __salt__['reclass.node_get'](name, **kwargs)
73
74 if 'Error' in node:
Adam Tenglerabe99ee2017-09-04 11:35:23 +000075 if __opts__['test']:
76 ret['result'] = None
77 ret['comment'] = 'Node "{0}" would be created'.format(name)
78 return ret
Adam Tengler805666d2017-05-15 16:01:13 +000079 # Create node
80 __salt__['reclass.node_create'](name, path, cluster, environment, classes, parameters, **kwargs)
81 ret['comment'] = 'Node "{0}" has been created'.format(name)
82 ret['changes']['Node'] = 'Created'
83 return ret
Ales Komarek166cc672016-07-27 14:17:22 +020084
Adam Tengler8a1cf402017-05-16 10:59:35 +000085
Adam Tengler23d965f2017-05-16 19:14:51 +000086def dynamic_node_present(name, node_data={}, class_mapping={}, **kwargs):
87 '''
88 Classify node, create cluster level overrides and node metadata
89
90 :param name: node FQDN
91 :param node_data: dictionary of known informations about the node
92 :param class_mapping: dictionary of classes and parameters, with conditions
93
94 '''
95 ret = {'name': name,
96 'changes': {},
97 'result': True,
98 'comment': 'Node "{0}" already exists and it is in correct state'.format(name)}
99
Adam Tenglerabe99ee2017-09-04 11:35:23 +0000100 if __opts__['test']:
101 ret['result'] = None
102 ret['comment'] = 'Classification of node "{0}" would be updated'.format(name)
103 return ret
104
Adam Tengler23d965f2017-05-16 19:14:51 +0000105 classify_ret = __salt__['reclass.node_classify'](name, node_data, class_mapping, **kwargs)
106 ret['comment'] = 'Node "{0}" has been created'.format(name)
107 ret['changes']['Node'] = classify_ret
108
109 return ret
110
111
Adam Tenglerabe99ee2017-09-04 11:35:23 +0000112def node_absent(name, **kwargs):
113 '''
114 Delete node from reclass metadata
115
116 :param name: node minion ID
117
118 '''
119 ret = {'name': name,
120 'changes': {},
121 'result': True,
122 'comment': 'Node "{0}" already absent'.format(name)}
123
124 # Check if node is present
125 node = __salt__['reclass.node_get'](name, **kwargs)
126 if 'Error' in node:
127 return ret
128
129 if __opts__['test']:
130 ret['result'] = None
131 ret['comment'] = 'Node "{0}" would be deleted'.format(name)
132 return ret
133
134 delete_ret = __salt__['reclass.node_delete'](name, **kwargs)
135 if 'Error' in delete_ret:
136 ret['result'] = False
137 ret['comment'] = delete_ret.get('Error', '')
138 return ret
139
140 ret['comment'] = 'Node "{0}" has been deleted'.format(name)
141 ret['changes']['Node'] = delete_ret
142
143 return ret
144
145
Adam Tengler8a1cf402017-05-16 10:59:35 +0000146def cluster_meta_present(name, value, file_name="overrides.yml", cluster="", **kwargs):
147 '''
148 Ensures that the cluster metadata entry exists
149
150 :param name: Metadata entry name
151 :param value: Metadata entry value
152 :param file_name: Name of metadata file, defaults to overrides.yml
153 :param cluster: Name of cluster directory to put the metadata file into, optional
154 '''
155 value = value or ""
156 cluster = cluster or ""
157 path = os.path.join(_get_cluster_dir(), cluster, file_name)
158 ret = {'name': name,
159 'changes': {},
160 'result': True,
161 'comment': 'Cluster metadata entry "{0}" already exists and is in correct state'.format(name)}
162 meta_check = __salt__['reclass.cluster_meta_get'](name, path, **kwargs)
163 if not meta_check:
Adam Tenglerabe99ee2017-09-04 11:35:23 +0000164 if __opts__['test']:
165 ret['result'] = None
166 ret['comment'] = 'Cluster metadata entry "{0}" would be created'.format(name)
167 return ret
Adam Tengler8a1cf402017-05-16 10:59:35 +0000168 __salt__['reclass.cluster_meta_set'](name, value, path, **kwargs)
Adam Tenglerabe99ee2017-09-04 11:35:23 +0000169 ret['comment'] = 'Cluster metadata entry {0} has been created'.format(name)
Adam Tengler8a1cf402017-05-16 10:59:35 +0000170 ret['changes']['Meta Entry'] = 'Cluster meta entry %s: "%s" has been created' % (name, value)
171 elif 'Error' in meta_check:
172 ret['comment'] = meta_check.get('Error')
173 ret['result'] = False
174 elif meta_check[name] != value:
Adam Tenglerabe99ee2017-09-04 11:35:23 +0000175 if __opts__['test']:
176 ret['result'] = None
177 ret['comment'] = 'Cluster metadata entry "{0}" would be updated'.format(name)
178 ret['changes']['Old Meta Entry'] = '{0}: "{1}"'.format(name, meta_check[name])
179 ret['changes']['New Meta Entry'] = '{0}: "{1}"'.format(name, value)
180 return ret
Adam Tengler8a1cf402017-05-16 10:59:35 +0000181 __salt__['reclass.cluster_meta_set'](name, value, path, **kwargs)
Adam Tenglerabe99ee2017-09-04 11:35:23 +0000182 ret['comment'] = 'Cluster metadata entry {0} has been updated'.format(name)
183 ret['changes']['Old Meta Entry'] = '{0}: "{1}"'.format(name, meta_check[name])
184 ret['changes']['New Meta Entry'] = '{0}: "{1}"'.format(name, value)
Adam Tengler8a1cf402017-05-16 10:59:35 +0000185 return ret
186
187
188def cluster_meta_absent(name, file_name="overrides.yml", cluster="", **kwargs):
189 '''
190 Ensures that the cluster metadata entry does not exist
191
192 :param name: Metadata entry name
193 :param file_name: Name of metadata file, defaults to overrides.yml
194 :param cluster: Name of cluster directory to put the metadata file into, optional
195 '''
196 cluster = cluster or ""
197 path = os.path.join(_get_cluster_dir(), cluster, file_name)
198 ret = {'name': name,
199 'changes': {},
200 'result': True,
201 'comment': 'Cluster metadata entry "{0}" is already absent'.format(name)}
202 meta_check = __salt__['reclass.cluster_meta_get'](name, path, **kwargs)
203 if meta_check:
Adam Tenglerabe99ee2017-09-04 11:35:23 +0000204 if __opts__['test']:
205 ret['result'] = None
206 ret['comment'] = 'Cluster metadata entry "{0}" would be deleted'.format(name)
207 return ret
Adam Tengler8a1cf402017-05-16 10:59:35 +0000208 __salt__['reclass.cluster_meta_delete'](name, path, **kwargs)
209 ret['comment'] = 'Cluster metadata entry {0} has been deleted'.format(name)
210 ret['changes']['Meta Entry'] = 'Cluster metadata entry %s: "%s" has been deleted' % (name, meta_check[name])
211 elif 'Error' in meta_check:
212 ret['comment'] = meta_check.get('Error')
213 ret['result'] = False
214 return ret
215