Example #1
0
 def encrypt(self, data, cluster_name=None, secret=None, encode=True):
     """
     Encrypt and return data in a wrapping structure.
     """
     if cluster_name is None:
         cluster_name = self.cluster_name
     if secret is None:
         cluster_key = self.cluster_key
     else:
         cluster_key = secret
     if cluster_key is None:
         return
     iv = self.gen_iv()
     try:
         data = json.dumps(data).encode()
     except (UnicodeDecodeError, TypeError):
         # already binary data
         pass
     message = {
         "clustername": cluster_name,
         "nodename": Env.nodename,
         "iv": bdecode(base64.urlsafe_b64encode(iv)),
         "data": bdecode(
             base64.urlsafe_b64encode(
                 self._encrypt(data, cluster_key, iv)
             )
         ),
     }
     if encode:
         return (json.dumps(message)+'\0').encode()
     return json.dumps(message)
Example #2
0
 def _fullpem(self):
     required = set(["private_key", "certificate_chain"])
     if required & set(self.data_keys()) != required:
         self.gen_cert()
     buff = bdecode(self.decode_key("private_key"))
     buff += bdecode(self.decode_key("certificate_chain"))
     return buff
Example #3
0
 def get_secret(self, sp, secret):
     if want_context():
         return
     if sp.context and not sp.context.get("secret"):
         return
     elif secret:
         return bdecode(secret)
     elif sp.server in self.cluster_drpnodes:
         node = self.get_node()
         return bdecode(self.prepare_key(node.oget("cluster", "secret", impersonate=sp.server)))
     else:
         return bdecode(self.cluster_key)
Example #4
0
 def action(self, nodename, thr=None, **kwargs):
     options = self.parse_options(kwargs)
     if not options.data and not options.template:
         return {"status": 0, "info": "no data"}
     if options.template is not None:
         if options.path:
             paths = [options.path]
             cmd = [
                 "create", "-s", options.path,
                 "--template=%s" % options.template, "--env=-"
             ]
         else:
             paths = [p for p in options.data]
             cmd = ["create", "--template=%s" % options.template, "--env=-"]
     else:
         paths = [p for p in options.data]
         cmd = ["create", "--config=-"]
     validate_paths(paths)
     if options.namespace:
         cmd.append("--namespace=" + options.namespace)
     if options.restore:
         cmd.append("--restore")
     thr.log_request("create/update %s" % ",".join(paths), nodename,
                     **kwargs)
     proc = thr.service_command(None,
                                cmd,
                                stdout=PIPE,
                                stderr=PIPE,
                                stdin=json.dumps(options.data))
     if options.sync:
         out, err = proc.communicate()
         result = {
             "status": proc.returncode,
             "data": {
                 "out": bdecode(out),
                 "err": bdecode(err),
                 "ret": proc.returncode,
             },
         }
     else:
         thr.push_proc(proc)
         result = {
             "status": 0,
             "info": "started %s action %s" % (options.path, " ".join(cmd)),
         }
     if options.provision:
         for path in paths:
             thr.set_smon(path, global_expect="provisioned")
     return result
Example #5
0
 def check_io():
     logged = 0
     rlist, _, xlist = select.select([rout, rerr], [], [],
                                     LCALL_CHECK_IO_TIMEOUT)
     if xlist:
         return logged
     for io in rlist:
         buff = os.read(io, 32768)
         buff = bdecode(buff)
         if six.PY2:
             buff = buff.decode("utf8")
         if buff in ('', b''):
             continue
         buff = pending[io] + buff
         while True:
             l = buff.split("\n", 1)
             if len(l) == 1:
                 pending[io] = l[0]
                 break
             line, buff = l
             if logger:
                 logger.log(log_level[io], "| " + line)
             elif log_level[io] < logging.ERROR:
                 print(line)
             else:
                 print(line, file=sys.stderr)
             logged += 1
     return logged
Example #6
0
 def h2_daemon_request(self, data, server=None, node=None, with_result=True, silent=False,
                       cluster_name=None, secret=None, timeout=None, sp=None, method="GET"):
     secret = self.get_secret(sp, secret)
     path = self.h2_path_from_data(data)
     headers = self.h2_headers(node=node, secret=secret, multiplexed=data.get("multiplexed"), af=sp.af)
     body = self.h2_body_from_data(data)
     headers.update({"Content-Length": str(len(body))})
     conn = self.h2c(sp=sp, timeout=timeout)
     elapsed = 0
     while True:
         try:
             conn.request(method, path, headers=headers, body=body)
             break
         except AssertionError as exc:
             raise ex.Error(str(exc))
         except ConnectionResetError:
             return {"status": 1, "error": "%s %s connection reset"%(method, path)}
         except (ConnectionRefusedError, ssl.SSLError, socket.error) as exc:
             try:
                 errno = exc.errno
             except AttributeError:
                 errno = None
             if errno in RETRYABLE and \
                (timeout == 0 or elapsed < timeout):
                 # Resource temporarily unavailable (busy, overflow)
                 # Retry after a delay, if the daemon is still
                 # running and timeout is not exhausted
                 time.sleep(PAUSE)
                 elapsed += PAUSE
                 continue
             return {"status": 1, "error": "%s"%exc, "errno": errno}
     resp = conn.get_response()
     data = resp.read()
     data = json.loads(bdecode(data))
     return data
Example #7
0
 def post(self, uri, data=None):
     api = self.api+uri+"/"
     headers = {'Content-Type': 'application/json'}
     if data:
         data = json.dumps(data)
     r = requests.post(api, data=data, auth=self.auth, timeout=self.timeout, verify=VERIFY, headers=headers)
     return bdecode(r.content)
Example #8
0
 def read_slot(self, slot, fo=None):
     offset = self.slot_offset(slot)
     fo.seek(offset, os.SEEK_SET)
     fo.readinto(self.slot_buff)
     data = bdecode(self.slot_buff[:])
     end = data.index("\0")
     return data[:end]
Example #9
0
def _zone_list(zone, nameserver):
    request = {
        "method": "list",
        "parameters": {
            "zonename": zone,
        }
    }
    try:
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        sock.connect(Env.paths.dnsuxsock)
        sock.send(bencode(json.dumps(request) + "\n"))
        response = ""
        while True:
            buff = sock.recv(4096)
            if not buff:
                break
            response += bdecode(buff)
            if response[-1] == "\n":
                break
    finally:
        sock.close()
    if not response:
        return
    try:
        return json.loads(response)["result"]
    except ValueError:
        raise ex.Error("invalid response format")
Example #10
0
 def _add_key(self, key, data):
     if not key:
         raise ex.Error("configuration key name can not be empty")
     if data is None:
         raise ex.Error("configuration value can not be empty")
     if not is_string(data):
         data = "base64:" + bdecode(base64.urlsafe_b64encode(data))
     elif "\n" in data:
         data = "base64:" + bdecode(base64.urlsafe_b64encode(bencode(data)))
     else:
         data = "literal:" + data
     self.set_multi(["data.%s=%s" % (key, data)])
     self.log.info("configuration key '%s' added (%s)", key,
                   print_size(len(data), compact=True, unit="b"))
     # refresh if in use
     self.postinstall(key)
Example #11
0
 def meta_read_slot(self, slot, fo=None):
     offset = self.meta_slot_offset(slot)
     fo.seek(offset, os.SEEK_SET)
     fo.readinto(self.meta_slot_buff)
     try:
         return bdecode(self.meta_slot_buff[:mmap.PAGESIZE])
     except Exception as exc:
         return None
Example #12
0
def is_container():
    p = '/proc/1/environ'
    if not os.path.exists(p):
        return False
    with open(p, 'r') as f:
        buff = f.read()
    if "container=lxc" in bdecode(buff):
        return True
    return False
Example #13
0
 def _pkcs12(self, password):
     required = set(["private_key", "certificate_chain"])
     if required & set(self.data_keys()) != required:
         self.gen_cert()
     from subprocess import Popen, PIPE
     import tempfile
     _tmpcert = tempfile.NamedTemporaryFile()
     _tmpkey = tempfile.NamedTemporaryFile()
     tmpcert = _tmpcert.name
     tmpkey = _tmpkey.name
     _tmpcert.close()
     _tmpkey.close()
     if password is None:
         from getpass import getpass
         pwd = getpass("Password: "******"\n"
     elif password in ["/dev/stdin", "-"]:
         pwd = sys.stdin.readline()
     else:
         pwd = password + "\n"
     if six.PY3:
         pwd = bencode(pwd)
     try:
         with open(tmpkey, "w") as _tmpkey:
             os.chmod(tmpkey, 0o600)
             _tmpkey.write(bdecode(self.decode_key("private_key")))
         with open(tmpcert, "w") as _tmpcert:
             os.chmod(tmpcert, 0o600)
             _tmpcert.write(bdecode(self.decode_key("certificate_chain")))
         cmd = [
             "openssl", "pkcs12", "-export", "-in", tmpcert, "-inkey",
             tmpkey, "-passout", "stdin"
         ]
         proc = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
         out, err = proc.communicate(input=pwd)
         if err:
             print(err, file=sys.stderr)
         return out
     finally:
         if os.path.exists(tmpcert):
             os.unlink(tmpcert)
         if os.path.exists(tmpkey):
             os.unlink(tmpkey)
Example #14
0
 def post2(self, uri, data=None):
     api = self.api.replace("api/v1.0", "")+uri
     s = requests.Session()
     r = s.get(api)
     csrf_token = r.cookies['csrftoken']
     data["csrfmiddlewaretoken"] = csrf_token
     if data:
         data = json.dumps(data)
     r = requests.post(api, data=data, auth=self.auth, timeout=self.timeout, verify=VERIFY)
     return bdecode(r.content)
Example #15
0
 def h2_daemon_stream_fetch(self, stream_id, conn):
     resps = []
     for push in conn.get_pushes(stream_id):
         resps.append(push.get_response())
     for resp in resps:
         # resp.read() can modify push.promises_headers, which get_pushes iterates
         # causing a RuntimeError => keep in a separate loop
         evt = resp.read()
         evt = json.loads(bdecode(evt))
         yield evt
Example #16
0
 def do_it(self, send_cmd, receive_cmd, node):
     self.log.info(' '.join(send_cmd + ["|"] + receive_cmd))
     p1 = Popen(send_cmd, stdout=PIPE)
     pi = Popen(["dd", "bs=4096"],
                stdin=p1.stdout,
                stdout=PIPE,
                stderr=PIPE)
     p2 = Popen(receive_cmd, stdin=pi.stdout, stdout=PIPE, stderr=PIPE)
     buff = p2.communicate()
     if p2.returncode == 0:
         stats_buff = pi.communicate()[1]
         stats = self.parse_dd(stats_buff)
         self.update_stats(stats, target=node)
     out = bdecode(buff[0])
     err = bdecode(buff[1])
     if p2.returncode != 0:
         if err is not None and len(err) > 0:
             self.log.error(err)
         raise ex.Error("sync failed")
     if out is not None and len(out) > 0:
         self.log.info(out)
Example #17
0
 def parse_dd(self, buff):
     """
     Extract normalized speed and transfered data size from the dd output
     """
     data = {}
     if not buff:
         return data
     words = bdecode(buff).split()
     if "bytes" in words:
         data["bytes"] = int(words[words.index("bytes") - 1])
     if words[-1].endswith("/s"):
         data["speed"] = int(convert_speed("".join(words[-2:])))
     return data
Example #18
0
def justcall(argv=None, stdin=None, input=None):
    """
    Call subprocess' Popen(argv, stdout=PIPE, stderr=PIPE, stdin=stdin)
    The 'close_fds' value is autodectected (true on unix, false on windows).
    Returns (stdout, stderr, returncode)
    """
    if argv is None:
        argv = [Env.syspaths.false]
    if input:
        stdin = PIPE
        input = bencode(input)
    try:
        proc = Popen(argv,
                     stdin=stdin,
                     stdout=PIPE,
                     stderr=PIPE,
                     close_fds=close_fds)
        out, err = proc.communicate(input=input)
        return bdecode(out), bdecode(err), proc.returncode
    except OSError as exc:
        if exc.errno in (ENOENT, EACCES):
            return "", "", 1
        raise
Example #19
0
    def _handle_client(self, conn, cr, cw):
        chunks = []
        buff_size = 4096
        while True:
            try:
                data = cr.readline()
            except socket.timeout as exc:
                break
            except socket.error as exc:
                self.log.info("%s", exc)
                break
            if len(data) == 0:
                #self.log.info("no more data")
                break

            self.log.debug("received %s", data)

            try:
                data = bdecode(data)
                data = json.loads(data)
            except Exception as exc:
                self.log.error(exc)
                data = None

            if self.stopped():
                self.log.info("stop event received (handler thread)")
                break

            if data is None or not isinstance(data, dict):
                continue

            try:
                result = self.router(data)
            except Exception as exc:
                self.log.error("dns request: %s => handler error: %s", data,
                               exc)
                return {"error": "unexpected backend error", "result": False}
            if result is not None:
                message = json.dumps(result) + "\n"
                try:
                    cw.write(message)
                    cw.flush()
                except socket.error as exc:
                    if exc.errno != errno.EPIPE:
                        raise
                    self.log.info("client died (broken pipe)")
                    break
                self.log.debug("replied %s", message)
                message_len = len(message)
                self.stats.sessions.tx += message_len
Example #20
0
 def action(self, nodename, thr=None, stream_id=None, **kwargs):
     logfile = os.path.join(Env.paths.pathlog, "node.log")
     ofile = thr._action_logs_open(logfile, 0, "node")
     request_headers = HTTPHeaderMap(
         thr.streams[stream_id]["request"].headers)
     try:
         content_type = bdecode(request_headers.get("accept").pop())
     except:
         content_type = "application/json"
     thr.streams[stream_id]["content_type"] = content_type
     thr.streams[stream_id]["pushers"].append({
         "o": self,
         "fn": "h2_push_logs",
         "args": [ofile, True],
     })
Example #21
0
 def get(self, uri, params=None, timeout=None):
     timeout = timeout or self.timeout
     ep = self.api + uri + "/"
     try:
         r = requests.get(ep,
                          params=params,
                          auth=self.auth,
                          timeout=timeout,
                          verify=VERIFY)
     except Exception as exc:
         raise ex.Error("GET %s %s => %s" % (ep, params, exc))
     content = bdecode(r.content)
     if r.status_code != 200:
         raise ex.Error("GET %s %s => %d: %s" %
                        (ep, params, r.status_code, content))
     return content
Example #22
0
 def action(self, nodename, thr=None, **kwargs):
     options = self.parse_options(kwargs)
     try:
         return {
             "status":
             0,
             "data":
             bdecode(shared.SERVICES[options.path].decode_key(options.key))
         }
     except ex.Error as exc:
         return {"status": 1, "error": str(exc)}
     except Exception as exc:
         return {
             "status": 1,
             "error": str(exc),
             "traceback": traceback.format_exc()
         }
Example #23
0
 def action(self, nodename, thr=None, stream_id=None, **kwargs):
     options = self.parse_options(kwargs)
     thr.selector = options.selector
     if not thr.event_queue:
         thr.event_queue = queue.Queue()
     if options.full:
         data = thr.daemon_status()
         namespaces = thr.get_namespaces()
         fevent = {
             "nodename":
             Env.nodename,
             "ts":
             time.time(),
             "kind":
             "full",
             "data":
             thr.filter_daemon_status(data,
                                      namespaces=namespaces,
                                      selector=options.selector),
         }
         if thr.h2conn:
             _msg = fevent
         elif thr.encrypted:
             _msg = thr.encrypt(fevent)
         else:
             _msg = thr.msg_encode(fevent)
         thr.event_queue.put(_msg)
     if not thr in thr.parent.events_clients:
         thr.parent.events_clients.append(thr)
     if not stream_id in thr.events_stream_ids:
         thr.events_stream_ids.append(stream_id)
     if thr.h2conn:
         request_headers = HTTPHeaderMap(
             thr.streams[stream_id]["request"].headers)
         try:
             content_type = bdecode(request_headers.get("accept").pop())
         except:
             content_type = "application/json"
         thr.streams[stream_id]["content_type"] = content_type
         thr.streams[stream_id]["pushers"].append({
             "fn":
             "h2_push_action_events",
         })
     else:
         thr.raw_push_action_events()
Example #24
0
 def get_src_dir_dev(self, dev):
     """Given a directory path, return its hosting device
     """
     if dev in self.src_dir_devs_cache:
         return self.src_dir_devs_cache[dev]
     p = Popen(self.df_one_cmd + [dev],
               stdout=PIPE,
               stderr=STDOUT,
               close_fds=True)
     out, err = p.communicate()
     if p.returncode != 0:
         return
     out = bdecode(out).lstrip()
     lines = out.splitlines()
     if len(lines) == 2:
         out = lines[1]
     self.src_dir_devs_cache[dev] = out.split()[0]
     return self.src_dir_devs_cache[dev]
Example #25
0
 def action(self, nodename, thr=None, stream_id=None, **kwargs):
     options = self.parse_options(kwargs)
     svc = thr.get_service(options.path)
     if svc is None:
         raise ex.HTTP(404, "%s not found" % options.path)
     request_headers = HTTPHeaderMap(
         thr.streams[stream_id]["request"].headers)
     try:
         content_type = bdecode(request_headers.get("accept").pop())
     except:
         content_type = "application/json"
     thr.streams[stream_id]["content_type"] = content_type
     logfile = os.path.join(svc.log_d, svc.name + ".log")
     ofile = thr._action_logs_open(logfile, 0, svc.path)
     thr.streams[stream_id]["pushers"].append({
         "o": self,
         "fn": "h2_push_logs",
         "args": [ofile, True],
     })
Example #26
0
 def post(self, uri, data=None, timeout=None):
     timeout = timeout or self.timeout
     ep = self.api + uri + "/"
     headers = {'Content-Type': 'application/json'}
     if data:
         data = json.dumps(data)
     try:
         r = requests.post(ep,
                           data=data,
                           auth=self.auth,
                           timeout=timeout,
                           verify=VERIFY,
                           headers=headers)
     except Exception as exc:
         raise ex.Error("POST %s %s => %s" % (ep, data, exc))
     content = bdecode(r.content)
     if r.status_code != 200:
         raise ex.Error("POST %s %s => %d: %s" %
                        (ep, data, r.status_code, content))
     return content
Example #27
0
 def cni_cmd(self, _env, data):
     cmd = [self.cni_bin(data)]
     if not which(cmd[0]):
         raise ex.Error("%s not found" % cmd[0])
     self.log_cmd(_env, data, cmd)
     env = {}
     env.update(Env.initial_env)
     env.update(_env)
     proc = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
     out, err = proc.communicate(input=bencode(json.dumps(data)))
     out = bdecode(out)
     try:
         data = json.loads(out)
     except ValueError:
         if proc.returncode == 0:
             # for example a del portmap outs nothing
             return
         raise ex.Error(err)
     if "code" in data:
         raise ex.Error(data.get("msg", ""))
     for line in format_str_flat_json(data).splitlines():
         self.log.info(line)
     return data
Example #28
0
    def action(self, nodename, thr=None, **kwargs):
        options = self.parse_options(kwargs)
        name, namespace, kind = split_path(options.path)

        if thr.get_service(options.path) is None and options.action not in ("create", "deploy"):
            thr.log_request("service action (%s not installed)" % options.path, nodename, lvl="warning", **kwargs)
            raise ex.HTTP(404, "%s not found" % options.path)
        if not options.action and not options.cmd:
            thr.log_request("service action (no action set)", nodename, lvl="error", **kwargs)
            raise ex.HTTP(400, "action not set")

        for opt in ("node", "daemon", "svcs", "service", "s", "parm_svcs", "local", "id"):
            if opt in options.options:
                del options.options[opt]
        for opt, ropt in (("jsonpath_filter", "filter"),):
            if opt in options.options:
                options.options[ropt] = options.options[opt]
                del options.options[opt]
        options.options["local"] = True
        pmod = importlib.import_module("commands.{kind}.parser".format(kind=kind))
        popt = pmod.OPT

        def find_opt(opt):
            for k, o in popt.items():
                if o.dest == opt:
                    return o
                if o.dest == "parm_" + opt:
                    return o

        if options.cmd:
            cmd = [options.cmd]
        else:
            cmd = [options.action]
            for opt, val in options.options.items():
                po = find_opt(opt)
                if po is None:
                    continue
                if val == po.default:
                    continue
                if val is None:
                    continue
                opt = po._long_opts[0] if po._long_opts else po._short_opts[0]
                if po.action == "append":
                    cmd += [opt + "=" + str(v) for v in val]
                elif po.action == "store_true" and val:
                    cmd.append(opt)
                elif po.action == "store_false" and not val:
                    cmd.append(opt)
                elif po.type == "string":
                    opt += "=" + val
                    cmd.append(opt)
                elif po.type == "integer":
                    opt += "=" + str(val)
                    cmd.append(opt)

        fullcmd = Env.om + ["svc", "-s", options.path] + cmd
        thr.log_request("run 'om %s %s'" % (options.path, " ".join(cmd)), nodename, **kwargs)
        if options.sync:
            proc = Popen(fullcmd, stdout=PIPE, stderr=PIPE, stdin=None, close_fds=True)
            out, err = proc.communicate()
            try:
                result = json.loads(out)
            except Exception:
                result = {
                    "status": 0,
                    "data": {
                        "out": bdecode(out),
                        "err": bdecode(err),
                        "ret": proc.returncode,
                    },
                }
        else:
            import uuid
            session_id = str(uuid.uuid4())
            env = {}
            env.update(os.environ)
            env["OSVC_PARENT_SESSION_UUID"] = session_id
            proc = Popen(fullcmd, stdin=None, close_fds=True, env=env)
            thr.push_proc(proc)
            result = {
                "status": 0,
                "data": {
                    "pid": proc.pid,
                    "session_id": session_id,
                },
                "info": "started %s action %s" % (options.path, " ".join(cmd)),
            }
        return result
Example #29
0
 def decrypt(self, message, cluster_name=None, secret=None, sender_id=None, structured=True):
     """
     Validate the message meta, decrypt and return the data.
     """
     if cluster_name is None:
         cluster_names = self.cluster_names
     else:
         cluster_names = [cluster_name]
     message = bdecode(message).rstrip("\0\x00")
     try:
         message = json.loads(message)
     except ValueError:
         message_len = len(message)
         if message_len > 40:
             self.log.error("misformatted encrypted message from %s: %s",
                            sender_id, message[:30]+"..."+message[-10:])
         elif message_len > 0:
             self.log.error("misformatted encrypted message from %s",
                            sender_id)
         return None, None, None
     msg_clustername = message.get("clustername")
     msg_nodename = message.get("nodename")
     if secret is None:
         if msg_nodename in self.cluster_drpnodes:
             cluster_key = self.get_secret(Storage(server=msg_nodename), None)
         else:
             cluster_key = self.cluster_key
     else:
         cluster_key = secret
     if cluster_name != "join" and \
        msg_clustername not in set(["join"]) | self.cluster_names:
         self.log.warning("discard message from cluster %s, sender %s",
                          msg_clustername, sender_id)
         return None, None, None
     if cluster_key is None:
         return None, None, None
     if msg_nodename is None:
         return None, None, None
     iv = message.get("iv")
     if iv is None:
         return None, None, None
     if self.blacklisted(sender_id):
         return None, None, None
     iv = base64.urlsafe_b64decode(to_bytes(iv))
     data = base64.urlsafe_b64decode(to_bytes(message["data"]))
     try:
         data = self._decrypt(data, cluster_key, iv)
     except Exception as exc:
         self.log.error("decrypt message from %s: %s", msg_nodename, str(exc))
         self.blacklist(sender_id)
         return None, None, None
     if sender_id:
         self.blacklist_clear(sender_id)
     if not structured:
         try:
             loaded = json.loads(bdecode(data))
         except ValueError as exc:
             loaded = data
         if not isinstance(loaded, foreign.six.text_type):
             loaded = data
         return msg_clustername, msg_nodename, loaded
     try:
         return msg_clustername, msg_nodename, json.loads(bdecode(data))
     except ValueError as exc:
         return msg_clustername, msg_nodename, data
Example #30
0
 def msg_decode(self, message):
     message = bdecode(message).rstrip("\0\x00")
     if len(message) == 0:
         return
     return json.loads(message)