|
| 1 | +#!@PYTHON@ -tt |
| 2 | + |
| 3 | +import sys |
| 4 | +import pycurl, io, json |
| 5 | +import logging |
| 6 | +import atexit |
| 7 | +sys.path.append("@FENCEAGENTSLIBDIR@") |
| 8 | +from fencing import * |
| 9 | +from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS |
| 10 | + |
| 11 | +state = { |
| 12 | + "ACTIVE": "on", |
| 13 | + "SHUTOFF": "off", |
| 14 | + "ERROR": "unknown" |
| 15 | +} |
| 16 | + |
| 17 | +def get_list(conn, options): |
| 18 | + outlets = {} |
| 19 | + |
| 20 | + try: |
| 21 | + command = "cloud-instances/{}/pvm-instances".format(options["--instance"]) |
| 22 | + res = send_command(conn, command) |
| 23 | + except Exception as e: |
| 24 | + logging.debug("Failed: {}".format(e)) |
| 25 | + return outlets |
| 26 | + |
| 27 | + for r in res["pvmInstances"]: |
| 28 | + if "--verbose" in options: |
| 29 | + logging.debug(json.dumps(r, indent=2)) |
| 30 | + outlets[r["pvmInstanceID"]] = (r["serverName"], state[r["status"]]) |
| 31 | + |
| 32 | + return outlets |
| 33 | + |
| 34 | +def get_power_status(conn, options): |
| 35 | + try: |
| 36 | + command = "cloud-instances/{}/pvm-instances/{}".format( |
| 37 | + options["--instance"], options["--plug"]) |
| 38 | + res = send_command(conn, command) |
| 39 | + result = get_list(conn, options)[options["--plug"]][1] |
| 40 | + except KeyError as e: |
| 41 | + logging.debug("Failed: Unable to get status for {}".format(e)) |
| 42 | + fail(EC_STATUS) |
| 43 | + |
| 44 | + return result |
| 45 | + |
| 46 | +def set_power_status(conn, options): |
| 47 | + action = { |
| 48 | + "on" : '{"action" : "start"}', |
| 49 | + "off" : '{"action" : "immediate-shutdown"}', |
| 50 | + }[options["--action"]] |
| 51 | + |
| 52 | + try: |
| 53 | + send_command(conn, "cloud-instances/{}/pvm-instances/{}/action".format( |
| 54 | + options["--instance"], options["--plug"]), "POST", action) |
| 55 | + except Exception as e: |
| 56 | + logging.debug("Failed: Unable to set power to {} for {}".format(options["--action"], e)) |
| 57 | + fail(EC_STATUS) |
| 58 | + |
| 59 | +def connect(opt): |
| 60 | + conn = pycurl.Curl() |
| 61 | + |
| 62 | + ## setup correct URL |
| 63 | + conn.base_url = "https://" + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" |
| 64 | + |
| 65 | + if opt["--verbose-level"] > 1: |
| 66 | + conn.setopt(pycurl.VERBOSE, 1) |
| 67 | + |
| 68 | + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) |
| 69 | + conn.setopt(pycurl.SSL_VERIFYPEER, 1) |
| 70 | + conn.setopt(pycurl.SSL_VERIFYHOST, 2) |
| 71 | + |
| 72 | + # set auth token for later requests |
| 73 | + conn.setopt(pycurl.HTTPHEADER, [ |
| 74 | + "Content-Type: application/json", |
| 75 | + "Authorization: Bearer {}".format(opt["--token"]), |
| 76 | + "CRN: {}".format(opt["--crn"]), |
| 77 | + "User-Agent: curl", |
| 78 | + ]) |
| 79 | + |
| 80 | + return conn |
| 81 | + |
| 82 | +def disconnect(conn): |
| 83 | + conn.close() |
| 84 | + |
| 85 | +def send_command(conn, command, method="GET", action=None): |
| 86 | + url = conn.base_url + command |
| 87 | + |
| 88 | + conn.setopt(pycurl.URL, url.encode("ascii")) |
| 89 | + |
| 90 | + web_buffer = io.BytesIO() |
| 91 | + |
| 92 | + if method == "GET": |
| 93 | + conn.setopt(pycurl.POST, 0) |
| 94 | + if method == "POST": |
| 95 | + conn.setopt(pycurl.POSTFIELDS, action) |
| 96 | + if method == "DELETE": |
| 97 | + conn.setopt(pycurl.CUSTOMREQUEST, "DELETE") |
| 98 | + |
| 99 | + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) |
| 100 | + |
| 101 | + try: |
| 102 | + conn.perform() |
| 103 | + except Exception as e: |
| 104 | + raise(e) |
| 105 | + |
| 106 | + rc = conn.getinfo(pycurl.HTTP_CODE) |
| 107 | + result = web_buffer.getvalue().decode("UTF-8") |
| 108 | + |
| 109 | + web_buffer.close() |
| 110 | + |
| 111 | + if rc != 200: |
| 112 | + if len(result) > 0: |
| 113 | + raise Exception("{}: {}".format(rc, |
| 114 | + result["value"]["messages"][0]["default_message"])) |
| 115 | + else: |
| 116 | + raise Exception("Remote returned {} for request to {}".format(rc, url)) |
| 117 | + |
| 118 | + if len(result) > 0: |
| 119 | + result = json.loads(result) |
| 120 | + |
| 121 | + logging.debug("url: {}".format(url)) |
| 122 | + logging.debug("method: {}".format(method)) |
| 123 | + logging.debug("response code: {}".format(rc)) |
| 124 | + logging.debug("result: {}\n".format(result)) |
| 125 | + |
| 126 | + return result |
| 127 | + |
| 128 | +def define_new_opts(): |
| 129 | + all_opt["token"] = { |
| 130 | + "getopt" : ":", |
| 131 | + "longopt" : "token", |
| 132 | + "help" : "--token=[token] Bearer Token", |
| 133 | + "required" : "1", |
| 134 | + "shortdesc" : "Bearer Token", |
| 135 | + "order" : 0 |
| 136 | + } |
| 137 | + all_opt["crn"] = { |
| 138 | + "getopt" : ":", |
| 139 | + "longopt" : "crn", |
| 140 | + "help" : "--crn=[crn] CRN", |
| 141 | + "required" : "1", |
| 142 | + "shortdesc" : "CRN", |
| 143 | + "order" : 0 |
| 144 | + } |
| 145 | + all_opt["instance"] = { |
| 146 | + "getopt" : ":", |
| 147 | + "longopt" : "instance", |
| 148 | + "help" : "--instance=[instance] PowerVS Instance", |
| 149 | + "required" : "1", |
| 150 | + "shortdesc" : "PowerVS Instance", |
| 151 | + "order" : 0 |
| 152 | + } |
| 153 | + all_opt["region"] = { |
| 154 | + "getopt" : ":", |
| 155 | + "longopt" : "region", |
| 156 | + "help" : "--region=[region] Region", |
| 157 | + "required" : "1", |
| 158 | + "shortdesc" : "Region", |
| 159 | + "order" : 0 |
| 160 | + } |
| 161 | + |
| 162 | + |
| 163 | +def main(): |
| 164 | + device_opt = [ |
| 165 | + "token", |
| 166 | + "crn", |
| 167 | + "instance", |
| 168 | + "region", |
| 169 | + "port", |
| 170 | + "no_password", |
| 171 | + ] |
| 172 | + |
| 173 | + atexit.register(atexit_handler) |
| 174 | + define_new_opts() |
| 175 | + |
| 176 | + all_opt["shell_timeout"]["default"] = "15" |
| 177 | + all_opt["power_timeout"]["default"] = "30" |
| 178 | + all_opt["power_wait"]["default"] = "1" |
| 179 | + |
| 180 | + options = check_input(device_opt, process_input(device_opt)) |
| 181 | + |
| 182 | + docs = {} |
| 183 | + docs["shortdesc"] = "Fence agent for IBM PowerVS" |
| 184 | + docs["longdesc"] = """fence_ibm_powervs is an I/O Fencing agent which can be \ |
| 185 | +used with IBM PowerVS to fence virtual machines.""" |
| 186 | + docs["vendorurl"] = "https://www.ibm.com" |
| 187 | + show_docs(options, docs) |
| 188 | + |
| 189 | + #### |
| 190 | + ## Fence operations |
| 191 | + #### |
| 192 | + run_delay(options) |
| 193 | + |
| 194 | + conn = connect(options) |
| 195 | + atexit.register(disconnect, conn) |
| 196 | + |
| 197 | + result = fence_action(conn, options, set_power_status, get_power_status, get_list) |
| 198 | + |
| 199 | + sys.exit(result) |
| 200 | + |
| 201 | +if __name__ == "__main__": |
| 202 | + main() |
0 commit comments