Plugins for configuration manager
[ta/cm-plugins.git] / activators / src / installationactivator.py
1 #! /usr/bin/python
2 # Copyright 2019 Nokia
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 from cmframework.apis import cmerror
17 from cmframework.apis import cmactivator
18 from cmdatahandlers.api import configmanager
19 from cmdatahandlers.api import configerror
20 import os
21 import subprocess
22 import json
23 import pwd
24 import logging
25
26 class installationactivator(cmactivator.CMGlobalActivator):
27     inventory_cli = '/opt/cmframework/scripts/inventory.sh'
28     playbooks_generate_cli = '/usr/local/bin/cmcli ansible-playbooks-generate'
29     playbooks_path = '/opt/openstack-ansible/playbooks/'
30     setup_playbook = 'setup-playbook.yml'
31     presetup_playbook = 'presetup-playbook.yml'
32     bootstrapping_playbook = 'bootstrapping-playbook.yml'
33     provisioning_playbook = 'provisioning-playbook.yml'
34     postconfig_playbook = 'postconfig-playbook.yml'
35     state_file = '/etc/installation_state'
36
37     def __init__(self):
38         self.plugin_client = None
39
40     def get_subscription_info(self):
41         return '.*'
42
43     def activate_set(self, props):
44         self.activate_full()
45
46     def activate_delete(self, props):
47         self.activate_full()
48
49     def activate_full(self, target=None):
50         try:
51             properties = self.get_plugin_client().get_properties('.*')
52             if not properties:
53                 return
54             propsjson = {}
55             for name, value in properties.iteritems():
56                 try:
57                     propsjson[name] = json.loads(value)
58                 except Exception as exp:
59                     continue
60             configman = configmanager.ConfigManager(propsjson)
61
62             hostsconfig = configman.get_hosts_config_handler()
63             installation_host = hostsconfig.get_installation_host()
64
65             installed = False
66             try:
67                 configman.get_cloud_installation_date()
68                 installed = True
69             except configerror.ConfigError as exp:
70                 pass
71
72             if installed:
73                 return
74
75             usersconf = configman.get_users_config_handler()
76             admin = usersconf.get_admin_user()
77
78             #generate high level playbooks
79             if self._run_cmd(self.playbooks_generate_cli, '/etc', 'root', os.environ.copy()):
80                 raise cmerror.CMError('Failed to run %s' % self.playbooks_generate_cli)
81
82             caas_data = configman.get_caas_config_handler()
83             phase = self._get_installation_phase()
84             #first we run the setup 
85             if not phase:
86                 self._set_installation_phase('setup-started')
87                 phase = 'setup-started'
88             env = os.environ.copy()
89             if phase == 'setup-started':
90                 env['VNF_EMBEDDED_DEPLOYMENT'] = 'false'
91                 env['CONFIG_PHASE'] = 'setup'
92                 env['BOOTSTRAP_OPTS'] = 'installation_controller=%s' %(installation_host)
93                 self._run_setup_playbook(self.presetup_playbook, env)
94                 env['BOOTSTRAP_OPTS'] = ''
95                 if caas_data.get_vnf_flag():
96                     env['VNF_EMBEDDED_DEPLOYMENT'] = 'true'
97                 self._run_setup_playbook(self.setup_playbook, env)
98                 self._set_installation_phase('setup-ended')
99                 phase = 'setup-ended'
100
101             #second we run the aio
102             if phase == 'setup-ended':
103                 self._set_installation_phase('bootstrapping-started')
104                 phase = 'bootstrapping-started'
105             if phase == 'bootstrapping-started':
106                 env['CONFIG_PHASE'] = 'bootstrapping'
107                 self._run_playbook(self.bootstrapping_playbook, admin, env)
108                 self._set_installation_phase('bootstrapping-ended')
109                 phase = 'bootstrapping-ended'
110
111             #3rd we run the provisioning
112             if phase == 'bootstrapping-ended':
113                 self._set_installation_phase('provisioning-started')
114                 phase = 'provisioning-started'
115             if phase == 'provisioning-started':
116                 env['CONFIG_PHASE'] = 'provisioning'
117                 self._run_playbook(self.provisioning_playbook, admin, env)
118                 self._set_installation_phase('provisioning-ended')
119                 phase = 'provisioning-ended'
120
121             #4th we run the postconfig
122             if phase == 'provisioning-ended':
123                 self._set_installation_phase('postconfig-started')
124                 phase = 'postconfig-started'
125             if phase == 'postconfig-started':
126                 env['CONFIG_PHASE'] = 'postconfig'
127                 env['CAAS_ONLY_DEPLOYMENT'] = 'false'
128                 if caas_data.get_caas_only():
129                     env['CAAS_ONLY_DEPLOYMENT'] = 'true'
130                 self._run_playbook(self.postconfig_playbook, admin, env)
131                 self._set_installation_phase('postconfig-ended')
132                 phase = 'postconfig-ended'
133             
134             self._set_installation_date()
135
136             self._set_state('success')
137
138         except Exception as exp:
139             self._set_state('failure')
140             raise cmerror.CMError(str(exp))
141
142     def _set_installation_phase(self, phase):
143         self.get_plugin_client().set_property('cloud.installation_phase', json.dumps(phase))
144
145     def _get_installation_phase(self):
146         phase = None
147         try:
148             phase = json.loads(self.get_plugin_client().get_property('cloud.installation_phase'))
149             logging.debug('Current installation phase cloud.installation_phase="%s"'%phase)
150         except Exception as exp:
151             pass
152         return phase
153
154     def _set_installation_date(self):
155         from time import gmtime, strftime
156         # Use ISO 8601 date format
157         times = strftime('%Y-%m-%dT%H:%M:%SZ', gmtime())
158         self.get_plugin_client().set_property('cloud.installation_date', json.dumps(times))
159
160     def _run_playbook(self, playbook, user, env):
161         cmd = '/usr/local/bin/openstack-ansible -b -u ' + user + ' ' + playbook
162         result = self._run_cmd(cmd, self.playbooks_path, user, env)
163         if result != 0:
164             raise cmerror.CMError('Playbook %s failed' % playbook)
165         
166     def _run_setup_playbook(self, playbook, env):
167         cmd = '/usr/local/bin/setup-controller.sh ' + playbook
168         result = self._run_cmd(cmd, self.playbooks_path, 'root', env)
169         if result != 0:
170             raise cmerror.CMError('Playbook %s failed' % playbook)
171         
172     def _run_cmd(self, cmd, cwd, user, env):
173         args = cmd.split()
174         pw_record = pwd.getpwnam(user)
175         user_name = pw_record.pw_name
176         user_home_dir = pw_record.pw_dir
177         user_uid = pw_record.pw_uid
178         user_gid = pw_record.pw_gid
179         env['HOME'] = user_home_dir
180         env['LOGNAME'] = user_name
181         env['HOME'] = user_home_dir
182         env['PWD'] = cwd
183         env['USER'] = user_name
184         process = subprocess.Popen(args, preexec_fn=self._demote(user_uid, user_gid), cwd=cwd, env=env)
185         result = process.wait()
186         return result
187
188
189     def _demote(self, user_uid, user_gid):
190         def result():
191             os.setgid(user_gid)
192             os.setuid(user_uid)
193         return result
194
195     def _set_state(self, state):
196         with open(self.state_file, 'w') as f:
197             f.write(state)