aboutsummaryrefslogtreecommitdiffstats
path: root/moon_orchestrator
diff options
context:
space:
mode:
authorThomas Duval <thomas.duval@orange.com>2018-01-15 21:12:32 +0100
committerThomas Duval <thomas.duval@orange.com>2018-01-15 21:12:32 +0100
commitba90e446c6d5a51c9ed392416f90b7bb56d11603 (patch)
treed4f2f02ace9af594fbe6abce3824cfb494ece998 /moon_orchestrator
parent1da8f2e5f28813a90ecc329462dcc647ce757494 (diff)
Add th ability to (un)load wrapper components through API
Change-Id: I58a25dbc0479e416d471115885dab7ccfb27e18a
Diffstat (limited to 'moon_orchestrator')
-rw-r--r--moon_orchestrator/moon_orchestrator/api/pods.py100
-rw-r--r--moon_orchestrator/moon_orchestrator/api/slaves.py46
-rw-r--r--moon_orchestrator/moon_orchestrator/drivers.py124
-rw-r--r--moon_orchestrator/moon_orchestrator/http_server.py7
-rw-r--r--moon_orchestrator/tests/unit_python/test_pods.py60
-rw-r--r--moon_orchestrator/tests/unit_python/test_slaves.py17
6 files changed, 300 insertions, 54 deletions
diff --git a/moon_orchestrator/moon_orchestrator/api/pods.py b/moon_orchestrator/moon_orchestrator/api/pods.py
index 31ae31de..3a01c3a9 100644
--- a/moon_orchestrator/moon_orchestrator/api/pods.py
+++ b/moon_orchestrator/moon_orchestrator/api/pods.py
@@ -6,6 +6,7 @@
from flask import request
from flask_restful import Resource
from python_moonutilities.security_functions import check_auth
+from python_moonutilities import exceptions
import logging
logger = logging.getLogger("moon.orchestrator.api.pods")
@@ -17,6 +18,7 @@ class Pods(Resource):
"""
__version__ = "4.3.1"
+ POD_TYPES = ("authz", "wrapper")
__urls__ = (
"/pods",
@@ -57,6 +59,21 @@ class Pods(Resource):
except Exception as e:
return {"result": False, "message": str(e)}, 500
+ def __get_pod_with_keystone_pid(self, keystone_pid):
+ for pod_key, pod_values in self.driver.get_pods().items():
+ if pod_values[0]['keystone_project_id'] == keystone_pid:
+ return True
+
+ def __get_wrapper(self, slave_name):
+ for slave in self.driver.get_slaves():
+ if slave_name == slave["name"] \
+ and slave["configured"]:
+ return True
+
+ def __get_slave_names(self):
+ for slave in self.driver.get_slaves():
+ yield slave["name"]
+
@check_auth
def post(self, uuid=None, user_id=None):
"""Create a new pod.
@@ -64,9 +81,14 @@ class Pods(Resource):
:param uuid: uuid of the pod (not used here)
:param user_id: user ID who do the request
:request body: {
- "name": "...",
- "description": "...",
- "type": "plugin_name"
+ "pdp_id": "fa2323f7055d4a88b1b85d31fe5e8369",
+ "name": "pdp_rbac3",
+ "keystone_project_id": "ceacbb5564cc48ad929dd4f00e52bf63",
+ "models": {...},
+ "policies": {...},
+ "description": "test",
+ "security_pipeline": [...],
+ "slave_name": ""
}
:return: {
"pdp_id1": {
@@ -76,25 +98,35 @@ class Pods(Resource):
}
}
"""
- logger.debug("POST param={}".format(request.json))
- try:
+ pods = {}
+ if "security_pipeline" in request.json:
+ if self.__get_pod_with_keystone_pid(request.json.get("keystone_project_id")):
+ raise exceptions.PipelineConflict
self.driver.create_pipeline(
request.json.get("keystone_project_id"),
request.json.get("pdp_id"),
request.json.get("security_pipeline"),
manager_data=request.json,
- active_context=None,
- active_context_name=None)
- pods = {}
+ slave_name=request.json.get("slave_name"))
for _pod_key, _pod_values in self.driver.get_pods().items():
pods[_pod_key] = []
for _pod_value in _pod_values:
if _pod_value['namespace'] != "moon":
continue
pods[_pod_key].append(_pod_value)
- return {"pods": pods}
- except Exception as e:
- return {"result": False, "message": str(e)}, 500
+ else:
+ logger.info("------------------------------------")
+ logger.info(list(self.__get_slave_names()))
+ logger.info("------------------------------------")
+ if self.__get_wrapper(request.json.get("slave_name")):
+ raise exceptions.WrapperConflict
+ if request.json.get("slave_name") not in self.__get_slave_names():
+ raise exceptions.SlaveNameUnknown
+ slave_name = request.json.get("slave_name")
+ if not slave_name:
+ slave_name = self.driver.get_slaves(active=True)
+ self.driver.create_wrappers(slave_name)
+ return {"pods": self.driver.get_pods()}
@check_auth
def delete(self, uuid=None, user_id=None):
@@ -110,27 +142,31 @@ class Pods(Resource):
try:
self.driver.delete_pipeline(uuid)
return {'result': True}
+ except exceptions.PipelineUnknown:
+ for slave in self.driver.get_slaves():
+ if uuid in (slave['name'], slave["wrapper_name"]):
+ self.driver.delete_wrapper(name=slave["wrapper_name"])
except Exception as e:
return {"result": False, "message": str(e)}, 500
- @check_auth
- def patch(self, uuid=None, user_id=None):
- """Update a pod
-
- :param uuid: uuid of the pdp to update
- :param user_id: user ID who do the request
- :request body: {
- "name": "...",
- "replicas": "...",
- "description": "...",
- }
- :return: {
- "pod_id1": {
- "name": "...",
- "replicas": "...",
- "description": "...",
- }
- }
- :internal_api: update_pdp
- """
- return {"pods": None}
+ # @check_auth
+ # def patch(self, uuid=None, user_id=None):
+ # """Update a pod
+ #
+ # :param uuid: uuid of the pdp to update
+ # :param user_id: user ID who do the request
+ # :request body: {
+ # "name": "...",
+ # "replicas": "...",
+ # "description": "...",
+ # }
+ # :return: {
+ # "pod_id1": {
+ # "name": "...",
+ # "replicas": "...",
+ # "description": "...",
+ # }
+ # }
+ # :internal_api: update_pdp
+ # """
+ # return {"pods": None}
diff --git a/moon_orchestrator/moon_orchestrator/api/slaves.py b/moon_orchestrator/moon_orchestrator/api/slaves.py
new file mode 100644
index 00000000..7453d305
--- /dev/null
+++ b/moon_orchestrator/moon_orchestrator/api/slaves.py
@@ -0,0 +1,46 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from flask import request
+from flask_restful import Resource
+from python_moonutilities.security_functions import check_auth
+import logging
+
+logger = logging.getLogger("moon.orchestrator.api.slaves")
+
+
+class Slaves(Resource):
+ """
+ Endpoint for slaves requests
+ """
+
+ __version__ = "4.3.1"
+
+ __urls__ = (
+ "/slaves",
+ "/slaves/",
+ "/slaves/<string:uuid>",
+ "/slaves/<string:uuid>/",
+ )
+
+ def __init__(self, **kwargs):
+ self.driver = kwargs.get("driver")
+
+ @check_auth
+ def get(self, uuid=None, user_id=None):
+ """Retrieve all pods
+
+ :param uuid: uuid of the pod
+ :param user_id: user ID who do the request
+ :return: {
+ "pod_id1": {
+ "name": "...",
+ "replicas": "...",
+ "description": "...",
+ }
+ }
+ """
+ slaves = self.driver.get_slaves()
+ return {"slaves": slaves}
diff --git a/moon_orchestrator/moon_orchestrator/drivers.py b/moon_orchestrator/moon_orchestrator/drivers.py
index 9c230cce..bb0d0c2c 100644
--- a/moon_orchestrator/moon_orchestrator/drivers.py
+++ b/moon_orchestrator/moon_orchestrator/drivers.py
@@ -159,17 +159,17 @@ class K8S(Driver):
resp = client.create_namespaced_service(namespace="moon",
body=service_manifest)
logger.info("Service {} created!".format(data.get('name')))
- return resp
+ return service_manifest
def load_deployment_and_service(self, data, api_client=None, ext_client=None, expose=False):
_client = api_client if api_client else self.client
+ manifest = self.__create_service(client=_client, data=data[0],
+ expose=expose)
+ data[0]["external_port"] = manifest['spec']['ports'][0].get('nodePort')
pod = self.__create_deployment(client=ext_client, data=data)
- self.__create_service(client=_client, data=data[0],
- expose=expose)
self.cache[pod.metadata.uid] = data
- @staticmethod
- def delete_deployment(name=None, namespace="moon", ext_client=None):
+ def delete_deployment(self, name=None, namespace="moon", ext_client=None):
logger.info("Deleting deployment {}".format(name))
body = client.V1DeleteOptions(propagation_policy='Foreground')
ret = ext_client.delete_namespaced_deployment(
@@ -177,7 +177,16 @@ class K8S(Driver):
namespace=namespace,
body=body
)
- logger.info(ret)
+ logger.debug(ret)
+ _uid = None
+ for uid, value in self.cache.items():
+ if value[0]['name'] == name:
+ _uid = uid
+ break
+ if _uid:
+ self.cache.pop(_uid)
+ else:
+ raise exceptions.DockerError("Cannot find and delete pod named {}".format(name))
def delete_service(self, name, namespace="moon", api_client=None):
if not api_client:
@@ -185,12 +194,45 @@ class K8S(Driver):
ret = api_client.delete_namespaced_service(name=name, namespace=namespace)
logger.debug("delete_service {}".format(ret))
- def get_slaves(self):
+ def get_slaves(self, active=False):
+ contexts, active_context = self.get_contexts()
+ pods = self.get_pods()
+ # logger.info("pods = {}".format(pods))
+ slaves = []
+ if active:
+ for key, value in pods.items():
+ # logger.info("ctx={}".format(active_context))
+ # logger.info("value={}".format(value))
+ if active_context["name"] == value[0].get('slave_name'):
+ data = dict(active_context)
+ data["wrapper_name"] = value[0]['name']
+ data["ip"] = value[0].get("ip", "NC")
+ data["port"] = value[0].get("external_port", "NC")
+ slaves.append(data)
+ break
+ return slaves
+ for ctx in contexts:
+ data = dict(ctx)
+ data["configured"] = False
+ for key, value in pods.items():
+ # logger.info("ctx={}".format(ctx))
+ # logger.info("value={}".format(value))
+ if ctx["name"] == value[0].get('slave_name'):
+ data["wrapper_name"] = value[0]['name']
+ data["ip"] = value[0].get("ip", "NC")
+ data["port"] = value[0].get("external_port", "NC")
+ data["configured"] = True
+ break
+ slaves.append(data)
+ return slaves
+
+ @staticmethod
+ def get_contexts():
contexts, active_context = config.list_kube_config_contexts()
return contexts, active_context
- def create_wrappers(self):
- contexts, active_context = self.get_slaves()
+ def create_wrappers(self, slave_name=None):
+ contexts, active_context = self.get_contexts()
logger.debug("contexts: {}".format(contexts))
logger.debug("active_context: {}".format(active_context))
conf = configuration.get_configuration("components/wrapper")
@@ -201,6 +243,8 @@ class K8S(Driver):
"container",
"wukongsun/moon_wrapper:v4.3")
for _ctx in contexts:
+ if slave_name and slave_name != _ctx['name']:
+ continue
_config = config.new_client_from_config(context=_ctx['name'])
logger.debug("_config={}".format(_config))
api_client = client.CoreV1Api(_config)
@@ -209,14 +253,56 @@ class K8S(Driver):
"name": hostname + "-" + get_random_name(),
"container": container,
"port": port,
- "namespace": "moon"
+ "namespace": "moon",
+ "slave_name": _ctx['name']
}, ]
self.load_deployment_and_service(data, api_client, ext_client, expose=True)
+ def delete_wrapper(self, uuid=None, name=None, namespace="moon",
+ active_context=None,
+ active_context_name=None):
+ name_to_delete = None
+ if uuid and uuid in self.get_pods():
+ name_to_delete = self.get_pods()[uuid][0]['name']
+ elif name:
+ for pod_key, pod_list in self.get_pods().items():
+ for pod_value in pod_list:
+ if pod_value.get("name") == name:
+ name_to_delete = pod_value.get("name")
+ break
+ if not name_to_delete:
+ raise exceptions.WrapperUnknown
+ contexts, _active_context = self.get_contexts()
+ if active_context_name:
+ for _context in contexts:
+ if _context["name"] == active_context_name:
+ active_context = _context
+ break
+ if active_context:
+ active_context = _active_context
+ _config = config.new_client_from_config(
+ context=active_context['name'])
+ logger.debug("_config={}".format(_config))
+ api_client = client.CoreV1Api(_config)
+ ext_client = client.ExtensionsV1beta1Api(_config)
+ self.delete_deployment(name=name_to_delete, namespace=namespace,
+ ext_client=ext_client)
+ self.delete_service(name=name_to_delete, api_client=api_client)
+ return
+ logger.debug("contexts={}".format(contexts))
+ for _ctx in contexts:
+ _config = config.new_client_from_config(context=_ctx['name'])
+ logger.debug("_config={}".format(_config))
+ api_client = client.CoreV1Api(_config)
+ ext_client = client.ExtensionsV1beta1Api(_config)
+ self.delete_deployment(name=name_to_delete, namespace=namespace,
+ ext_client=ext_client)
+ self.delete_service(name=name_to_delete, api_client=api_client)
+
def create_pipeline(self, keystone_project_id,
pdp_id, policy_ids, manager_data=None,
active_context=None,
- active_context_name=None):
+ slave_name=None):
""" Create security functions
:param keystone_project_id: the Keystone project id
@@ -225,7 +311,7 @@ class K8S(Driver):
:param manager_data: data needed to create pods
:param active_context: if present, add the security function in this
context
- :param active_context_name: if present, add the security function in
+ :param slave_name: if present, add the security function in
this context name
if active_context_name and active_context are not present, add the
security function in all context (ie, in all slaves)
@@ -295,12 +381,12 @@ class K8S(Driver):
"namespace": "moon"
})
logger.debug("data={}".format(data))
- contexts, _active_context = self.get_slaves()
- logger.debug("active_context_name={}".format(active_context_name))
+ contexts, _active_context = self.get_contexts()
+ logger.debug("active_context_name={}".format(slave_name))
logger.debug("active_context={}".format(active_context))
- if active_context_name:
+ if slave_name:
for _context in contexts:
- if _context["name"] == active_context_name:
+ if _context["name"] == slave_name:
active_context = _context
break
if active_context:
@@ -314,6 +400,8 @@ class K8S(Driver):
return
logger.debug("contexts={}".format(contexts))
for _ctx in contexts:
+ if slave_name and slave_name != _ctx['name']:
+ continue
_config = config.new_client_from_config(context=_ctx['name'])
logger.debug("_config={}".format(_config))
api_client = client.CoreV1Api(_config)
@@ -342,9 +430,9 @@ class K8S(Driver):
name_to_delete = pod_value.get("name")
break
if not name_to_delete:
- raise exceptions.MoonError("Cannot find pipeline")
+ raise exceptions.PipelineUnknown
logger.info("Will delete deployment and service named {}".format(name_to_delete))
- contexts, _active_context = self.get_slaves()
+ contexts, _active_context = self.get_contexts()
if active_context_name:
for _context in contexts:
if _context["name"] == active_context_name:
diff --git a/moon_orchestrator/moon_orchestrator/http_server.py b/moon_orchestrator/moon_orchestrator/http_server.py
index fa5308d0..85e29cd0 100644
--- a/moon_orchestrator/moon_orchestrator/http_server.py
+++ b/moon_orchestrator/moon_orchestrator/http_server.py
@@ -10,6 +10,7 @@ import requests
import time
from moon_orchestrator import __version__
from moon_orchestrator.api.pods import Pods
+from moon_orchestrator.api.slaves import Slaves
from moon_orchestrator.api.generic import Status
from moon_orchestrator.drivers import get_driver
from python_moonutilities import configuration, exceptions
@@ -122,7 +123,7 @@ class HTTPServer(Server):
if "pdps" in pdp.json():
break
logger.debug("pdp={}".format(pdp))
- self.driver.create_wrappers()
+ # self.driver.create_wrappers()
for _pdp_key, _pdp_value in pdp.json()['pdps'].items():
if _pdp_value.get('keystone_project_id'):
# TODO: select context to add security function
@@ -151,6 +152,10 @@ class HTTPServer(Server):
resource_class_kwargs={
"driver": self.driver
})
+ self.api.add_resource(Slaves, *Slaves.__urls__,
+ resource_class_kwargs={
+ "driver": self.driver
+ })
def run(self):
self.app.run(host=self._host, port=self._port) # nosec
diff --git a/moon_orchestrator/tests/unit_python/test_pods.py b/moon_orchestrator/tests/unit_python/test_pods.py
index f760aa62..678645be 100644
--- a/moon_orchestrator/tests/unit_python/test_pods.py
+++ b/moon_orchestrator/tests/unit_python/test_pods.py
@@ -31,7 +31,7 @@ def test_get_pods_failure(context, monkeypatch):
assert not data["pods"]
-def test_add_pods(context, monkeypatch):
+def test_add_pods_with_pipeline(context, monkeypatch):
patch_k8s(monkeypatch)
import moon_orchestrator.server
@@ -52,6 +52,60 @@ def test_add_pods(context, monkeypatch):
assert data["pods"]
+def test_add_pods_without_pipeline_with_bad_slave_name(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "slave_name": "test",
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert 'The slave is unknown.' in data['message']
+
+
+def test_add_pods_without_pipeline_with_good_slave_name(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "slave_name": "active_context",
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert "pods" in data
+ assert data["pods"]
+
+
+def test_add_pods_without_pipeline_without_slave_name(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert 'The slave is unknown.' in data['message']
+
+
def test_add_pods_with_no_data(context, monkeypatch):
patch_k8s(monkeypatch)
import moon_orchestrator.server
@@ -59,10 +113,10 @@ def test_add_pods_with_no_data(context, monkeypatch):
_client = server.app.test_client()
req = _client.post("/pods", data=json.dumps({}),
headers={'Content-Type': 'application/json'})
- assert req.status_code == 500
+ assert req.status_code == 400
assert req.data
data = get_json(req.data)
- assert '400: Policy Unknown' in data['message']
+ assert 'The slave is unknown.' in data['message']
def test_add_pods_with_no_policies_no_models(context, monkeypatch, no_requests):
diff --git a/moon_orchestrator/tests/unit_python/test_slaves.py b/moon_orchestrator/tests/unit_python/test_slaves.py
new file mode 100644
index 00000000..88ff7e55
--- /dev/null
+++ b/moon_orchestrator/tests/unit_python/test_slaves.py
@@ -0,0 +1,17 @@
+import json
+from mock_pods import patch_k8s
+from utilities import get_json
+
+
+def test_get_slaves(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ req = _client.get("/slaves")
+ assert req.status_code == 200
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert "slaves" in data