summaryrefslogtreecommitdiff
path: root/extensions/distbuild-trove-nfsboot.check
blob: 780d5e0a0deb8d4d7c6ecbb1e4601be62be82bd9 (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
#!/usr/bin/python
# Copyright (C) 2014-2015  Codethink Limited
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

'''Preparatory checks for Morph 'distbuild-trove-nfsboot' write extension'''

import logging
import os
import sys

import writeexts


class DistbuildTroveNFSBootCheckExtension(writeexts.WriteExtension):

    nfsboot_root = '/srv/nfsboot'
    remote_user = 'root'

    required_vars = [
        'DISTBUILD_CONTROLLER',
        'DISTBUILD_GIT_SERVER',
        'DISTBUILD_SHARED_ARTIFACT_CACHE',
        'DISTBUILD_TROVE_ID',
        'DISTBUILD_WORKERS',
        'DISTBUILD_WORKER_SSH_KEY',
    ]

    def system_path(self, system_name, version_label=None):
        if version_label:
            return os.path.join(self.nfsboot_root, system_name, 'systems',
                                version_label, 'run')
        else:
            return os.path.join(self.nfsboot_root, system_name)

    def process_args(self, args):
        if len(args) != 1:
            raise writeexts.ExtensionError(
                'Wrong number of command line args')

        nfs_host = args[0]
        nfs_netloc = '%s@%s' % (self.remote_user, nfs_host)

        version_label = os.getenv('VERSION_LABEL', 'factory')

        missing_vars = [var for var in self.required_vars
                        if not var in os.environ]
        if missing_vars:
            raise writeexts.ExtensionError(
                'Please set: %s' % ', '.join(missing_vars))

        controllers = os.getenv('DISTBUILD_CONTROLLER').split()
        workers = os.getenv('DISTBUILD_WORKERS').split()

        if len(controllers) != 1:
            raise writeexts.ExtensionError(
                'Please specify exactly one controller.')

        if len(workers) == 0:
            raise writeexts.ExtensionError(
                'Please specify at least one worker.')

        upgrade = self.get_environment_boolean('UPGRADE')

        self.check_good_server(nfs_netloc)

        system_names = set(controllers + workers)
        for system_name in system_names:
            if upgrade:
                self.check_upgradeable(nfs_netloc, system_name, version_label)
            else:
                system_path = self.system_path(system_name)

                if self.remote_directory_exists(nfs_netloc, system_path):
                    if self.get_environment_boolean('OVERWRITE') == False:
                        raise writeexts.ExtensionError(
                            'System %s already exists at %s:%s. Try `morph '
                            'upgrade` instead of `morph deploy`.' % (
                            system_name, nfs_netloc, system_path))

    def check_good_server(self, netloc):
        # FIXME: assumes root
        self.check_ssh_connectivity(netloc.split('@')[-1])

        # Is an NFS server
        try:
            writeexts.ssh_runcmd(
                netloc, ['test', '-e', '/etc/exports'])
        except writeexts.ExtensionError:
            raise writeexts.ExtensionError('server %s is not an nfs server'
                                           % netloc)
        try:
            writeexts.ssh_runcmd(
                netloc, ['systemctl', 'is-enabled', 'nfs-server.service'])

        except writeexts.ExtensionError:
            raise writeexts.ExtensionError('server %s does not control its '
                                           'nfs server by systemd' % netloc)

        # TFTP server exports /srv/nfsboot/tftp
        tftp_root = os.path.join(self.nfsboot_root, 'tftp')
        try:
            writeexts.ssh_runcmd(
                netloc, ['test' , '-d', tftp_root])
        except writeexts.ExtensionError:
            raise writeexts.ExtensionError('server %s does not export %s' %
                                           (netloc, tftp_root))

    def check_upgradeable(self, nfs_netloc, system_name, version_label):
        '''Check that there is already a version of the system present.

        Distbuild nodes are stateless, so an upgrade is actually pretty much
        the same as an initial deployment. This test is just a sanity check.

        '''
        system_path = self.system_path(system_name)
        system_version_path = self.system_path(system_name, version_label)

        if not self.remote_directory_exists(nfs_netloc, system_path):
            raise writeexts.ExtensionError(
                'System %s not found at %s:%s, cannot deploy an upgrade.' % (
                system_name, nfs_netloc, system_path))

        if self.remote_directory_exists(nfs_netloc, system_version_path):
            if self.get_environment_boolean('OVERWRITE'):
                pass
            else:
                raise writeexts.ExtensionError(
                    'System %s version %s already exists at %s:%s.' % (
                    system_name, version_label, nfs_netloc,
                    system_version_path))

    def remote_directory_exists(self, nfs_netloc, path):
        try:
            writeexts.ssh_runcmd(nfs_netloc, ['test', '-d', path])
        except writeexts.ExtensionError as e:
            logging.debug('SSH exception: %s', e)
            return False

        return True


DistbuildTroveNFSBootCheckExtension().run()