1    	#!@PYTHON@ -tt
2    	# -*- coding: utf-8 -*-
3    	
4    	import sys
5    	import atexit
6    	sys.path.append("@FENCEAGENTSLIBDIR@")
7    	from fencing import *
8    	from fencing import fail, EC_STATUS, EC_LOGIN_DENIED, EC_INVALID_PRIVILEGES, run_delay
9    	import requests
10   	import ast
11   	import urllib3
12   	import json
13   	import logging
14   	
15   	from requests.exceptions import ConnectionError
16   	
17   	
18   	###################################################################################
19   	# Inner functions
20   	
21   	
22   	def authorize_and_get_cookie(skala_ip, login, password, options):
23   	    URL0 = proto + str(skala_ip) + '/api/0/auth'
24   	    cred = {
25   	        "login" : str(login),
26   	        "password" : str(password)
27   	    }
28   	    
29   	    try:
30   	        with requests.Session() as session:
31   	            session.post(url=URL0, data=cred, verify=ssl_verify)
32   	            cookie = session.cookies.get_dict()
33   	    except:
34   	        logging.exception('Exception occured.')
35   	        fail(EC_LOGIN_DENIED)
36   	    if 'api_token' in cookie:
37   	        return cookie
38   	    else:
39   	        fail(EC_LOGIN_DENIED)
40   	
41   	
42   	def logout(skala_ip):
43   	    URL1 = proto + str(skala_ip) + '/api/0/logout'
44   	    
45   	    try:
46   	        with requests.Session() as session:
(1) Event Sigma main event: The `timeout` attribute is undefined or is set to `None`, which disables the timeouts on streaming connections. This makes it easier for an attacker to launch a Denial-of-Service (DoS) attack. Other problems can include large numbers of inactive connections that aren't being closed and running out of ephemeral ports.
(2) Event remediation: Explicitly set the `timeout` attribute to a value greater than 0.
47   	            session.post(url=URL1, verify=ssl_verify, cookies=cookie)
48   	    except:
49   	        ## Logout; we do not care about result as we will end in any case
50   	        pass
51   	
52   	
53   	def get_vm_id(skala_ip, uuid, options, cookie):
54   	    URL2 = proto + str(skala_ip) + '/api/0/vm'
55   	    parameters = {
56   	        "uuid": str(uuid)
57   	    }
58   	    
59   	    vm_info = requests.get(url=URL2, verify=ssl_verify, params=parameters, cookies=cookie)
60   	    jvm_info = vm_info.json()
61   	    if jvm_info["vm_list"]["items"] == []:
62   	        raise NameError('Can not find VM by uuid.')
63   	    logging.debug("VM_INFO:\n{}".format(json.dumps(vm_info.json(), indent=4, sort_keys=True)))
64   	    return jvm_info["vm_list"]["items"][0]["vm_id"]
65   	
66   	
67   	def vm_task(skala_ip, vm_id, command, options, cookie):
68   	
69   	    # command(str) – Command for vm: ‘vm_start’, ‘vm_stop’, ‘vm_restart’,
70   	    # ‘vm_suspend’, ‘vm_resume’, ‘vm_pause’, ‘vm_reset’
71   	    # main_request_id(TaskId) – Parent task id
72   	    # graceful(bool) – vm_stop command parameter, graceful or not, default
73   	    # false - *args[0]
74   	    # force(bool) – vm_stop command parameter, force stop or not, default
75   	    # false - *args[1]
76   	    
77   	    if "--graceful" in options:
78   	        graceful = True
79   	    else:
80   	        graceful = False
81   	    if "--force" in options:
82   	        force = True
83   	    else:
84   	        force = False
85   	
86   	    URL3 = proto + str(skala_ip) + '/api/0/vm/' + str(vm_id) + '/task'
87   	
88   	    logging.debug("vm_task skala_ip: " + str(skala_ip))
89   	    logging.debug("vm_task vm_id: " + str(vm_id))
90   	    logging.debug("vm_task command: " + str(command))
91   	    logging.debug("vm_task cookie: " + str(cookie))
92   	
93   	
94   	    def checking(vm_id, command, graceful, force):
95   	        firstcondition = type(vm_id) is int
96   	        secondcondition = command in ['vm_start', 'vm_stop', 'vm_restart', 'vm_suspend', 'vm_resume', 'vm_pause', 'vm_reset']
97   	        thirdcondition = type(graceful) is bool
98   	        fourthcondition = type(force) is bool
99   	        return firstcondition * secondcondition * thirdcondition * fourthcondition
100  	
101  	    if not checking(vm_id, command, graceful, force):
102  	        print('Wrong parameters! \n'
103  	              'command(str) – Command for vm: ‘vm_start’, ‘vm_stop’, \n'
104  	              '‘vm_restart’,‘vm_suspend’, ‘vm_resume’, ‘vm_pause’, ‘vm_reset’ \n'
105  	              'graceful(bool) – vm_stop command parameter, graceful or not, default false \n'
106  	              'force(bool) – vm_stop command parameter, force stop or not, default false \n'
107  	              )
108  	    else:
109  	        parameters = {
110  	            "command": command,
111  	            "graceful": graceful,
112  	            "force": force
113  	        }
114  	
115  	    with requests.Session() as session:
116  	        response = session.post(url=URL3, params=parameters, verify=ssl_verify, cookies=cookie)
117  	    if response.status_code != 200:
118  	        raise Exception('Invalid response code from server: {}.'.format(response.status_code))
119  	    return
120  	
121  	######################################################################################
122  	
123  	def get_power_status(conn, options):
124  	    state = {"RUNNING": "on", "PAUSED": "on", "STOPPED": "off", "SUSPENDED": "off", "ERROR": "off", "DELETED": "off",
125  	             "CREATING": "off", "FAILED_TO_CREATE": "off", "NODE_OFFLINE": "off", "STARTING": "off", "STOPPING": "on"}
126  	
127  	    URL4 = proto + options["--ip"] + '/api/0/vm/'
128  	    parameters = {
129  	        "uuid": str(options["--plug"])
130  	    }
131  	
132  	    vm_info = requests.get(url=URL4, params=parameters, verify=ssl_verify, cookies=cookie)
133  	    jvm_info = vm_info.json()
134  	    if jvm_info["vm_list"]["items"] == []:
135  	        raise NameError('Can not find VM by uuid.')
136  	    logging.debug("VM_INFO:\n{}".format(json.dumps(vm_info.json(), indent=4, sort_keys=True)))
137  	    status_v = jvm_info["vm_list"]["items"][0]["status"]
138  	    if status_v not in state:
139  	        raise Exception('Unknown VM state: {}.'.format(status_v))
140  	    return state[status_v]
141  	
142  	
143  	def set_power_status(conn, options):
144  	    action = {
145  	        "on" : "vm_start",
146  	        "reboot": "vm_restart",
147  	        "off" : "vm_stop"
148  	        }
149  	
150  	    vm_id_v = get_vm_id(options["--ip"], options["--plug"], options, cookie)
151  	    vm_task(options["--ip"], vm_id_v, action[options["--action"]], options, cookie)
152  	    return
153  	
154  	
155  	def get_list(conn, options):
156  	    outlets = {}
157  	    URL5 = proto + options["--ip"] + '/api/0/vm'
158  	    
159  	    vm_info = requests.get(url=URL5, verify=ssl_verify, cookies=cookie)
160  	    jvm_info = vm_info.json()
161  	    list_jvm = jvm_info["vm_list"]["items"]
162  	    for elem in list_jvm:
163  	        outlets[elem["name"]] = (elem["uuid"], None)
164  	    return outlets
165  	
166  	
167  	def define_new_opts():
168  	    all_opt["graceful"] = {
169  	            "getopt" : "",
170  	            "longopt" : "graceful",
171  	            "help" : "--graceful                     vm_stop command parameter, graceful stop or not, default false", 
172  	            "required" : "0",
173  	            "shortdesc" : "vm_stop command parameter, graceful stop or not, default false",
174  	            "order" : 1}
175  	
176  	    all_opt["force"] = {
177  	            "getopt" : "",
178  	            "longopt" : "force",
179  	            "help" : "--force                        vm_stop command parameter, force stop or not, default false",
180  	            "required" : "0",
181  	            "shortdesc" : "vm_stop command parameter, force stop or not, default false", 
182  	            "order" : 1}
183  	
184  	
185  	def main():
186  	    global cookie, proto, ssl_verify
187  	    define_new_opts()
188  	    device_opt = ["ipaddr", "login", "passwd", "port", "web", "ssl", "verbose", "graceful", "force"]
189  	    
190  	    atexit.register(atexit_handler)
191  	    options = check_input(device_opt, process_input(device_opt))
192  	
193  	    docs = {}
194  	    docs["shortdesc"] = "Skala-R Fence agent"
195  	    docs["longdesc"] = "fence_skalar is a Power Fencing agent for Skala-R."
196  	    docs["vendorurl"] = "https://www.skala-r.ru/"
197  	    show_docs(options, docs)
198  	    options["eol"] = "\r"
199  	    
200  	    run_delay(options)
201  	    
202  	    proto = "https://"
203  	    if "--ssl-secure" in options:
204  	        ssl_verify = True
205  	    elif "--ssl-insecure" in options:
206  	        ssl_verify = False
207  	        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
208  	    else:
209  	        proto = "http://"
210  	        ssl_verify = False
211  	        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
212  	
213  	    cookie = authorize_and_get_cookie(options["--ip"], options["--username"], options["--password"], options)
214  	    atexit.register(logout, options["--ip"])
215  	    
216  	    logging.debug("OPTIONS: " + str(options) + "\n")
217  	    
218  	    try:
219  	        result = fence_action(None, options, set_power_status, get_power_status, get_list)
220  	        sys.exit(result)
221  	    except Exception:
222  	        logging.exception('Exception occured.')
223  	        fail(EC_STATUS)
224  	
225  	if __name__ == "__main__":
226  	    main()
227