X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=cmframework%2Fsrc%2Fcmframework%2Fapis%2Fcmactivator.py;fp=cmframework%2Fsrc%2Fcmframework%2Fapis%2Fcmactivator.py;h=05f9f36b9a09d56a0fcc4d3a326fdb29a99653e8;hb=c389bdee7b3845b55f443dbf04c0ce4083a55886;hp=0000000000000000000000000000000000000000;hpb=5030f0c004701dd422c78c71c014ef60f48139fc;p=ta%2Fconfig-manager.git diff --git a/cmframework/src/cmframework/apis/cmactivator.py b/cmframework/src/cmframework/apis/cmactivator.py new file mode 100644 index 0000000..05f9f36 --- /dev/null +++ b/cmframework/src/cmframework/apis/cmactivator.py @@ -0,0 +1,195 @@ +# Copyright 2019 Nokia + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import subprocess +import pwd +import logging + +from cmframework.apis import cmerror + + +class CMActivator(object): + ansible_bin = '/usr/local/bin/openstack-ansible' + admin_user_file = '/etc/admin_user' + + def __init__(self): + self.plugin_client = None + try: + with open(CMActivator.admin_user_file, 'r') as f: + self.admin_user = f.read() + except IOError: + pass + + # pylint: disable=no-self-use + def get_subscription_info(self): + """get the subscription filter + + This API is used to get the re for matching the properties which the + activation plugin is concerned about. + + Return: + + A string representing the regular expression used to match the + properties which the activation plugin is concerned about. + + Raise: + + CMError can be raised in-case of a failure. + """ + raise cmerror.CMError('Not implemented') + + # pylint: disable=no-self-use, unused-argument + def activate_set(self, props): + """activate a configuration data addition/update + + Arguments: + + props: A dictionary of name-value pairs representing the changed + properties. + + Raise: + + CMError can be raised in-case of an error + """ + raise cmerror.CMError('Not implemented') + + # pylint: disable=no-self-use, unused-argument + def activate_delete(self, props): + """activate a configuration data deletion + + Arguments: + + props: A list of deleted property names. + + Raise: + + CMError can be raised in-case of an error + """ + raise cmerror.CMError('Not implemented') + + # pylint: disable=no-self-use, unused-argument + def activate_full(self, target): + """perform a full activation + + Arguments: + + target: None if activating all nodes + Node name string if activating only one node + + Raise: + + CMError can be raised in-case of an error + """ + raise cmerror.CMError('Not implemented') + + # pylint: disable=no-self-use + def get_plugin_client(self): + """get the plugin client object + + This API can be used by the plugin to get the client object which the + plugin can use to access the configuration data. Notice that the data + accessed by this is what is stored in the backend. The changed data + is passed as argument to the different validate functions. + + Return: + + The plugin client object + """ + return self.plugin_client + + def run_playbook(self, playbook, target=None): + playbook_dir = os.path.dirname(playbook) + + arguments = [] + arguments.append('-b') + arguments.append('-u {}'.format(self.admin_user)) + if target: + arguments.append('--limit {}'.format(target)) + arguments.append(playbook) + + cmd = '{} {}'.format(CMActivator.ansible_bin, ' '.join(arguments)) + out, result = self._run_cmd_as_user(cmd, playbook_dir, self.admin_user) + if result != 0: + raise cmerror.CMError('Playbook {} failed: {}'.format(playbook, out)) + logging.debug('Playbook out: %s', out) + + def _run_cmd_as_user(self, cmd, cwd, user): + pw_record = pwd.getpwnam(user) + user_name = pw_record.pw_name + user_home_dir = pw_record.pw_dir + user_uid = pw_record.pw_uid + user_gid = pw_record.pw_gid + env = os.environ.copy() + env['CONFIG_PHASE'] = 'postconfig' + env['HOME'] = user_home_dir + env['LOGNAME'] = user_name + env['PWD'] = cwd + env['USER'] = user_name + p = subprocess.Popen(cmd.split(), preexec_fn=self._demote(user_uid, user_gid), + cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, _ = p.communicate() + return (out, p.returncode) + + def _demote(self, user_uid, user_gid): + def result(): + os.setgid(user_gid) + os.setuid(user_uid) + + return result + + +class CMGlobalActivator(CMActivator): + def __init__(self): + super(CMGlobalActivator, self).__init__() + + +class CMLocalActivator(CMActivator): + def __init__(self): + super(CMLocalActivator, self).__init__() + self.hostname = None + + def get_hostname(self): + """get the node name + + This API is used to get the name of the node where activation is + ongoing. + + Return: + + The node name + """ + return self.hostname + + +def main(): + def print_type(activator): + if isinstance(activator, CMLocalActivator): + print 'Local activator' + elif isinstance(activator, CMActivator): + print 'Activator' + else: + print 'Unknown' + + activator = CMActivator() + localactivator = CMLocalActivator() + + x = 100 + + print_type(activator) + print_type(localactivator) + print_type(x) + + +if __name__ == '__main__': + main()