~tyler-baker/lava-lab/latest-lit

« back to all changes in this revision

Viewing changes to scripts/lava_salt.py

  • Committer: Andy Doan
  • Date: 2013-02-08 04:41:31 UTC
  • mto: This revision was merged to the branch mainline in revision 68.
  • Revision ID: andy.doan@linaro.org-20130208044131-92ukqd5s542qqbrp
add some lava scripts to help manage lab

lava-status - shows the nodes contributing to a lava deployment, if
they are running, and which is the master instance

lava-{start/stop} - start/stop each lava-instance contributing to a lava deployment

lava-upgrade - performs an upgrade for a lava-deployment

lava-addworker - add support for installing a remote worker instance

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import salt.client
 
2
 
 
3
RUNNING = 0
 
4
STOPPED = 1
 
5
UNKNOWN = 3
 
6
 
 
7
STATE_STRING = {
 
8
    RUNNING: 'running',
 
9
    STOPPED: 'stopped',
 
10
    UNKNOWN: '???',
 
11
}
 
12
 
 
13
LDT = '/home/instance-manager/lava-deployment-tool/lava-deployment-tool'
 
14
 
 
15
 
 
16
def salt_client():
 
17
    return salt.client.LocalClient()
 
18
 
 
19
 
 
20
def info(client, instance):
 
21
    """
 
22
    Shows whether an instance of LAVA is running or not on its configured hosts.
 
23
    """
 
24
    cmd = 'status lava-instance LAVA_INSTANCE={0}'.format(instance)
 
25
    inst_path = '/srv/lava/instances/{0}'.format(instance)
 
26
    worker_file = '{0}/sbin/mount-masterfs'.format(inst_path)
 
27
 
 
28
    inf = {}
 
29
 
 
30
    ret = client.cmd('*', 'lava.list_instances', [])
 
31
    for k, v in ret.iteritems():
 
32
        if inst_path in v:
 
33
            ret = client.cmd(k, 'cmd.run', [cmd])
 
34
            running = UNKNOWN
 
35
            if ret[k] == 'status: Unknown instance: %s' % instance:
 
36
                running = STOPPED
 
37
            elif ret[k] == 'lava-instance (%s) start/running' % instance:
 
38
                running = RUNNING
 
39
 
 
40
            ret = client.cmd(k, 'file.file_exists', [worker_file])
 
41
            master = not ret[k]
 
42
 
 
43
            inf[k] = {'running': running, 'master': master}
 
44
    return inf
 
45
 
 
46
 
 
47
def stop(client, instance, just_workers=False):
 
48
    """
 
49
    Issues a command to stop a given instance name on all minions where the
 
50
    LAVA instance appears to be running.
 
51
    """
 
52
    cmd = 'stop lava-instance LAVA_INSTANCE={0}'.format(instance)
 
53
 
 
54
    hosts = []
 
55
    for host, props in info(client, instance).iteritems():
 
56
        if props['running'] != STOPPED:
 
57
            if not just_workers or not props['master']:
 
58
                hosts.append(host)
 
59
 
 
60
    if len(hosts):
 
61
        return client.cmd(hosts, 'cmd.run', [cmd], expr_form='list')
 
62
 
 
63
 
 
64
def start(client, instance):
 
65
    """
 
66
    Issues a command to start a given instance name on all minions where the
 
67
    LAVA instance appears to not be running.
 
68
    """
 
69
    cmd = 'start lava-instance LAVA_INSTANCE={0}'.format(instance)
 
70
 
 
71
    hosts = []
 
72
    for host, props in info(client, instance).iteritems():
 
73
        if props['running'] != RUNNING:
 
74
            hosts.append(host)
 
75
 
 
76
    if len(hosts):
 
77
        return client.cmd(hosts, 'cmd.run', [cmd], expr_form='list')
 
78
 
 
79
 
 
80
def upgrade(client, instance, dry_run=True):
 
81
    """
 
82
    Runs lava-deployment-tool upgrade for a LAVA setup. It first shuts down
 
83
    each worker node instance. Then it runs lava-deployment-tool upgrade on
 
84
    the master. Lastly, it runs lava-deployment-tool upgradeworker on the
 
85
    worker nodes.
 
86
    """
 
87
    timeout = 300  # 5 minutes
 
88
    workers = []
 
89
    master = None
 
90
 
 
91
    for host, props in info(client, instance).iteritems():
 
92
        if props['master']:
 
93
            assert not master, 'Detected multiple master instances in LAVA deployment'
 
94
            master = host
 
95
        else:
 
96
            workers.append(host)
 
97
 
 
98
    assert master, 'No master instance found in LAVA deployment'
 
99
 
 
100
    w_ret = {}
 
101
    for h in workers:
 
102
        w_ret[h] = {'stop': 'dry-run', 'upgrade': 'dry-run', 'start': 'dry-run'}
 
103
 
 
104
    if dry_run:
 
105
        m_ret = {master: 'dry-run: upgrade master'}
 
106
        return m_ret, w_ret
 
107
 
 
108
    # first stop workers. This prevents a DB error if the upgrade changes
 
109
    # the schema.
 
110
    ret = stop(client, instance, True)
 
111
    if ret:
 
112
        for host, msg in ret.iteritems():
 
113
            w_ret[host]['stop'] = msg
 
114
 
 
115
    # now upgrade the master node
 
116
    cmd = 'SKIP_ROOT_CHECK=yes {0} upgrade {1}'.format(LDT, instance)
 
117
    m_ret = client.cmd(master, 'cmd.run', [cmd], timeout=timeout)
 
118
 
 
119
    # now upgrade the workers
 
120
    cmd = 'SKIP_ROOT_CHECK=yes {0} upgradeworker {1}'.format(LDT, instance)
 
121
    if len(workers):
 
122
        ret = client.cmd(workers, 'cmd.run', [cmd], timeout=timeout, expr_form='list')
 
123
        for host, msg in ret.iteritems():
 
124
            w_ret[host]['upgrade'] = msg
 
125
 
 
126
    ret = start(client, instance)
 
127
    if ret:
 
128
        for host, msg in ret.iteritems():
 
129
            if host in w_ret:
 
130
                w_ret[host]['start'] = msg
 
131
 
 
132
    # last thing: l-d-t ran as root, lets chmod things
 
133
    cmd = 'chown -R instance-manager:instance-manager /srv/lava/instances/{0}/code/*'.format(instance)
 
134
    client.cmd(workers + [master], 'cmd.run', [cmd], expr_form='list')
 
135
 
 
136
    return m_ret, w_ret
 
137
 
 
138
 
 
139
def _update_props(inifile_content, props):
 
140
    for line in inifile_content.split('\n'):
 
141
        if not line.strip().startswith('#'):
 
142
            key, val = line.split('=')
 
143
            if key in props:
 
144
                props[key] = val.replace("'", '')
 
145
 
 
146
 
 
147
def add_worker(client, minion, minion_ip, instance, dry_run=True):
 
148
    """
 
149
    Creates a new lava workernode on a salt-minion.
 
150
    """
 
151
 
 
152
    args = {
 
153
        'LAVA_SERVER_IP': None,
 
154
        'LAVA_SYS_USER': None,
 
155
        'LAVA_PROXY': None,
 
156
        'masterdir': '/srv/lava/instances/{0}'.format(instance),
 
157
        'workerip': minion_ip,
 
158
        'ldt': LDT,
 
159
        'instance': instance,
 
160
        'dbuser': None,
 
161
        'dbpass': None,
 
162
        'dbname': None,
 
163
        'dbserver': None,
 
164
    }
 
165
 
 
166
    # ensure the instance exists and isn't already installed on the minion
 
167
    master = None
 
168
    for host, props in info(client, instance).iteritems():
 
169
        if props['master']:
 
170
            assert not master, 'Detected multiple master instances in LAVA deployment'
 
171
            master = host
 
172
        assert minion != host, 'LAVA instance already deployed on minion'
 
173
 
 
174
    assert master, 'No master instance found in LAVA deployment'
 
175
 
 
176
    # determine settings needed by looking at master instance
 
177
    cmd = 'cat {0}/instance.conf'.format(args['masterdir'])
 
178
    ret = client.cmd(master, 'cmd.run', [cmd])
 
179
    _update_props(ret[master], args)
 
180
 
 
181
    # get the db information
 
182
    cmd = 'cat {0}/etc/lava-server/default_database.conf'.format(args['masterdir'])
 
183
    ret = client.cmd(master, 'cmd.run', [cmd])
 
184
    _update_props(ret[master], args)
 
185
    if not args['dbserver']:
 
186
        args['dbserver'] = args['LAVA_SERVER_IP']
 
187
 
 
188
    cmd = ('SKIP_ROOT_CHECK=yes '
 
189
           'LAVA_DB_SERVER={dbserver} LAVA_DB_NAME={dbname} '
 
190
           'LAVA_DB_USER={dbuser} LAVA_DB_PASSWORD={dbpass} '
 
191
           'LAVA_REMOTE_FS_HOST={LAVA_SERVER_IP} '
 
192
           'LAVA_REMOTE_FS_USER={LAVA_SYS_USER} LAVA_REMOTE_FS_DIR={masterdir} '
 
193
           'LAVA_PROXY="{LAVA_PROXY}" LAVA_SERVER_IP={workerip} '
 
194
           '{ldt} installworker -n {instance} 2>&1 | tee /tmp/ldt.log'.format(**args))
 
195
 
 
196
    if dry_run:
 
197
        return {minion: 'dry-run: {0}'.format(cmd)}
 
198
 
 
199
    ret = client.cmd(minion, 'cmd.run', [cmd], timeout=600)
 
200
 
 
201
    # l-d-t ran as root, lets chmod things
 
202
    cmd = 'chown -R instance-manager:instance-manager /srv/lava/instances/{0}/code/*'.format(instance)
 
203
    client.cmd(minion, 'cmd.run', [cmd])
 
204
 
 
205
    # now add the pubkey of the minion to the master's list of authorized keys
 
206
    cmd = 'cat /srv/lava/instances/{0}/home/.ssh/id_rsa.pub'.format(instance)
 
207
    pubkey = client.cmd(minion, 'cmd.run', [cmd])
 
208
    pubkey = pubkey[minion].replace('ssh key used by LAVA for sshfs', minion)
 
209
    authorized_keys = '{0}/home/.ssh/authorized_keys'.format(args['masterdir'])
 
210
    client.cmd(master, 'file.append', [authorized_keys, pubkey])
 
211
 
 
212
    return ret