3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain 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,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
16 from functools import wraps
17 from cmframework import apis as cmapis
20 def handle_exceptions(func):
22 def wrapper(self, *arg, **kwargs):
24 return func(self, *arg, **kwargs)
25 except cmapis.cmerror.CMError as exp:
27 except Exception as exp:
28 raise cmapis.cmerror.CMError(str(exp))
33 class CMClient(object):
37 def __call__(self, msg):
40 logger = VerboseLogger()
42 client = CMClient(192.128.254.10, 51110, cmclient.CMClientImpl, logger)
44 value = client.get_property('controller-1.ntp.servers')
45 except cmapis.cmerror.CMError as error:
46 print('Got exception %s' % str(error))
50 def __init__(self, server_ip='config-manager', server_port=61100,
51 client_lib_impl_module='cmframework.lib.CMClientImpl', verbose_logger=None):
52 """ initialize the client interface
56 server_ip: The configuration management server ip address.
58 server_port: The configuration management server port number.
60 client_lib_impl_module: The module implementing the client library.
62 verbose_logger: The verbose logging callable. any callable which
63 takes a string as input argument can be used.
67 CMError exception in-case of a failure.
72 serverip = socket.gethostbyname(server_ip)
73 except Exception: # pylint: disable=broad-except
74 # use localhost in-case we cannot resolve the provided hostname
75 serverip = '127.0.0.1'
77 self.server_ip = serverip
78 self.server_port = server_port
79 self.client_lib = None
80 self.verbose_logger = verbose_logger
82 # Separate class path and module name
83 parts = client_lib_impl_module.rsplit('.', 1)
84 module_path = parts[0]
86 self.verbose_log('module_path = %s' % module_path)
87 self.verbose_log('class_name = %s' % class_name)
88 module = __import__(module_path, fromlist=[module_path])
89 classobj = getattr(module, class_name)
90 self.client_lib = classobj(self.server_ip, self.server_port, verbose_logger)
92 def verbose_log(self, msg):
93 if self.verbose_logger:
94 self.verbose_logger(msg)
97 def get_property(self, prop_name, snapshot_name=None):
98 """get the value assoicated with a property.
100 This is the API used to read the value associated with a
101 configuration property.
105 prop_name: The property name
106 (optional) snapshot_name: The snapshot name
110 CMError in-case of a failure.
112 result = self.client_lib.get_property(prop_name, snapshot_name)
116 def get_properties(self, prop_filter, snapshot_name=None):
117 """get a set of properties matching a filter.
119 This is the API used to read a group of properties matching some
124 prop_filter: A valid python re describing the filter used when
125 matching the returned properties.
126 (optional) snapshot_name: The snapshot name
130 CMError is raised in-case of a failure.
132 self._check_filter(prop_filter)
133 result = self.client_lib.get_properties(prop_filter, snapshot_name)
137 def set_property(self, prop_name, prop_value):
138 """set/update the value of a property.
140 This is the API used to set/update the value associated with a
145 prop_name: A string representing the property name.
147 prop_value: A string representing the property value.
151 CMError is raised in-case of failure.
153 return self.client_lib.set_property(prop_name, prop_value)
156 def set_properties(self, props, overwrite=False):
157 """set/update a group of properties as a whole
159 This API is used to set/update the values associated with a group of
160 properties as a whole, the change is either accepted as a whole or
165 props: A dictionary containing the changed properties.
167 overwrite: Replace the existing configuration dictionary with the new one.
171 CMError is raised in-case of a failure.
173 return self.client_lib.set_properties(props, overwrite)
176 def delete_property(self, prop_name):
179 This is the API used to delete a configuration property.
183 prop_name: The name of the property to be deleted.
187 CMError is raised in-case of a failure.
189 return self.client_lib.delete_property(prop_name)
192 def delete_properties(self, arg):
193 """delete a group of properties as a whole
195 This is the API used to delete a group of properties as whole, if the
196 deletion of one of the properties is rejected then the whole delete
201 arg: This can be either a string representing the re used when
202 matching the properties to be deleted, or it can be a list of
203 properties names to be deleted.
207 CMError is raised in-case of a failure.
209 if isinstance(arg, str):
210 self._check_filter(arg)
211 return self.client_lib.delete_properties(arg)
214 def get_changes_states(self, change_uuid):
215 """get the config changes states
217 This is the API used to get the changes states
221 arg: This can be either a valid change uuid or None.
225 CMError is raised in-case of a failure.
227 return self.client_lib.get_changes_states(change_uuid)
230 def wait_activation(self, change_uuid):
231 """wait for activation of config changes to finish
233 This is the API used to wait for config changes to finish
237 arg: A valid change uuid.
241 CMError is raised in-case of a failure.
243 return self.client_lib.wait_activation(change_uuid)
245 # pylint: disable=no-self-use
246 def _check_filter(self, prop_filter):
247 re.compile(prop_filter)