nuvolaris/mongodb.py (122 lines of code) (raw):
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
# Deploys mongodb for nuvolaris using operator or standalone
# implementation.
#
# By default standalone configuration is used unless mongodb.useOperator is set to true
#
import nuvolaris.config as cfg
import nuvolaris.util as util
import nuvolaris.mongodb_operator as operator
import nuvolaris.mongodb_standalone as standalone
import nuvolaris.kube as kube
import nuvolaris.template as ntp
import logging, json
import os
import urllib.parse
import nuvolaris.openwhisk as openwhisk
from nuvolaris.user_config import UserConfig
from nuvolaris.user_metadata import UserMetadata
def get_mdb_pod_name():
useOperator = cfg.get('mongodb.useOperator') or False
pod_name_jsonpath = useOperator and "{.items[?(@.metadata.labels.app == 'nuvolaris-mongodb-svc')].metadata.name}" or "{.items[?(@.metadata.labels.app == 'nuvolaris-mongodb')].metadata.name}"
return util.get_pod_name(pod_name_jsonpath)
def _add_mdb_user_metadata(ucfg, user_metadata):
"""
adds an entry for the mongodb connectivity, i.e
something like "mongodb://{namespace}:{auth}@nuvolaris-mongodb-0.nuvolaris-mongodb-svc.nuvolaris.svc.cluster.local:27017/{database}?connectTimeoutMS=60000"}
"""
try:
mdb_service = util.get_service("{.items[?(@.metadata.name == 'nuvolaris-mongodb-svc')]}")
if(mdb_service):
mdb_service_name = mdb_service['metadata']['name']
mdb_ns = mdb_service['metadata']['namespace']
mdb_pod_name = get_mdb_pod_name()
username = urllib.parse.quote(ucfg.get('namespace'))
password = urllib.parse.quote(ucfg.get('mongodb.password'))
auth = f"{username}:{password}"
database = ucfg.get('mongodb.database')
mdb_url = f"mongodb://{auth}@{mdb_pod_name}.{mdb_service_name}.{mdb_ns}.svc.cluster.local:27017/{database}?connectTimeoutMS=60000"
user_metadata.add_metadata("MONGODB_URL",mdb_url)
return None
except Exception as e:
logging.error(f"failed to build mongodb_url for {ucfg.get('mongodb.database')}: {e}")
return None
def create(owner=None):
"""
Deploys the mongodb operator and wait for the operator to be ready.
"""
useOperator = cfg.get('mongodb.useOperator') or False
res = useOperator and operator.create(owner) or standalone.create(owner)
if(res):
update_system_cm_for_mdb()
return res
def update_system_cm_for_mdb():
logging.info("*** annotating configuration for mongodb nuvolaris user")
try:
mdb_service = util.get_service("{.items[?(@.metadata.name == 'nuvolaris-mongodb-svc')]}")
if(mdb_service):
mdb_pod_name = get_mdb_pod_name()
mdb_service_name = mdb_service['metadata']['name']
mdb_ns = mdb_service['metadata']['namespace']
data = util.get_mongodb_config_data()
username = urllib.parse.quote(data['mongo_nuvolaris_user'])
password = urllib.parse.quote(data['mongo_nuvolaris_password'])
auth = f"{username}:{password}"
mdb_url = f"mongodb://{auth}@{mdb_pod_name}.{mdb_service_name}.{mdb_ns}.svc.cluster.local:27017/nuvolaris?connectTimeoutMS=60000"
openwhisk.annotate(f"mongodb_url={mdb_url}")
logging.info("*** saved annotation for mongodb nuvolaris user")
except Exception as e:
logging.error(f"failed to build mongodb_url for nuvolaris database: {e}")
def delete(owner=None):
useOperator = cfg.get('mongodb.useOperator') or False
if useOperator:
return operator.delete(owner)
return standalone.delete(owner)
def init():
return "TODO"
def render_mongodb_script(namespace,template,data):
"""
uses the given template to render a js script to execute as a json.
"""
out = f"/tmp/__{namespace}_{template}"
file = ntp.spool_template(template, out, data)
return os.path.abspath(file)
def exec_mongosh_command(pod_name,path_to_mdb_script):
logging.info(f"passing script {path_to_mdb_script} to pod {pod_name}")
res = kube.kubectl("cp",path_to_mdb_script,f"{pod_name}:{path_to_mdb_script}")
res = kube.kubectl("exec","-it",pod_name,"--","/bin/bash","-c",f"mongosh --file {path_to_mdb_script}")
os.remove(path_to_mdb_script)
return res
def create_db_user(ucfg: UserConfig, user_metadata: UserMetadata):
database = ucfg.get('mongodb.database')
logging.info(f"authorizing new mongodb database {database}")
try:
data = util.get_mongodb_config_data()
data["database"]=database
data["subject"]=ucfg.get('namespace')
data["auth"]=ucfg.get('mongodb.password')
data["mode"]="create"
path_to_mdb_script = render_mongodb_script(ucfg.get('namespace'),"mongodb_manage_user_tpl.js",data)
pod_name = util.get_pod_name("{.items[?(@.metadata.labels.app == 'nuvolaris-mongodb')].metadata.name}")
if(pod_name):
res = exec_mongosh_command(pod_name,path_to_mdb_script)
_add_mdb_user_metadata(ucfg, user_metadata)
return res
return None
except Exception as e:
logging.error(f"failed to add Mongodb database {database}: {e}")
return None
def delete_db_user(namespace, database):
logging.info(f"removing mongodb database {database}")
try:
data = util.get_mongodb_config_data()
data["subject"]=namespace
data["database"]=database
data["mode"]="delete"
path_to_mdb_script = render_mongodb_script(namespace,"mongodb_manage_user_tpl.js",data)
pod_name = util.get_pod_name("{.items[?(@.metadata.labels.app == 'nuvolaris-mongodb')].metadata.name}")
if(pod_name):
res = exec_mongosh_command(pod_name,path_to_mdb_script)
return res
return None
except Exception as e:
logging.error(f"failed to remove Mongodb database {namespace} authorization id and key: {e}")
return None
def patch(status, action, owner=None):
"""
Called the the operator patcher to create/delete mongodb
"""
try:
logging.info(f"*** handling request to {action} mongodb")
if action == 'create':
msg = create(owner)
status['whisk_create']['mongodb']='on'
else:
msg = delete(owner)
status['whisk_create']['mongodb']='off'
logging.info(msg)
logging.info(f"*** hanlded request to {action} mongodb")
except Exception as e:
logging.error('*** failed to update mongodb: %s' % e)
status['whisk_create']['mongodb']='error'