Skip to content
Permalink
Browse files

Merge branch 'master' of github.com:opensvc/opensvc

  • Loading branch information...
cvaroqui committed Aug 2, 2019
2 parents 3deefcb + 8cb3261 commit 3d17f539a586012d3504ff52e30f91f4b30ae95a
Showing with 224 additions and 16 deletions.
  1. +43 −0 bin/pkg/make.lib
  2. +4 −1 lib/extconfig.py
  3. +41 −0 lib/keywords.py
  4. +81 −0 lib/node.py
  5. +0 −7 lib/nodedict.py
  6. +7 −1 lib/nodemgr_parser.py
  7. +2 −2 lib/osvcd.py
  8. +27 −0 lib/osvcd_lsnr.py
  9. +2 −1 lib/osvcd_mon.py
  10. +3 −0 lib/osvcd_shared.py
  11. +12 −3 lib/rcUtilities.py
  12. +2 −1 usr/share/bash_completion.d/opensvc.sh
@@ -52,6 +52,45 @@ else
SUDO="sudo"
fi

function deploy_cluster_manager {

# need curl to be available
if ! [ -x "$(command -v curl)" ]; then
echo 'Warning: curl is not installed. skipping cluster manager installation' >&2
return
fi

# OSVC_CLUMGR_REPO can be set to use a custom repository
# OSVC_CURL_OPTS can be set to custom download parameters
CLUMGR_DIR="$CHROOT/opt/opensvc/usr/share/html"
API_VERSION=$(grep ^API_VERSION $CHROOT/opt/opensvc/lib/osvcd_shared.py | awk '{print $3}')
CLUMGR_REPO=${OSVC_CLUMGR_REPO:-https://repo.opensvc.com/cluster-manager}
CLUMGR_URL="${CLUMGR_REPO}/${API_VERSION}/latest"
CLUMGR_BUNDLE="$CHROOT/opt/opensvc/bundle.tar.gz"

echo $CLUMGR_REPO | grep -qw "^https"
ret=$?
if [ $ret -eq 0 ]; then
CURL_OPTS=${OSVC_CURL_OPTS:--k -s}
else
CURL_OPTS=${OSVC_CURL_OPTS:--s}
fi

echo "Downloading cluster manager bundle from ${CLUMGR_URL}"
curl $CURL_OPTS -o $CLUMGR_BUNDLE $CLUMGR_URL || {
echo 'Warning: could not download cluster manager bundle. skipping cluster manager installation' >&2
return
}

[[ ! -d $CLUMGR_DIR ]] && mkdir -p $CLUMGR_DIR

echo "Extracting cluster manager bundle to $CLUMGR_DIR"
tar xzf $CLUMGR_BUNDLE -C $CLUMGR_DIR 2>/dev/null || {
echo 'Warning: could not extract cluster manager bundle. skipping cluster manager installation' >&2
return
}
}

function prepare_chroot {
# cleanup
$SUDO rm -rf $OSVC/tmp/BUILDROOT/*
@@ -84,8 +123,11 @@ function prepare_chroot {
gzip -9 -n $f
done

deploy_cluster_manager

# purge unwanted files
cd /tmp
rm -f $CHROOT/opt/opensvc/*.tar.gz >> /dev/null 2>&1
rm -rf $CHROOT/opt/opensvc/bin/pkg
rm -rf $CHROOT/opt/opensvc/lib/tests
rm -f $CHROOT/opt/opensvc/bin/postinstall.cmd
@@ -109,6 +151,7 @@ function prepare_chroot {
mv $CHROOT/opt/opensvc/var/compliance $CHROOT/var/lib/opensvc/
mv $CHROOT/opt/opensvc/usr/share/doc/* $DOCDIR/
mv $CHROOT/opt/opensvc/usr/share/man/man1/* $CHROOT/usr/share/man/man1/
mv $CHROOT/opt/opensvc/usr/share/html $CHROOT/usr/share/opensvc/
mv $CHROOT/opt/opensvc/usr/share/bash_completion.d/opensvc.sh $CHROOT/etc/bash_completion.d/
ln -sf ../share/opensvc/bin/om $CHROOT/usr/bin/om
ln -sf ../share/opensvc/bin/opensvc $CHROOT/usr/bin/svcmgr
@@ -79,6 +79,8 @@ def unset_multi(self, kws):
except Exception:
section = "DEFAULT"
option = kw
section = section.lower()
option = option.lower()
try:
del cd[section][option]
deleted += 1
@@ -204,6 +206,7 @@ def set_multi(self, kws, eval=False, validation=True):
if "=" not in kw:
raise ex.excError("malformed kw expression: %s: no '='" % kw)
keyword, value = kw.split("=", 1)
keyword = keyword.lower()
if keyword[-1] == "-":
op = "remove"
keyword = keyword[:-1]
@@ -261,7 +264,7 @@ def set_mono(self, eval=False):
else:
op = "set"
value = self.options.value
keyword = self.options.param
keyword = self.options.param.lower()
index = self.options.index
changes = []
if "." in keyword and "#" not in keyword:
@@ -193,6 +193,35 @@ def template_rst(self, section=None):
s += '\n'
return s

def dump(self):
data = {"keyword": self.keyword}
if self.rtype:
data["type"] = self.rtype
if self.at:
data["at"] = self.at
if self.required:
data["required"] = self.required
if self.candidates:
data["candidates"] = self.candidates
data["strict_candidates"] = self.strict_candidates
if self.default:
data["default"] = self.default
if self.default_text:
data["default_text"] = self.default_text
if self.inheritance:
data["inheritance"] = self.inheritance
if self.scope_order:
data["scope_order"] = self.scope_order
if self.provisioning:
data["provisioning"] = self.provisioning
if self.depends:
data["depends"] = self.depends
if self.convert:
data["convert"] = self.convert
if self.text:
data["text"] = self.text
return data

class Section(object):
def __init__(self, section, top=None):
self.section = section
@@ -205,6 +234,12 @@ def __iadd__(self, o):
self.keywords.append(o)
return self

def dump(self):
data = []
for kw in self.keywords:
data.append(kw.dump())
return data

def template(self, fmt="text", write=False):
k = self.getkey("type")
if k is None:
@@ -379,6 +414,12 @@ def __getitem__(self, key):
return Section(k, top=self)
return self.sections[k]

def dump(self):
data = {}
for section in sorted(self.sections):
data[section] = self.sections[section].dump()
return data

def print_templates(self, fmt="text"):
"""
Print templates in the spectified format (text by default, or rst).
@@ -109,6 +109,7 @@
"reboot",
"shutdown",
"updatepkg",
"updateclumgr",
"updatecomp",
)
ACTIONS_NO_PARALLEL = [
@@ -2166,6 +2167,86 @@ def updatepkg(self):
os.system("%s pushasset" % rcEnv.paths.nodemgr)
return 0

def updateclumgr(self):
"""
Downloads and installs the cluster manager bundle archive from the url
specified as node.repopkg or node.repo in node.conf.
"""
import osvcd_shared as shared
api_version = str(shared.API_VERSION)
repopkg = self.oget("node", "repopkg")
repo = self.oget("node", "repo")
if repopkg:
bundle_basename = repopkg.strip('/')
elif repo:
bundle_basename = repo.strip('/')
else:
if self.options.cron:
return 0
print("node.repo or node.repopkg must be set in node.conf",
file=sys.stderr)
return 1
bundle_name = bundle_basename + "/cluster-manager/" + api_version + '/current'
import tempfile
tmpf = tempfile.NamedTemporaryFile()
fpath = tmpf.name
tmpf.close()
try:
ret = self._updateclumgr(bundle_name, fpath)
finally:
if os.path.exists(fpath):
os.unlink(fpath)
return ret

def _updateclumgr(self, bundle_name, fpath):
"""
Downloads and installs the cluster manager bundle archive from the url
specified by the bundle_name argument. The download destination file
is specified by fpath. The caller is responsible for its deletion.
"""
print("get %s (%s)"%(bundle_name, fpath))
try:
self.urlretrieve(bundle_name, fpath)
except IOError as exc:
print("download failed", ":", exc, file=sys.stderr)
if self.options.cron:
return 0
return 1
tmpp = os.path.join(rcEnv.paths.pathtmp, 'html')
backp = os.path.join(rcEnv.paths.pathsvc, 'html.bck')
htmlp = os.path.join(rcEnv.paths.pathsvc, 'html')
makedirs(htmlp)
makedirs(tmpp)

print("extract cluster manager in", tmpp)
import tarfile
tar = tarfile.open(fpath)
os.chdir(tmpp)
try:
tar.extractall()
tar.close()
except (OSError, IOError):
print("failed to unpack", file=sys.stderr)
return 1
os.chdir("/")

print("install new cluster manager in %s"%htmlp)
for root, dirs, files in os.walk(tmpp):
for fpath in dirs:
os.chown(os.path.join(root, fpath), 0, 0)
for fpath in files:
os.chown(os.path.join(root, fpath), 0, 0)

import shutil
try:
shutil.rmtree(backp)
except (OSError, IOError):
pass

shutil.move(htmlp, backp)
shutil.move(tmpp, htmlp)
return 0

def array(self):
"""
Execute a array command, passing extra_argv to the array driver.
@@ -1104,13 +1104,6 @@
"default": "10.22.0.0/16",
"text": "The cluster backend network. The routed_bridge driver fragments this network into <ips_per_nodes> blocks> subnets."
},
{
"section": "network",
"rtype": ["routed_bridge"],
"keyword": "subnet",
"default": "10.22.0.0/16",
"text": "The cluster backend network to fragment for nodes into <ips_per_nodes> blocks."
},
{
"section": "network",
"rtype": "weave",
@@ -432,7 +432,13 @@
},
"updatepkg": {
"msg": "Upgrade the opensvc agent version. the packages must be "
"available behind the node.repo/packages url.",
"available behind the node.repo/packages url, or behind "
"a mirrored node.repopkg url.",
},
"updateclumgr": {
"msg": "Upgrade the opensvc cluster manager version. the bundles "
"must be available behind the node.repo/cluster-manager "
"url, or behind a mirrored node.repopkg url.",
},
"updatecomp": {
"msg": "Upgrade the opensvc compliance modules. The modules must "
@@ -191,8 +191,8 @@ def write_pid(self):

def init(self):
shared.NODE = node_mod.Node()
self.log.info("daemon started, version %s, crypto mod %s",
shared.NODE.agent_version, CRYPTO_MODULE)
self.log.info("daemon started, version %s, crypto mod %s, api version %s",
shared.NODE.agent_version, CRYPTO_MODULE, shared.API_VERSION)

def loop_forever(self):
"""
@@ -3084,6 +3084,33 @@ def action_get_node(self, nodename, **kwargs):
data = shared.NODE.asset.get_asset_dict()
return data

def rbac_action_get_pools(self, nodename, **kwargs):
self.rbac_requires(roles=["guest"], namespaces="ANY", **kwargs)

def action_get_pools(self, nodename, **kwargs):
data = shared.NODE.pool_status_data()
return data

def rbac_action_get_networks(self, nodename, **kwargs):
self.rbac_requires(roles=["guest"], namespaces="ANY", **kwargs)

def action_get_networks(self, nodename, **kwargs):
data = shared.NODE.network_status_data()
return data

def rbac_action_get_keywords(self, nodename, **kwargs):
pass

def action_get_keywords(self, nodename, **kwargs):
options = kwargs.get("options", {})
kind = options.get("kind", {})
if kind == "node":
obj = shared.NODE
elif kind:
obj = factory(kind)(name="dummy", node=self, volatile=True)
else:
raise HTTP(400, "A kind must be specified.")
return obj.kwdict.KEYS.dump()

##########################################################################
#
@@ -101,6 +101,7 @@ def init(self):
with shared.CLUSTER_DATA_LOCK:
shared.CLUSTER_DATA[rcEnv.nodename] = {
"compat": shared.COMPAT_VERSION,
"api": shared.API_VERSION,
"agent": shared.NODE.agent_version,
"monitor": dict(shared.NMON_DATA),
"labels": shared.NODE.labels,
@@ -706,7 +707,7 @@ def services_init_status(self):
)

def services_init_boot(self):
proc = self.service_command(",".join(list_services()), ["boot", "--parallel"])
proc = self.service_command(",".join(list_services(kinds=["vol", "svc"])), ["boot", "--parallel"])
self.push_proc(
proc=proc,
on_success="services_init_status_callback",
@@ -37,6 +37,9 @@
# ours
COMPAT_VERSION = 10

# expose api handlers version
API_VERSION = 3

# node and cluster conf lock to block reading changes during a multi-write
# transaction (ex daemon join)
CONFIG_LOCK = threading.RLock()
@@ -1153,7 +1153,7 @@ def daemon_test_lock():
#
#############################################################################

def is_service(f, namespace=None, data=None, local=False):
def is_service(f, namespace=None, data=None, local=False, kinds=None):
if f is None:
return
f = re.sub(".conf$", "", f)
@@ -1162,6 +1162,8 @@ def is_service(f, namespace=None, data=None, local=False):
name, namespace, kind = split_path(f)
except ValueError:
return
if kinds and kind not in kinds:
return
path = fmt_path(name, namespace, kind)
if not local:
try:
@@ -1175,14 +1177,14 @@ def is_service(f, namespace=None, data=None, local=False):
return
return path

def list_services(namespace=None):
def list_services(namespace=None, kinds=None):
l = []
if namespace in (None, "root"):
for name in glob_root_config():
s = name[:-5]
if len(s) == 0:
continue
path = is_service(name)
path = is_service(name, kinds=kinds)
if path is None:
continue
l.append(path)
@@ -1191,6 +1193,13 @@ def list_services(namespace=None):
path = path[n:-5]
if path[-1] == os.sep:
continue
if kinds:
try:
name, namespace, kind = split_path(path)
except ValueError:
continue
if kind not in kinds:
continue
l.append(path)
return l

0 comments on commit 3d17f53

Please sign in to comment.
You can’t perform that action at this time.