示例#1
0
def ready():
    """
    When the StorPool block service has been installed and the OpenStack
    integration has been installed everywhere, set the unit's status to
    `active`.
    """
    rdebug('ready to go')
    ensure_our_presence()
    spstatus.set('active', 'so far so good so what')
def update_status():
    try:
        status = get_status()
        spstatus.set("active" if status["ready"] else "maintenance",
                     status["message"])
    except BaseException as e:
        s = "Querying the StorPool status: {e}".format(e=e)
        hookenv.log(s, hookenv.ERROR)
        spstatus.set("maintenance", s)
def sp_status():
    # Yes, removing it at once, not after the fact.  If something
    # goes wrong, the action may be reissued.
    reactive.remove_state("storpool-block-charm.sp-status")
    try:
        status = get_status()
        hookenv.action_set({"status": json.dumps(status)})
        spstatus.set("active" if status["ready"] else "maintenance",
                     status["message"])
    except BaseException as e:
        s = "Querying the StorPool status: {e}".format(e=e)
        hookenv.log(s, hookenv.ERROR)
        hookenv.action_fail(s)
def try_to_submit():
    """
    Once the data has been collected and `submit_url` is set, go ahead.
    """
    url = hookenv.config().get('submit_url', None)
    rdebug('trying to submit to {url}'.format(url=url))
    reactive.remove_state('storpool-inventory.submitting')

    if url is None:
        rdebug('erm, how did we get here with no submit URL?')
        return

    spstatus.npset('maintenance', 'submitting the collected data')
    try:
        global datafile
        rdebug('about to read {df}'.format(df=datafile))
        with open(datafile, mode='r', encoding='latin1') as f:
            contents = ''.join(f.readlines())
        rdebug('read {ln} characters of data from the collect file'.format(
            ln=len(contents)))
        data = json.dumps({'filename': platform.node(), 'contents': contents})
        rdebug('encoded stuff into {ln} characters of data to submit'.format(
            ln=len(data)))
        data_enc = data.encode('latin1')
        rdebug('submitting {ln} bytes of data to {url}'.format(
            ln=len(data_enc), url=url))
        with urllib.request.urlopen(url, data=data_enc) as resp:
            rdebug('got some kind of an HTTP response')
            code = resp.getcode()
            rdebug('got response code {code}'.format(code=code))
            if code is not None and code >= 200 and code < 300:
                rdebug('success!')
                reactive.set_state('storpool-inventory.submitted')
                spstatus.set('active', 'here, have a blob of data')
    except Exception as e:
        rdebug('could not submit the data: {e}'.format(e=e))
        sputils.err('failed to submit the collected data')
def get_status():
    inst = reactive.is_state("storpool-block-charm.services-started")
    status = {
        "node": sputils.get_machine_id(),
        "charm-config": dict(hookenv.config()),
        "storpool-conf": read_storpool_conf(),
        "installed": inst,
        "presence": service_hook.fetch_presence(RELATIONS),
        "lxd": unitdata.kv().get(kvdata.KEY_LXD_NAME),
        "ready": False,
    }

    for name in (
            "storpool_repo_url",
            "storpool_version",
            "storpool_openstack_version",
    ):
        value = status["charm-config"].get(name)
        if value is None or value == "":
            status["message"] = "No {name} in the config".format(name=name)
            return status
    if not inst:
        status["message"] = "Packages not installed yet"
        return status

    spstatus.set("maintenance", "checking the StorPool configuration")
    rdebug("about to try to obtain our StorPool ID")
    try:
        out = subprocess.check_output(["storpool_showconf", "-ne", "SP_OURID"])
        out = out.decode()
        out = out.split("\n")
        our_id = out[0]
    except Exception as e:
        status["message"] = "Could not obtain the StorPool ID: {e}".format(e=e)
        return status

    spstatus.set("maintenance", "checking the Cinder and Nova processes...")
    found = False
    status["proc"] = {}
    for cmd in ("cinder-volume", "nova-compute"):
        d = osi.check_spopenstack_processes(cmd)
        if d:
            found = True
        status["proc"][cmd] = d
        bad = sorted(filter(lambda pid: not d[pid], d.keys()))
        if bad:
            status["message"] = "No spopenstack group: {pid}".format(pid=bad)
            return status

    if found:
        spstatus.set("maintenance", "checking for the spool directory")
        dirname = pathlib.Path("/var/spool/openstack-storpool")
        if not dirname.is_dir():
            status["message"] = "No {d} directory".format(d=dirname)
            return status
        st = dirname.stat()
        if not st.st_mode & 0o0020:
            status["message"] = "{d} not group-writable".format(d=dirname)
            return status

    spstatus.set("maintenance", "checking the StorPool services...")
    svcs = ("storpool_beacon", "storpool_block")
    rdebug("checking for services: {svcs}".format(svcs=svcs))
    missing = list(filter(lambda s: not host.service_running(s), svcs))
    rdebug("missing: {missing}".format(missing=missing))
    if missing:
        status["message"] = "StorPool services not running: {missing}".format(
            missing=" ".join(missing))
        return status

    spstatus.set("maintenance", "querying the StorPool API")
    rdebug("checking the network status of the StorPool client")
    try:
        out = subprocess.check_output(["storpool", "-jB", "service", "list"])
        out = out.decode()
        data = json.loads(out)
        rdebug("got API response: {d}".format(d=data))
        if "error" in data:
            raise Exception(
                "API response: {d}".format(d=data["error"]["descr"]))
        state = data["data"]["clients"][our_id]["status"]
        rdebug("got our client status {st}".format(st=state))
        if state != "running":
            status["message"] = "StorPool client: {st}".format(st=state)
            return status
    except Exception as e:
        status["message"] = "Could not query the StorPool API: {e}".format(e=e)
        return status

    spstatus.set("maintenance", "querying the StorPool API for client status")
    rdebug("checking the status of the StorPool client")
    try:
        out = subprocess.check_output(["storpool", "-jB", "client", "status"])
        out = out.decode()
        data = json.loads(out)
        rdebug("got API response: {d}".format(d=data))
        if "error" in data:
            raise Exception(
                "API response: {d}".format(d=data["error"]["descr"]))
        int_id = int(our_id)
        found = list(filter(lambda e: e["id"] == int_id, data["data"]))
        if not found:
            raise Exception(
                "No client status reported for {our_id}".format(our_id=our_id))
        state = found[0]["configStatus"]
        status["message"] = "StorPool client: {st}".format(st=state)

        if state == "ok":
            status["ready"] = True
            rdebug("get_status: calling for Cinder LXD reconfiguration")
            reactive.set_state("storpool-block-charm.lxd")
        else:
            status["ready"] = False
        return status
    except Exception as e:
        status["message"] = "Could not query the StorPool API: {e}".format(e=e)
        return status
def err(msg):
    """
    Log an error message and set the unit's status.
    """
    hookenv.log(msg, hookenv.ERROR)
    spstatus.set("error", msg)