summaryrefslogtreecommitdiffstats
path: root/vstf/vstf/common/saltstack.py
blob: efc953c43e5e9ac8bb360eb7a3e53281b04471d9 (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
#!/usr/bin/env python
# coding=utf-8
import os
import sys
import inspect
import logging
import salt.client as sclient

from vstf.common import cmds

log = logging.getLogger(__name__)


class Mysalt(object):
    IS_DIR = 1
    IS_FILE = 2
    FAILED = -1

    def __init__(self):
        self.cur_path = os.path.abspath(os.path.dirname(inspect.stack()[1][1]))
        self.salt_conf = "/etc/salt/master"
        if not os.path.exists(self.salt_conf):
            raise Exception("this python must be run on the salt master.")
        self.pillar_path = str(
            cmds.execute("grep '^pillar_roots' \
                    /etc/salt/master -A 2 | sed 1,2d | awk '{print $2}'") + '/')
        if self.pillar_path == "":
            log.warning("pillar path not found, make sure the pillar_roots configed")
        else:
            os.system("mkdir -p " + self.pillar_path)

        self.state_path = str(cmds.execute("grep '^file_roots' \
            /etc/salt/master -A 2 | sed 1,2d | awk '{print $2}'") + '/')
        if self.state_path == "":
            log.warning("state path not found, make sure the file_roots configed")
        else:
            os.system("mkdir -p " + self.state_path)

        self.salt = sclient.LocalClient()

    def slave_exists(self, host):
        pslave = "/etc/salt/pki/master/minions/" + host
        if os.path.exists(pslave):
            return True
        else:
            return False

    def __is_dir_or_file(self, src):
        if not os.path.exists(src):
            return self.FAILED
        if os.path.isdir(src):
            return self.IS_DIR
        elif os.path.isfile(src):
            return self.IS_FILE
        else:
            return self.FAILED

    def __copy_target(self, target, flag=""):
        if not os.path.exists(target):
            log.error("target %(d)s  not exists.", {'d': target})
            return False

        if flag == "pillar":
            dst = self.pillar_path
        elif flag == "state":
            dst = self.state_path
        else:
            log.error("this file or dir not pillar or state, can not support now.")
            return False

        if self.IS_FILE == self.__is_dir_or_file(target):
            os.system('cp ' + target + ' ' + dst)
        else:
            os.system("cp -r " + target + ' ' + dst)
        return True

    def copy(self, host, src, dst):
        """copy file or dir to slave.
        :src a file or a dir
        :dst if src is a file, the dst must be like this /home/xx.py, not /home
        """

        '''check if the host exists on the master'''
        if not self.slave_exists(host):
            log.error("the host %(h)s is not held by master, please check.")
            return False

        '''copy file to salt's file_roots'''
        if not self.__copy_target(src, "state"):
            return False

        if self.IS_DIR == self.__is_dir_or_file(src):
            dir_name = os.path.basename(src)
            self.salt.cmd(host, "cp.get_dir", ["salt://" + dir_name, dst])
        elif self.IS_FILE == self.__is_dir_or_file(src):
            file_name = os.path.basename(src)
            print self.salt.cmd(host, "cp.get_file", ["salt://" + file_name, dst])
        else:
            log.error("not file and not dir, what is it")
            return False
        return True

    def __luxuriant_line(self, str, color):
        if "red" == color:
            return "\033[22;35;40m" + str + "\033[0m"
        elif "green" == color:
            return "\033[22;32;40m" + str + "\033[0m"
        else:
            return str

    def result_check(self, ret, host):
        num_s = 0
        num_f = 0
        msg = ""
        try:
            for key in ret[host].keys():
                if True == ret[host][key]['result']:
                    num_s += 1
                else:
                    num_f += 1
                    msg = msg + self.__luxuriant_line("Failed %d:\n" % num_f, "red")
                    msg = msg + "\t" + key + '\n'
                    msg = msg + self.__luxuriant_line("\t%s\n" % ret[host][key]['comment'], "red")
                    if True == ret[host][key]['changes'].has_key('retcode'):
                        msg = msg + "RETCODE: %s\n" % (ret[host][key]['changes']['retcode'])
                    if True == ret[host][key]['changes'].has_key('stderr'):
                        msg = msg + "STDERR: %s\n" % (ret[host][key]['changes']['stderr'])
                    if True == ret[host][key]['changes'].has_key('stdout'):
                        msg = msg + "STDOUT: %s\n" % (ret[host][key]['changes']['stdout'])
            msg = msg + self.__luxuriant_line("total success: %d\n" % num_s, "green")
            msg = msg + self.__luxuriant_line("failed: %d\n" % num_f, "red")
        except Exception as e:
            log.error("sorry, thy to check result happend error, <%(e)s>.\nret:%(ret)s",
                      {'e': e, 'ret': ret})
            return -1
        log.info(':\n' + msg)
        return num_f

    def run_state(self, host, fstate, ext_pillar={}, care_result=True):
        try:
            log.info("salt " + host + " state.sls " +
                     fstate + ' pillar=\'' + str(ext_pillar) + '\'')
            ret = self.salt.cmd(host, 'state.sls', [fstate, 'pillar=' + str(ext_pillar)], 180, 'list')
        except Exception as e:
            log.error("try to init host %(host)s happend error: <%(e)s>.",
                      {'host': host, 'e': e})
            if True == care_result:
                raise e

        if 0 != self.result_check(ret, host) and care_result:
            sys.exit(-1)
        return True

    def salt_cmd(self, host, cmd):
        # import pdb
        # pdb.set_trace()
        logging.info("Begin to run cmd %s on %s" % (host, cmd))

        try:
            ret = self.salt.cmd(host, 'cmd.run', [cmd])
        except Exception:
            log.error("Remote salt execute failed.")
        return ret

    def copy_by_state(self, host, src, state_cmd, **kwargs):
        '''the src must be a dir, and the state.sls 
        must be the name of the dir name'''

        if not self.slave_exists(host):
            log.error("the host %(h)s is not held by master, please check.")
            return False

        if not self.__copy_target(src, "state"):
            return False

        return self.run_state(host, state_cmd, kwargs, care_result=True)

    def get_master_ip(self, host=None):
        if not host:
            ret = cmds.execute("grep '^interface:' /etc/salt/master | awk '{print $2}'").strip()
            return ret
        try:
            ret = self.salt.cmd(host, "grains.item", ["master"])[host]['master']
        except Exception:
            log.error("salt happened error when get master ip")
            return ""
        return ret


mysalt = Mysalt()