summaryrefslogtreecommitdiff
path: root/src/orchestration/remoteregionhandler.py
blob: 6754672a01bde74117281d184b3fb1564489c3f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
import django
import os
import threading

from django.conf import settings
from django.core.exceptions import AppRegistryNotReady
from django.utils import timezone

from .utils import *

try:
    django.setup()
    from .models import ImageSync
    from caas.models import Cluster
    from caas.models import Location 
    from caas.models import Namespace  
except django.core.exceptions.AppRegistryNotReady as exp:
    pass            
                    
class RemoteRegionWorker:

    def __init__(self):
        pass

    def _get_crd_details(self):
        crd_cluster_role = "nad"
        crd_api_group = "k8s.cni.cncf.io"
        crd_api_resources = "network-attachment-definitions"
        crd_api_verbs = "*"
        return crd_cluster_role, crd_api_group, crd_api_resources, crd_api_verbs

    def _read_remote_openrc(self, remote_region_oam_ip, logger):
        #cmd = "scp @[fd00:4888:2000:120c::290]:/etc/platform/openrc .

        logger.info("Inside _read_remote_openrc")
        host_username = settings.HOST_CREDS['username']
        host_password = settings.HOST_CREDS['password']
        ssh_prefix = 'ssh -o StrictHostKeyChecking=no -t ' + host_username + '@' + remote_region_oam_ip
        env_string = ""
        cmds_scp = []
        folder = get_temp_file_location()
        logger.info("Tmp file location:" + folder)
        #tmpFilePath = os.path.join(os.path.dirname(__file__), "./" + folder)
        tmpFileName = 'openrc_' + str(remote_region_oam_ip)
        cmds_scp.append('scp -o StrictHostKeyChecking=no ' + host_username + '@[' + remote_region_oam_ip + ']:/etc/platform/openrc ' + folder + '/' + tmpFileName)
        logger.info(cmds_scp)
        run_commands_scp(cmds_scp, host_password, logger, block=True)
        logger.info("About to create env string")

        fp = open(folder + '/' + tmpFileName)
        lines = fp.readlines()
        logger.info(lines)
        password_line = ''
        for line in lines:
            line = line.lstrip().rstrip()
            logger.info(line)
            parts = line.split(' ')
            if len(parts) == 2:
                if parts[0] == 'export':
                    if parts[1]:
                        env_var = parts[1].lstrip().rstrip()
                        logger.info(env_var)
                        if 'OS_PASSWORD' not in env_var:
                            env_string = env_string + " " + env_var
            if len(parts) >= 2 and 'OS_PASSWORD=' in parts[1]:
                logger.info("Parsing password")
                password_parts = line.split('PASSWORD=')
                password_command_parts = password_parts[1].split(' ')
                password_line = password_command_parts[1].rstrip().lstrip()
                logger.info("Password line:" + password_line)

        logger.info("Deleting openrc file ")

        # Delete file
        if os.path.exists(folder + '/' + tmpFileName):
            os.remove(folder + '/' + tmpFileName)

        logger.info("Looking for password")
        # Get password
        password_cmd = []
        #cmd = 'TERM=linux /opt/platform/.keyring/20.06/.CREDENTIAL 2>/dev/null'
        cmd_to_run = ssh_prefix + " " + password_line
        logger.info(cmd_to_run)
        successful, value = self._run_command_get_output([cmd_to_run], host_password, logger)
        password_val = host_password
        #if successful:
        #    if value != '':
        #        password_val = value
        os_password = "OS_PASSWORD=" + password_val
        env_string = env_string + " " + os_password

        logger.info("Env string:" + env_string)
        return env_string

    def _run_command_get_all_lines(self, commands, host_password, logger, block=False, timeout=None):
        logger.info("Inside _run_command_get_all_lines")
        all_lines = []
        for command in commands:
            logger.info(" Executing.." + str(command))
            child = pexpect.spawn(command)
            child.timeout=timeout
            try:
                i = child.expect(['password: ','Connection refused\r\r\n'], timeout=timeout)
                if i == 0:
                    child.sendline(host_password)
                    all_lines = child.read()
                    all_lines = all_lines.rstrip().lstrip()
                    all_lines = all_lines.decode('utf-8').replace('\r\n', '\n')
                    logger.info(all_lines)
                if i == 1:
                    logger.info("Connection refused")
            except:
                logger.info(str(child))
        return all_lines 
    
    def _run_command_get_output(self, commands, host_password, logger, block=False, timeout=None):
        successful = False
        value_to_return = ''
        logger.info("Inside _run_command_get_output")
        for command in commands:
            logger.info(" Executing.." + str(command))
            child = pexpect.spawn(command)
            child.timeout=timeout
            try:
                child.expect(['password: '], timeout=timeout)
                child.sendline(host_password)
                all_lines = child.read()
                all_lines = all_lines.rstrip().lstrip()
                all_lines = all_lines.decode('utf-8').replace('\r\n', '\n')
                successful = True # Tentative
                for line in all_lines.split("\n"):
                    logger.info(line)
                    if value_to_return == '':
                        value_to_return = line.strip()
                    if re.search('error', line, re.IGNORECASE):
                        successful = False 
                    if re.search('unable', line, re.IGNORECASE):
                        successful = False 
            except:
                logger.info(str(child))
        logger.info("Status:" + str(successful) + " value_to_return:" + value_to_return)
        return successful, value_to_return 

    def _get_remote_region_oam_ip(self, cluster_name, logger):
        remoteclusterObj = Cluster.objects.filter(cluster_name=cluster_name)
        oam_ip = remoteclusterObj[0].oam_vip_address
        logger.info(" Remote region:" + cluster_name + " OAM IP:" + str(oam_ip))
        return oam_ip

    def _get_central_region_name(self, oam_vip_address, logger):
        logger.info("1")
        remoteclusterObj = Cluster.objects.filter(oam_vip_address=oam_vip_address)
        logger.info("2")
        logger.info(remoteclusterObj)
        cluster_name = remoteclusterObj[0].cluster_name
        logger.info(" Remote region:" + str(oam_vip_address) + " Cluster Name:" + str(cluster_name))
        return cluster_name

    def _get_namespace(self, region, logger):
        # Lookup database and findout namespace given region
        logger.info(" Inside _get_namespace")
        remoteclusterObj = Cluster.objects.filter(cluster_name=region)
        if len(remoteclusterObj) > 0:
            logger.info(" RemoteClusterObj:" + str(remoteclusterObj))
            namespace_id = remoteclusterObj[0].namespace_id
            logger.info(" Namespace id:" + str(namespace_id))
            namespaceObj = Namespace.objects.filter(id=namespace_id)
            logger.info(" NamespaceObj:" + str(namespaceObj))
            namespace_name = namespaceObj[0].namespace_name
            logger.info(" Remote region:" + region + " Namespace:" + namespace_name)
            return namespace_name
        else:
            return ""

    def _get_central_region_oam_ip(self, remoteregion, transaction_id):
        remoteclusterObj = Cluster.objects.filter(cluster_name=remoteregion)
        parent_cluster_id = remoteclusterObj[0].parent_cluster_id
        self.logger.info(str(transaction_id) + " Parent cluster id.." + str(parent_cluster_id))
        centralclusterObj = Cluster.objects.filter(id=parent_cluster_id)
        self.logger.info(str(transaction_id) + " " + str(centralclusterObj))
        central_region_list = []
        for central_region in centralclusterObj:
            central_region_list.append(central_region.oam_vip_address)
        self.logger.info(str(transaction_id) + " Central Region List:" + ','.join(central_region_list))
        return central_region_list

    def get_fuze_spm_site_details(self, cluster_name, logger):
        fuze_spm_site_name = ''
        fuze_spm_site_id = ''
        logger.info(" Inside _get_fuze_spm_site_name " + str(cluster_name))
        remoteclusterObj = Cluster.objects.filter(cluster_name=cluster_name)
        if len(remoteclusterObj) > 0:
            fuze_id = remoteclusterObj[0].location_id
            locationObj = Location.objects.filter(id=fuze_id)
            if len(locationObj) > 0:
                fuze_spm_site_name = locationObj[0].fuze_spm_site_name
                fuze_spm_site_id = locationObj[0].fuze_spm_site_id
        logger.info(" Fuze site name:" + fuze_spm_site_name)
        logger.info(" Fuze site id:" + fuze_spm_site_id)
        return fuze_spm_site_name, fuze_spm_site_id 

    def check_namespaces(self, remote_region_oam_ip, logger):

        host_username, host_password, ssh_prefix = get_host_connection_details(remote_region_oam_ip)
        cmds = []
        cmds.append(ssh_prefix + " kubectl get namespaces --kubeconfig=/etc/kubernetes/admin.conf ")

        output_lines = self._run_command_get_all_lines(cmds, host_password, logger, block=True)
        #logger.info("Returned output lines:")
        #logger.info(output_lines)

        new_op_lines = []
        for line in output_lines.split("\n"):
            if not 'Connection to' in line:
                new_op_lines.append(line)

        return new_op_lines

    def check_namespace_secrets(self, region, remote_region_oam_ip, logger):
        namespace = self._get_namespace(region, logger)
        host_username, host_password, ssh_prefix = get_host_connection_details(remote_region_oam_ip)
        cmds = []
        cmds.append(ssh_prefix + " kubectl get secrets --kubeconfig=/etc/kubernetes/admin.conf -n " + namespace)

        output_lines = self._run_command_get_all_lines(cmds, host_password, logger, block=True)
        #logger.info("Returned output lines:")
        #logger.info(output_lines)

        new_op_lines = []
        for line in output_lines.split("\n"):
            if not 'Connection to' in line:
                new_op_lines.append(line)

        return new_op_lines

    def check_namespace_serviceaccounts(self, region, remote_region_oam_ip, logger):
        namespace = self._get_namespace(region, logger)
        host_username, host_password, ssh_prefix = get_host_connection_details(remote_region_oam_ip)
        cmds = []
        cmds.append(ssh_prefix + " kubectl get serviceaccounts --kubeconfig=/etc/kubernetes/admin.conf -n " + namespace)

        output_lines = self._run_command_get_all_lines(cmds, host_password, logger, block=True)
        #logger.info("Returned output lines:")
        #logger.info(output_lines)

        new_op_lines = []
        for line in output_lines.split("\n"):
            if not 'Connection to' in line:
                new_op_lines.append(line)

        return new_op_lines

    def check_online_status(self, region, remote_region_oam_ip, logger):
        host_username, host_password, ssh_prefix = get_host_connection_details(remote_region_oam_ip)
        central_region_list = self._get_central_region_oam_ip(region, "-1")
        region_online_status = []
        new_op_lines = []
        for central_region_ip in central_region_list:
            cmds = []
            cmd = 'ssh -o StrictHostKeyChecking=no -t ' + host_username + '@' + central_region_ip + ' ' + '"source /etc/platform/openrc; dcmanager subcloud list | grep ' + region + '"'
            cmds.append(cmd)
            output_lines = self._run_command_get_all_lines(cmds, host_password, logger, block=True)
            logger.info(output_lines)

            for line in output_lines.split("\n"):
                if not 'Connection to' in line:
                    new_op_lines.append(line)
        return new_op_lines

    def create_host_network(self, remote_region_oam_ip, logger):
        logger.info("Inside _create_host_network")

        #host_username = settings.HOST_CREDS['username']
        #host_password = settings.HOST_CREDS['password']
        #ssh_prefix = 'ssh -o StrictHostKeyChecking=no -t ' + host_username + '@' + remote_region_oam_ip

        host_username, host_password, ssh_prefix = get_host_connection_details(remote_region_oam_ip)

        env_string = self._read_remote_openrc(remote_region_oam_ip, logger)

        #basecmd = " OS_ENDPOINT_TYPE=internalURL CINDER_ENDPOINT_TYPE=internalURL OS_USERNAME=admin"
        #basecmd = basecmd + " OS_PASSWORD=`TERM=linux /opt/platform/.keyring/20.06/.CREDENTIAL 2>/dev/null`"
        #basecmd = basecmd + " OS_AUTH_TYPE=password OS_AUTH_URL=http://[fd00:4888:2000:120b::220]:5000/v3"
        #basecmd = basecmd + " OS_PROJECT_NAME=admin OS_USER_DOMAIN_NAME=Default OS_PROJECT_DOMAIN_NAME=Default"
        #basecmd = basecmd + " OS_IDENTITY_API_VERSION=3 OS_REGION_NAME=subcloud2 OS_INTERFACE=internal"

        basecmd = env_string

        cmds = ["system host-lock controller-0",
                "system host-if-modify -n f1u -c pci-sriov --num-vfs 8 controller-0 ens3f1 --vf-driver=vfio",
                "system host-if-add -c pci-sriov controller-0 f1c vf f1u --num-vfs 4 --vf-driver=netdevice",
                "system host-if-modify controller-0 f1u --imtu=1956",
                "system host-if-modify controller-0 f1c --imtu=1956",
                "system datanetwork-add f1u vlan --mtu=1956",
                "system datanetwork-add f1c vlan --mtu=1956",
                "system interface-datanetwork-assign controller-0 f1u f1u",
                "system interface-datanetwork-assign controller-0 f1c f1c",
                "system host-if-add -c pci-sriov controller-0 fh0m vf fh0 --num-vfs 4 --vf-driver=netdevice",
                "system host-if-modify controller-0 fh0m --imtu=9000",
                "system datanetwork-add fh0m flat",
                "system interface-datanetwork-assign controller-0  fh0m fh0m",
                "system host-if-modify -n fh1 -c pci-sriov --num-vfs 8 controller-0 enp181s0f0 --vf-driver=vfio",
                "system host-if-modify controller-0 fh1 --imtu=9000",
                "system datanetwork-add fh1 vlan --mtu=9000",
                "system interface-datanetwork-assign controller-0 fh1 fh1"]

        # New steps proposed by Eddy - These do not seem to create fh0m so commenting out.
        #cmds = ["system host-lock controller-0",
        #        "system host-if-modify -n f1c -c pci-sriov --num-vfs 8 controller-0 ens3f1 --vf-driver=netdevice",
        #        "system host-if-add -c pci-sriov controller-0 f1u vf f1c --num-vfs 4 --vf-driver=vfio",
        #        "system host-if-modify controller-0 f1u --imtu=1956",
        #        "system host-if-modify controller-0 f1c --imtu=1956",
        #        "system datanetwork-add f1u vlan --mtu=1956",
        #        "system datanetwork-add f1c vlan --mtu=1956",
        #        "system interface-datanetwork-assign controller-0 f1u f1u",
        #        "system interface-datanetwork-assign controller-0 f1c f1c",
        #         # this one is wrong as well but for some reason I think the fh0 is setup in Carlos deployment config.  So we have to delete the fh0 and recreate both.
        #        "system host-if-modify controller0 fh0 -nc none"
        #        "system host-if-modify -n fh0m -c pci-sriov --num-vfs 8 controller-0 ens179s0f0 --vf-driver=netdevice",
        #        "system host-if-add -c pci-sriov controller-0 fh0 vf fh0m --num-vfs 4 --vf-driver=vfio",
        #        "system host-if-modify controller-0 fh0m --imtu=9000",
        #        "system datanetwork-add fh0m flat",
        #        "system interface-datanetwork-assign controller-0  fh0m fh0m",
        #        "system host-if-modify -n fh1 -c pci-sriov --num-vfs 8 controller-0 enp181s0f0 --vf-driver=vfio",
        #        "system host-if-modify controller-0 fh1 --imtu=9000",
        #        "system datanetwork-add fh1 vlan --mtu=9000",
        #        "system interface-datanetwork-assign controller-0 fh1 fh1"]

        for cmd in cmds:
            cmd_to_run = ssh_prefix + " " + basecmd + " "  + cmd
            logger.info(cmd_to_run)
            run_commands([cmd_to_run], host_password, logger, block=True)

#        host_network_configured = False
#        while not host_network_configured:
#            host_network_configured = self._verify_host_network(ssh_prefix, basecmd, host_password, logger)
#            if not host_network_configured:
#                cmds = ["system host-lock controller-0"]
#                for cmd in cmds:
#                    cmd_to_run = ssh_prefix + " " + basecmd + " " + cmd
#                    logger.info(cmd_to_run)
#                    output_lines = self._run_command_get_all_lines([cmd_to_run], host_password, logger, block=True)
#                    logger.info("Returned output lines:")
#                    logger.info(output_lines)
#                time.sleep(3)

        cmds = ["system host-unlock controller-0"]
        while True:
            unlock_wait = False
            for cmd in cmds:
                cmd_to_run = ssh_prefix + " " + basecmd + " " + cmd
                logger.info(cmd_to_run)
                output_lines = self._run_command_get_all_lines([cmd_to_run], host_password, logger, block=True)
                logger.info("Returned output lines:")
                logger.info(output_lines)
                if len(output_lines) > 0:
                    for line in output_lines.split("\n"):
                        logger.info("Line:" + line)
                        if not unlock_wait:
                            if 'retry host-unlock' in line or 'Rejected' in line:
                                logger.info("Need to wait to call host-unlock ##### ")
                                unlock_wait = True 
                                break
            if unlock_wait: 
                time.sleep(60)
            else:
                break

#        for cmd in cmds:
#            cmd_to_run = ssh_prefix + " " + basecmd + " " + cmd
#            logger.info(cmd_to_run)
#            output_lines = self._run_command_get_all_lines([cmd_to_run], host_password, logger, block=True)
#            logger.info("Returned output lines:")
#            logger.info(output_lines)
        logger.info("Done setting up host network")