diff options
Diffstat (limited to 'moonv4')
363 files changed, 13424 insertions, 8341 deletions
diff --git a/moonv4/DEV.md b/moonv4/DEV.md index 70bcc4fc..0dff2f17 100644 --- a/moonv4/DEV.md +++ b/moonv4/DEV.md @@ -1,6 +1,52 @@ -# Build Python Packages and Docker Images - -## Python Package +# Developer Tutorial + +## Gerrit Setup +### Git Install +- `sudo apt-get install git` +- `git config --global user.email "example@wikimedia.org"` +- `git config --global user.name "example"` + +### ssh key +- `cd ~/.ssh` +- `ssh-keygen -t rsa -C your_email@youremail.com` +- `~/.ssh/id_rsa`: identification (private) key` +- `~/.ssh/id_rsa.pub`: public key +- copy the public key to Gerrit web +- add Gerrit web上 entry to `~/.ssh/known_hosts` +- eval `ssh-agent`: start ssh-agent +- `ssh-add ~/.ssh/id_rsa`: add private key to ssh +- `ssh -p 29418 <USERNAME>@gerrit.opnfv.org`: test + +### Gerrit clone +- `git clone https://WuKong@gerrit.opnfv.org:29418/moon` +- the password is dynamically generated on the Gerrit web + +### Gerrit Setting +- `sudo apt-get install python-pip` +- `sudo pip install git-review` +- `git remote add gerrit ssh://<yourname>@gerrit.opnfv.org:29418/moon.git` +- add the ssh public key to the Gerrit web +- `git review –s`: test the Gerrit review connection +- add Contributor Agreement, from settings/Agreement + +### Gerrit-Review +- git add XXX +- git commit --signoff --all +- git review + +### Review Correction +- `git clone https://git.opnfv.org/moon` +- `cd moon` +- get the commit id from Gerrit dashboard +- `git checkout commit_id` +- `git checkout -b 48957-1` (where '48957' is the change number and '1' is the patch_number) +- do your changes ex:`vi specs/policy/external-pdp.rst` +- `git add specs/policy/external-pdp.rst` +- `git commit –amend` +- `git review` + + +## Build Python Package ### pre-requist Get the code ```bash diff --git a/moonv4/README.md b/moonv4/README.md index 95499589..ba3604d6 100644 --- a/moonv4/README.md +++ b/moonv4/README.md @@ -1,122 +1,381 @@ -# Moon Version 4 - -This directory contains all the modules for MoonV4 +# Moon +__Version 4.3__ +This directory contains all the modules for running the Moon platform. ## Installation -### Prerequisite +### kubeadm +You must follow those explanations to install `kubeadm`: +> https://kubernetes.io/docs/setup/independent/install-kubeadm/ + +To summarize, you must install `docker`: ```bash -sudo apt install python3-dev python3-pip -sudo pip3 install pip --upgrade -sudo apt -y install docker-engine # ([Get Docker](https://docs.docker.com/engine/installation/)) -echo 127.0.0.1 messenger db keystone | sudo tee -a /etc/hosts +apt update +apt install -y docker.io ``` - - -### Docker Engine Configuration + +And then, install `kubeadm`: ```bash -cat <<EOF | sudo tee /etc/docker/daemon.json -{ - "hosts": ["fd://", "tcp://0.0.0.0:2376"] -} +apt update && apt install -y apt-transport-https +curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - +cat <<EOF >/etc/apt/sources.list.d/kubernetes.list +deb http://apt.kubernetes.io/ kubernetes-xenial main EOF -sudo mv /lib/systemd/system/docker.service /lib/systemd/system/docker.service.bak -sudo sed 's/ExecStart=\/usr\/bin\/dockerd -H fd:\/\//ExecStart=\/usr\/bin\/dockerd/' /lib/systemd/system/docker.service.bak | sudo tee /lib/systemd/system/docker.service -sudo service docker restart -# if you have a firewall: -sudo ufw allow in from 172.88.88.0/16 +apt update +apt install -y kubelet kubeadm kubectl ``` -## Run Standard Containers -### Cleanup -Remove already running containers +### Moon +The Moon code is not necessary to start the platform but you need +Kubernetes configuration files from the GIT repository. + +The easy way is to clone the Moon code: ```bash -docker container rm -f $(docker ps -a | grep moon | cut -d " " -f 1) 2>/dev/null -docker container rm -f messenger db keystone consul 2>/dev/null +git clone https://git.opnfv.org/moon +cd moon/moonv4 +export MOON=$(pwd) ``` +### OpenStack +You must have the following OpenStack components installed somewhere: +- nova, see [Nova install](https://docs.openstack.org/mitaka/install-guide-ubuntu/nova-controller-install.html) +- glance, see [Glance install](https://docs.openstack.org/glance/pike/install/) -### Internal Network Creation -Create an internal Docker network called `moon` -```bash -docker network create -d bridge --subnet=172.88.88.0/16 --gateway=172.88.88.1 moon -``` +A Keystone component is automatically installed and configured in the Moon platform. +After the Moon platform installation, the Keystone server will be available +at: `http://localhost:30005 or http://\<servername\>:30005` +You can also use your own Keystone server if you want. -### MySql -Run the standard `MySql` container in the `moon` network +## Initialisation +### kubeadm +The `kubeadm` platform can be initialized with the following shell script: ```bash -docker container run -dti --net=moon --hostname db --name db -e MYSQL_ROOT_PASSWORD=p4sswOrd1 -e MYSQL_DATABASE=moon -e MYSQL_USER=moon -e MYSQL_PASSWORD=p4sswOrd1 -p 3306:3306 mysql:latest +sh kubernetes/init_k8s.sh ``` - -### Rabbitmq -Run the standard `Rabbitmq` container in the `moon` network + +Wait until all the kubeadm containers are in the `running` state: ```bash -docker container run -dti --net=moon --hostname messenger --name messenger -e RABBITMQ_DEFAULT_USER=moon -e RABBITMQ_DEFAULT_PASS=p4sswOrd1 -e RABBITMQ_NODENAME=rabbit@messenger -e RABBITMQ_DEFAULT_VHOST=moon -e RABBITMQ_HIPE_COMPILE=1 -p 5671:5671 -p 5672:5672 -p 8080:15672 rabbitmq:3-management +watch kubectl get po --namespace=kube-system ``` + +You must see something like this: + + $ kubectl get po --namespace=kube-system + NAME READY STATUS RESTARTS AGE + calico-etcd-7qgjb 1/1 Running 0 1h + calico-node-f8zvm 2/2 Running 1 1h + calico-policy-controller-59fc4f7888-ns9kv 1/1 Running 0 1h + etcd-varuna 1/1 Running 0 1h + kube-apiserver-varuna 1/1 Running 0 1h + kube-controller-manager-varuna 1/1 Running 0 1h + kube-dns-bfbb49cd7-rgqxn 3/3 Running 0 1h + kube-proxy-x88wg 1/1 Running 0 1h + kube-scheduler-varuna 1/1 Running 0 1h + +### Moon +The Moon platform is composed on the following components: +* `consul`: a Consul configuration server +* `db`: a MySQL database server +* `keystone`: a Keystone authentication server +* `gui`: a Moon web interface +* `manager`: the Moon manager for the database +* `orchestrator`: the Moon component that manage pods in te K8S platform +* `wrapper`: the Moon endpoint where OpenStack component connect to. +At this point, you must choose one of the following options: +* Specific configuration +* Generic configuration -### moon_keystone -Run the `keystone` container (created by the `Moon` project) in the `moon` network +#### Specific Configuration +Why using a specific configuration: +1. The `db` and `keystone` can be installed by yourself but you must configure the +Moon platform to use them. +2. You want to change the default passwords in the Moon platform + +Use the following commands: `TODO` + +#### Generic Configuration +Why using a specific configuration: +1. You just want to test the platform +2. You want to develop on the Moon platform + +The `Moon` platform can be initialized with the following shell script: ```bash -docker container run -dti --net moon --hostname keystone --name keystone -e DB_HOST=db -e DB_PASSWORD_ROOT=p4sswOrd1 -p 35357:35357 -p 5000:5000 wukongsun/moon_keystone:ocata +sh kubernetes/start_moon.sh ``` -### Consul -Run the standard `Consul` container in the `moon` network +Wait until all the Moon containers are in the `running` state: ```bash -docker run -d --net=moon --name=consul --hostname=consul -p 8500:8500 consul +watch kubectl get po --namespace=moon ``` +You must see something like this: -## Run Moon's Containers -### Automatic Launch -To start the `Moon` framework, you only have to run the `moon_orchestrator` container -```bash -docker container run -dti --net moon --hostname orchestrator --name orchestrator wukongsun/moon_orchestrator:v4.1 + $ kubectl get po --namespace=moon + NAME READY STATUS RESTARTS AGE + consul-57b6d66975-9qnfx 1/1 Running 0 52m + db-867f9c6666-bq8cf 1/1 Running 0 52m + gui-bc9878b58-q288x 1/1 Running 0 51m + keystone-7d9cdbb69f-bl6ln 1/1 Running 0 52m + manager-5bfbb96988-2nvhd 1/1 Running 0 51m + manager-5bfbb96988-fg8vj 1/1 Running 0 51m + manager-5bfbb96988-w9wnk 1/1 Running 0 51m + orchestrator-65d8fb4574-tnfx2 1/1 Running 0 51m + wrapper-astonishing-748b7dcc4f-ngsvp 1/1 Running 0 51m + +## Configuration +### Moon +#### Introduction +The Moon platform is already configured after the installation. +If you want to see or modify the configuration, go with a web browser +to the following page: + +> http://localhost:30006 + +This is a consul server, you can update the configuration in the `KEY/VALUE` tab. +There are some configuration items, lots of them are only read when a new K8S pod is started +and not during its life cycle. + +**WARNING: some confidential information are put here in clear text. +This is a known security issue.** + +#### Keystone +If you have your own Keystone server, you can point Moon to your server in the +`openstack/keystone` element or through the link: +> http://localhost:30005/ui/#/dc1/kv/openstack/keystone/edit + +This configuration element is read every time Moon need it, specially when adding users. + +#### Database +The database can also be modified here: +> http://varuna:30005/ui/#/dc1/kv/database/edit + +**WARNING: the password is in clear text, this is a known security issue.** + +If you want to use your own database server, change the configuration: + + {"url": "mysql+pymysql://my_user:my_secret_password@my_server/moon", "driver": "sql"} + +Then you have to rebuild the database before using it. +This can be done with the following commands: + + cd $MOON + kubectl delete -f kubernetes/templates/moon_configuration.yaml + kubectl create -f kubernetes/templates/moon_configuration.yaml + + +### OpenStack +Before updating the configuration of the OpenStack platform, check that the platform +is working without Moon, use the following commands: +```bash +# set authentication +openstack endpoint list +openstack user list +openstack server list ``` +In order to connect the OpenStack platform with the Moon platform, you must update some +configuration files in Nova and Glance: +* `/etc/nova/policy.json` +* `/etc/glance/policy.json` + +In some installed platform, the `/etc/nova/policy.json` can be absent so you have +to create one. You can find example files in those directory: +> ${MOON}/moonv4/templates/nova/policy.json +> ${MOON}/moonv4/templates/glance/policy.json + +Each line is mapped to an OpenStack API interface, for example, the following line +allows the user to get details for every virtual machines in the cloud +(the corresponding shell command is `openstack server list`): -### Manuel Launch -We can also manually start the `Moon` framework + "os_compute_api:servers:detail": "", -#### moon_router +This lines indicates that there is no special authorisation to use this API, +every users can use it. If you want that the Moon platform handles that authorisation, +update this line with: + + "os_compute_api:servers:detail": "http://my_hostname:31001/authz" + +1) by replacing `my_hostname` with the hostname (od the IP address) of the Moon platform. +2) by updating the TCP port (default: 31001) with the good one. + +To find this TCP port, use the following command: + + $ kubectl get services -n moon | grep wrapper | cut -d ":" -f 2 | cut -d " " -f 1 + 31002/TCP + +### Moon +The Moon platform comes with a graphical user interface which can be used with +a web browser at this URL: +> http://$MOON_HOST:30002 + +You will be asked to put a login and password. Those elements are the login and password +of the Keystone server, if you didn't modify the Keystone server, you will find the +login and password here: +> http://$MOON_HOST:30005/ui/#/dc1/kv/openstack/keystone/edit + +**WARNING: the password is in clear text, this is a known security issue.** + +The Moon platform can also be requested through its API: +> http://$MOON_HOST:30001 + +**WARNING: By default, no login/password will be needed because of +the configuration which is in DEV mode.** + +If you want more security, you have to update the configuration of the Keystone server here: +> http://$MOON_HOST:30005/ui/#/dc1/kv/openstack/keystone/edit + +by modifying the `check_token` argument to `yes`. +If you write this modification, your requests to Moon API must always include a valid token +taken from the Keystone server. This token must be place in the header of the request +(`X-Auth-Token`). + +## usage +### tests the platform +In order to know if the platform is healthy, here are some commands you can use. +1) Check that all the K8S pods in the Moon namespace are in running state: +`kubectl get pods -n moon` + +2) Check if the Manager API is running: ```bash -docker container run -dti --net moon --hostname router --name router wukongsun/moon_router:v4.1 +curl http://$MOON_HOST:30001 +curl http://$MOON_HOST:30001/pdp +curl http://$MOON_HOST:30001/policies ``` - -#### moon_manager + +If you configured the authentication in the Moon platform: ```bash -docker container run -dti --net moon --hostname manager --name manager wukongsun/moon_manager:v4.1 +curl -i \ + -H "Content-Type: application/json" \ + -d ' +{ "auth": { + "identity": { + "methods": ["password"], + "password": { + "user": { + "name": "admin", + "domain": { "id": "default" }, + "password": "<set_your_password_here>" + } + } + }, + "scope": { + "project": { + "name": "admin", + "domain": { "id": "default" } + } + } + } +}' \ + "http://moon_hostname:30006/v3/auth/tokens" ; echo + +curl --header "X-Auth-Token: <token_retrieve_from_keystone>" http://moon_hostname:30001 +curl --header "X-Auth-Token: <token_retrieve_from_keystone>" http://moon_hostname:30001/pdp +curl --header "X-Auth-Token: <token_retrieve_from_keystone>" http://moon_hostname:30001/policies ``` + +3) Use a web browser to navigate to the GUI and enter the login and password of the keystone service: +`firefox http://$MOON_HOST:30002` -#### moon_interface -```bash -docker container run -dti --net moon --hostname interface --name interface wukongsun/moon_interface:v4.1 +4) Use tests Python Scripts +check firstly the Consul service for *Components/Manager*, e.g. +```json +{ + "port": 8082, + "bind": "0.0.0.0", + "hostname": "manager", + "container": "wukongsun/moon_manager:v4.3.1", + "external": { + "port": 30001, + "hostname": "$MOON_HOST" + } +} +``` +*OpenStack/Keystone*: e.g. +```json +{ + "url": "http://keystone:5000/v3", + "user": "admin", + "password": "p4ssw0rd", + "domain": "default", + "project": "admin", + "check_token": false, + "certificate": false, + "external": { + "url": "http://$MOON_HOST:30006/v3" + } +} ``` -#### moon_orchestrator ```bash -docker container run -dti --net moon --hostname orchestrator --name orchestrator wukongsun/moon_orchestrator:v4.1 +python3 populate_default_values.py --consul-host=$MOON_HOST --consul-port=30005 -v scenario/rbac_large.py +python3 send_authz.py --consul-host=$MOON_HOST --consul-port=30005 --authz-host=$MOON_HOST --authz-port=31002 -v scenario/rbac_large.py ``` + +### GUI usage +After authentication, you will see 4 tabs: Project, Models, Policies, PDP: +* *Projects*: configure mapping between Keystone projects and PDP (Policy Decision Point) +* *Models*: configure templates of policies (for example RBAC or MLS) +* *Policies*: applied models or instantiated models ; +on one policy, you map a authorisation model and set subject, objects and action that will +rely on that model +* *PDP*: Policy Decision Point, this is the link between Policies and Keystone Project -### Tests -```bash -docker exec -ti interface /bin/bash -pip3 install pytest -cd /usr/local/lib/python3.5/dist-packages/moon_interface/tests/apitests -pytest -``` +In the following paragraphs, we will add a new user in OpenStack and allow her to list +all VM on the OpenStack platform. + +First, add a new user and a new project in the OpenStack platform: + + openstack user create --password-prompt demo_user + openstack project create demo + DEMO_USER=$(openstack user list | grep demo_user | cut -d " " -f 2) + DEMO_PROJECT=$(openstack project list | grep demo | cut -d " " -f 2) + openstack role add --user $DEMO_USER --project $DEMO_PROJECT admin + +You have to add the same user in the Moon interface: + +1. go to the `Projects` tab in the Moon interface +1. go to the line corresponding to the new project and click to the `Map to a PDP` link +1. select in the combobox the MLS PDP and click `OK` +1. in the Moon interface, go to the `Policy` tab +1. go to the line corresponding to the MLS policy and click on the `actions->edit` button +1. scroll to the `Perimeters` line and click on the `show` link to show the perimeter configuration +1. go to the `Add a subject` line and click on `Add a new perimeter` +1. set the name of that subject to `demo_user` (*the name must be strictly identical*) +1. in the combobox named `Policy list` select the `MLS` policy and click on the `+` button +1. click on the yellow `Add Perimeter` button +1. go to the `Assignment` line and click on the `show` button +1. under the `Add a Assignments Subject` select the MLS policy, +the new user (`demo_user`), the category `subject_category_level` +1. in the `Select a Data` line, choose the `High` scope and click on the `+` link +1. click on the yellow `Create Assignments` button +1. if you go to the OpenStack platform, the `demo_user` is now allow to connect +to the Nova component (test with `openstack server list` connected with the `demo_user`) + + +## Annexes + +### connect to the OpenStack platform + +Here is a shell script to authenticate to the OpenStack platform as `admin`: + + export OS_USERNAME=admin + export OS_PASSWORD=p4ssw0rd + export OS_REGION_NAME=Orange + export OS_TENANT_NAME=admin + export OS_AUTH_URL=http://moon_hostname:30006/v3 + export OS_DOMAIN_NAME=Default + export OS_IDENTITY_API_VERSION=3 + +For the `demo_user`, use: + + export OS_USERNAME=demo_user + export OS_PASSWORD=your_secret_password + export OS_REGION_NAME=Orange + export OS_TENANT_NAME=demo + export OS_AUTH_URL=http://moon_hostname:30006/v3 + export OS_DOMAIN_NAME=Default + export OS_IDENTITY_API_VERSION=3 -## Log -### Get some logs -```bash -docker container ps -docker logs db -docker logs messenger -docker logs keystone -docker logs router -docker logs manager -docker logs interface -``` diff --git a/moonv4/TODO b/moonv4/TODO index 6d0ca9fc..afdadf3c 100644 --- a/moonv4/TODO +++ b/moonv4/TODO @@ -3,30 +3,24 @@ Here is a list of what must be done to have complete version of the Moon platfor Architecture - Add a complete logging system -- Replace moon_orchestrator with Kubernetes ? -- Add a load balancer (HAProxy ?) -- Update Consul with Consul-Template ? -- Develop the Moon hook in Oslo_Policy +- Replace moon_orchestrator with Kubernetes Actions that must be done before the next version: - manage a token/uuid (ie session ID) in the moon_interface component -- update RabbitMQ connections in security_function to have work queues instead of RPC - add a timestamps in moon_router to know if the database has been modified - rename moon_db and moon_utilities because they are not container but just libraries - work on moonclient because it doesn't work with the new data model - check all input from moon_interface (check that input data are correct and safe) - Move @enforce from moon_db to API in Moon_Manager - Need to work on unit tests with the new data model -- Allow to have multiple moon_interface in parallel (needed for load balancing) Bugs to fix: - Connect the authz functionality with the enforce decorator -- The intra_extension ID parameter must be given when the container is ran and not when it is build - (security_function) -- When a container is deleted, the reference is not deleted from CONTAINERS in orchestrator -- All request to moon_interface generally end with a 200 HTTP code even if there is an error +- When adding user or VM in GUI, there is a bug in the backend (manager ?) +- GUI: in the "Projects" tab, move the "Map" link in the "Action" button +- GUI: move tabs in this order : "Models, Policy, PDP, Projects" Other actions: @@ -35,5 +29,5 @@ Other actions: - Write User and administrator documentation - Run unit tests - Add and run integration tests -- moon_orchestrator in a docker -- Add security on RabbitMQ transactions (auth+crypt) +- Need to check if the Moon platform still can retrieve users and roles from Keystone +- Need to retrieve VM from Nova diff --git a/moonv4/bin/README.md b/moonv4/bin/README.md new file mode 100644 index 00000000..3125c468 --- /dev/null +++ b/moonv4/bin/README.md @@ -0,0 +1,5 @@ +# Automated Tools/Scripts + +## moon_utilities_update +- update moon_utilities to PIP: `./moon_utilities_update.sh upload` +- locally update moon_utilities for each moon Python package: `./moon_utilities_update.sh copy`
\ No newline at end of file diff --git a/moonv4/bin/bootstrap.py b/moonv4/bin/bootstrap.py index 85b3adfb..6f2a5e03 100644 --- a/moonv4/bin/bootstrap.py +++ b/moonv4/bin/bootstrap.py @@ -9,18 +9,12 @@ import base64 import mysql.connector import re import subprocess -# import pika -# import pika.credentials -# import pika.exceptions logging.basicConfig(level=logging.INFO) log = logging.getLogger("moon.bootstrap") requests_log = logging.getLogger("requests.packages.urllib3") requests_log.setLevel(logging.WARNING) requests_log.propagate = True -pika_log = logging.getLogger("pika") -pika_log.setLevel(logging.ERROR) -pika_log.propagate = True if len(sys.argv) == 2: if os.path.isfile(sys.argv[1]): @@ -85,7 +79,9 @@ def get(key): def start_consul(data_config): cmd = ["docker", "run", "-d", "--net=moon", "--name=consul", "--hostname=consul", "-p", "8500:8500", "consul"] - output = subprocess.run(cmd) + output = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) if output.returncode != 0: log.info(" ".join(cmd)) log.info(output.returncode) @@ -134,13 +130,14 @@ def start_database(): cmd = ["docker", "run", "-dti", "--net=moon", "--hostname=db", "--name=db", "-e", "MYSQL_ROOT_PASSWORD=p4sswOrd1", "-e", "MYSQL_DATABASE=moon", "-e", "MYSQL_USER=moon", "-e", "MYSQL_PASSWORD=p4sswOrd1", "-p", "3306:3306", "mysql:latest"] - output = subprocess.run(cmd) + output = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) if output.returncode != 0: log.info(cmd) log.error(output.stderr) log.error(output.stdout) raise Exception("Error starting DB container!") - log.info(get("database")) for database in get("database"): database_url = database['url'] match = re.search("(?P<proto>^[\\w+]+):\/\/(?P<user>\\w+):(?P<password>.+)@(?P<host>\\w+):*(?P<port>\\d*)", @@ -161,50 +158,20 @@ def start_database(): continue else: log.info("Database is up, populating it...") - output = subprocess.run(["moon_db_manager", "upgrade"]) + output = subprocess.run(["moon_db_manager", "upgrade"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) if output.returncode != 0: raise Exception("Error populating the database!") break -def wait_for_message_queue(): - for messenger in get("messenger"): - url = messenger['url'] - match = re.search("(?P<proto>^[\\w+]+):\/\/(?P<user>\\w+):(?P<password>.+)@(?P<host>\\w+):?(?P<port>\\d*)/?(?P<virtual_host>\\w+)", - url) - config = match.groupdict() - while True: - try: - connection = pika.BlockingConnection( - pika.ConnectionParameters( - host=config['host'], - port=int(config['port']), - virtual_host=config['virtual_host'], - credentials=pika.credentials.PlainCredentials( - config['user'], - config['password'] - ) - ) - ) - connection.close() - except ( - pika.exceptions.ProbableAuthenticationError, - pika.exceptions.ConnectionClosed, - ConnectionResetError, - pika.exceptions.IncompatibleProtocolError - ): - log.info("Waiting for MessageQueue ({})".format(config["host"])) - time.sleep(1) - continue - else: - log.info("MessageQueue is up") - break - - def start_keystone(): output = subprocess.run(["docker", "run", "-dti", "--net=moon", "--hostname=keystone", "--name=keystone", "-e", "DB_HOST=db", "-e", "DB_PASSWORD_ROOT=p4sswOrd1", "-p", "35357:35357", - "-p", "5000:5000", "keystone:mitaka"]) + "-p", "5000:5000", "keystone:mitaka"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) if output.returncode != 0: raise Exception("Error starting Keystone container!") # TODO: Keystone answers request too quickly @@ -214,6 +181,7 @@ def start_keystone(): for config in get("openstack/keystone"): while True: try: + time.sleep(1) req = requests.get(config["url"]) except requests.exceptions.ConnectionError: log.info("Waiting for Keystone ({})".format(config["url"])) @@ -226,40 +194,42 @@ def start_keystone(): def start_moon(data_config): cmds = [ - ["docker", "run", "-dti", "--net=moon", "--name=wrapper", "--hostname=wrapper", "-p", - "{0}:{0}".format(data_config['components']['wrapper']['port']), - data_config['components']['wrapper']['container']], - ["docker", "run", "-dti", "--net=moon", "--name=interface", "--hostname=interface", "-p", - "{0}:{0}".format(data_config['components']['interface']['port']), - data_config['components']['interface']['container']], - ["docker", "run", "-dti", "--net=moon", "--name=manager", "--hostname=manager", "-p", + # ["docker", "run", "-dti", "--net=moon", "--name=wrapper", "--hostname=wrapper", "-p", + # "{0}:{0}".format(data_config['components']['wrapper']['port']), + # data_config['components']['wrapper']['container']], + ["docker", "run", "-dti", "--net=moon", "--name=manager", + "--hostname=manager", "-p", "{0}:{0}".format(data_config['components']['manager']['port']), data_config['components']['manager']['container']], + ["docker", "run", "-dti", "--net=moon", "--name=interface", + "--hostname=interface", "-p", + "{0}:{0}".format(data_config['components']['interface']['port']), + data_config['components']['interface']['container']], ] for cmd in cmds: - log.warning("Start {} ?".format(cmd[-1])) - answer = input() - if answer.lower() in ("y", "yes", "o", "oui"): - output = subprocess.run(cmd) - if output.returncode != 0: - log.info(" ".join(cmd)) - log.info(output.returncode) - log.error(output.stderr) - log.error(output.stdout) - raise Exception("Error starting {} container!".format(cmd[-1])) + log.warning("Start {}".format(cmd[-1])) + # answer = input() + # if answer.lower() in ("y", "yes", "o", "oui"): + output = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + time.sleep(3) + if output.returncode != 0: + log.info(" ".join(cmd)) + log.info(output.returncode) + log.error(output.stderr) + log.error(output.stdout) + raise Exception("Error starting {} container!".format(cmd[-1])) subprocess.run(["docker", "ps"]) def main(): data_config = search_config_file() - subprocess.run(["docker", "rm", "-f", "consul", "db", "manager", "wrapper", "interface", "authz*"]) + subprocess.run(["docker", "rm", "-f", "consul", "db", "manager", "wrapper", "interface", "authz*", "keystone"]) start_consul(data_config) start_database() start_keystone() start_moon(data_config) - # wait_for_message_queue() - # import moon_orchestrator.server - # moon_orchestrator.server.main() main() diff --git a/moonv4/bin/delete_orchestrator.sh b/moonv4/bin/delete_orchestrator.sh new file mode 100644 index 00000000..95fcfddd --- /dev/null +++ b/moonv4/bin/delete_orchestrator.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +set +x + +kubectl delete -n moon -f kubernetes/templates/moon_orchestrator.yaml +for i in $(kubectl get deployments -n moon | grep wrapper | cut -d " " -f 1 | xargs); do + kubectl delete deployments/$i -n moon; +done +for i in $(kubectl get deployments -n moon | grep interface | cut -d " " -f 1 | xargs); do + kubectl delete deployments/$i -n moon; +done +for i in $(kubectl get deployments -n moon | grep authz | cut -d " " -f 1 | xargs); do + kubectl delete deployments/$i -n moon; +done +for i in $(kubectl get services -n moon | grep wrapper | cut -d " " -f 1 | xargs); do + kubectl delete services/$i -n moon; +done +for i in $(kubectl get services -n moon | grep interface | cut -d " " -f 1 | xargs); do + kubectl delete services/$i -n moon; +done +for i in $(kubectl get services -n moon | grep authz | cut -d " " -f 1 | xargs); do + kubectl delete services/$i -n moon; +done + +if [ "$1" = "build" ]; then + + DOCKER_ARGS="" + + cd moon_manager + docker build -t wukongsun/moon_manager:v4.3.1 . ${DOCKER_ARGS} + if [ "$2" = "push" ]; then + docker push wukongsun/moon_manager:v4.3.1 + fi + cd - + + cd moon_orchestrator + docker build -t wukongsun/moon_orchestrator:v4.3 . ${DOCKER_ARGS} + if [ "$2" = "push" ]; then + docker push wukongsun/moon_orchestrator:v4.3 + fi + cd - + + cd moon_interface + docker build -t wukongsun/moon_interface:v4.3 . ${DOCKER_ARGS} + if [ "$2" = "push" ]; then + docker push wukongsun/moon_interface:v4.3 + fi + cd - + + cd moon_authz + docker build -t wukongsun/moon_authz:v4.3 . ${DOCKER_ARGS} + if [ "$2" = "push" ]; then + docker push wukongsun/moon_authz:v4.3 + fi + cd - + + cd moon_wrapper + docker build -t wukongsun/moon_wrapper:v4.3 . ${DOCKER_ARGS} + if [ "$2" = "push" ]; then + docker push wukongsun/moon_wrapper:v4.3 + fi + cd - +fi diff --git a/moonv4/bin/moon_lib_update.sh b/moonv4/bin/moon_lib_update.sh new file mode 100644 index 00000000..1d9d4cb3 --- /dev/null +++ b/moonv4/bin/moon_lib_update.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# usage: moon_update.sh {build,upload,copy} {db,utilities} <GPG_ID> + +CMD=$1 +COMPONENT=$2 +GPG_ID=$3 + +VERSION=moon_${COMPONENT}-$(grep __version__ moon_${COMPONENT}/moon_${COMPONENT}/__init__.py | cut -d "\"" -f 2) + +cd moon_${COMPONENT} + +python3 setup.py sdist bdist_wheel + +if [ "$CMD" = "upload" ]; then + # Instead of "A0A96E75", use your own GPG ID + rm dist/*.asc 2>/dev/null + gpg --detach-sign -u "${GPG_ID}" -a dist/${VERSION}-py3-none-any.whl + gpg --detach-sign -u "${GPG_ID}" -a dist/${VERSION}.tar.gz + twine upload dist/${VERSION}-py3-none-any.whl dist/${VERSION}-py3-none-any.whl.asc + twine upload dist/${VERSION}.tar.gz dist/${VERSION}.tar.gz.asc +fi + +rm -f ../moon_manager/dist/moon_${COMPONENT}* +rm -f ../moon_orchestrator/dist/moon_${COMPONENT}* +rm -f ../moon_wrapper/dist/moon_${COMPONENT}* +rm -f ../moon_interface/dist/moon_${COMPONENT}* +rm -f ../moon_authz/dist/moon_${COMPONENT}* + + +if [ "$CMD" = "copy" ]; then + mkdir -p ../moon_manager/dist/ 2>/dev/null + cp -v dist/${VERSION}-py3-none-any.whl ../moon_manager/dist/ + mkdir -p ../moon_orchestrator/dist/ 2>/dev/null + cp -v dist/${VERSION}-py3-none-any.whl ../moon_orchestrator/dist/ + mkdir -p ../moon_wrapper/dist/ 2>/dev/null + cp -v dist/${VERSION}-py3-none-any.whl ../moon_wrapper/dist/ + mkdir -p ../moon_interface/dist/ 2>/dev/null + cp -v dist/${VERSION}-py3-none-any.whl ../moon_interface/dist/ + mkdir -p ../moon_authz/dist/ 2>/dev/null + cp -v dist/${VERSION}-py3-none-any.whl ../moon_authz/dist/ +fi + diff --git a/moonv4/conf/moon.conf b/moonv4/conf/moon.conf index 27213f04..a5a40ad2 100644 --- a/moonv4/conf/moon.conf +++ b/moonv4/conf/moon.conf @@ -2,20 +2,6 @@ database: url: mysql+pymysql://moon:p4sswOrd1@db/moon driver: sql -messenger: - url: rabbit://moon:p4sswOrd1@messenger:5672/moon - -docker: - url: tcp://172.88.88.1:2376 - network: moon - -slave: - name: - master: - url: - login: - password: - openstack: keystone: url: http://keystone:5000/v3 @@ -25,31 +11,46 @@ openstack: project: admin check_token: false certificate: false + external: + url: http://keystone:30006/v3 plugins: authz: - container: wukongsun/moon_authz:v4.1 + container: wukongsun/moon_authz:v4.3 + port: 8081 session: container: asteroide/session:latest + port: 8082 components: interface: - port: 8081 + port: 8080 bind: 0.0.0.0 hostname: interface - container: wukongsun/moon_interface:v4.1 + container: wukongsun/moon_interface:v4.3 + orchestrator: + port: 8083 + bind: 0.0.0.0 + hostname: orchestrator + container: wukongsun/moon_orchestrator:v4.3 + external: + port: 30003 + hostname: orchestrator wrapper: port: 8080 bind: 0.0.0.0 hostname: wrapper - container: wukongsun/moon_wrapper:v4.1 + container: wukongsun/moon_wrapper:v4.3.1 timeout: 5 manager: port: 8082 bind: 0.0.0.0 hostname: manager - container: wukongsun/moon_manager:v4.1 - port_start: 38001 + container: wukongsun/moon_manager:v4.3.1 + external: + port: 30001 + hostname: manager + port_start: 31001 logging: version: 1 diff --git a/moonv4/kubernetes/README.md b/moonv4/kubernetes/README.md new file mode 100644 index 00000000..04d54924 --- /dev/null +++ b/moonv4/kubernetes/README.md @@ -0,0 +1,50 @@ + +# Installation + +Choose the right deployment: + +## Minikube installation + +```bash +curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl +chmod +x ./kubectl +sudo mv ./kubectl /usr/local/bin/kubectl +curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.21.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/ +``` + +## Kubeadm installation + +see: https://kubernetes.io/docs/setup/independent/install-kubeadm/ + +```bash +apt-get update && apt-get install -y apt-transport-https +curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - +cat <<EOF >/etc/apt/sources.list.d/kubernetes.list +deb http://apt.kubernetes.io/ kubernetes-xenial main +EOF +apt-get update +apt-get install -y kubelet kubeadm kubectl +``` + +# Platform + +## Creation + +Execute the script : init_k8s.sh + +```bash +sudo bash init_k8s.sh +watch kubectl get po --namespace=kube-system +``` + +Wait until all pods are in "Running" state (crtl-c to stop the watch command) + +## Execution + +Execute the script : start_moon.sh + +```bash +sudo bash start_moon.sh +watch kubectl get po --namespace=moon +``` + diff --git a/moonv4/kubernetes/conf/password_moon.txt b/moonv4/kubernetes/conf/password_moon.txt new file mode 100644 index 00000000..bb9bcf7d --- /dev/null +++ b/moonv4/kubernetes/conf/password_moon.txt @@ -0,0 +1 @@ +p4sswOrd1
\ No newline at end of file diff --git a/moonv4/kubernetes/conf/password_root.txt b/moonv4/kubernetes/conf/password_root.txt new file mode 100644 index 00000000..bb9bcf7d --- /dev/null +++ b/moonv4/kubernetes/conf/password_root.txt @@ -0,0 +1 @@ +p4sswOrd1
\ No newline at end of file diff --git a/moonv4/kubernetes/conf/ports.conf b/moonv4/kubernetes/conf/ports.conf new file mode 100644 index 00000000..487945c0 --- /dev/null +++ b/moonv4/kubernetes/conf/ports.conf @@ -0,0 +1,24 @@ +manager: + port: 8082 + kport: 30001 +gui: + port: 3000 + kport: 30002 +orchestrator: + port: 8083 + kport: 30003 + +consul: + port: 8500 + kport: 30005 +keystone: + port: 5000 + kport: 30006 + +wrapper: + port: 8080 + kport: 30010 +interface: + port: 8080 +authz: + port: 8081 diff --git a/moonv4/kubernetes/init_k8s.sh b/moonv4/kubernetes/init_k8s.sh new file mode 100644 index 00000000..6eb94e78 --- /dev/null +++ b/moonv4/kubernetes/init_k8s.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -x + +sudo kubeadm reset + +sudo swapoff -a + +sudo kubeadm init --pod-network-cidr=192.168.0.0/16 +#sudo kubeadm init --pod-network-cidr=10.244.0.0/16 + +mkdir -p $HOME/.kube +sudo cp -f /etc/kubernetes/admin.conf $HOME/.kube/config +sudo chown $(id -u):$(id -g) $HOME/.kube/config + +kubectl apply -f http://docs.projectcalico.org/v2.4/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml +#kubectl apply -f https://raw.githubusercontent.com/projectcalico/canal/master/k8s-install/1.6/rbac.yaml +#kubectl apply -f https://raw.githubusercontent.com/projectcalico/canal/master/k8s-install/1.6/canal.yaml + +#kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml + +kubectl delete deployment kube-dns --namespace=kube-system +kubectl apply -f kubernetes/templates/kube-dns.yaml + +kubectl taint nodes --all node-role.kubernetes.io/master- + +kubectl proxy& +sleep 5 +echo ========================================= +kubectl get po --namespace=kube-system +echo ========================================= + + diff --git a/moonv4/kubernetes/start_moon.sh b/moonv4/kubernetes/start_moon.sh new file mode 100644 index 00000000..8121e319 --- /dev/null +++ b/moonv4/kubernetes/start_moon.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +set -x + +kubectl create namespace moon +kubectl create configmap moon-config --from-file conf/moon.conf -n moon +kubectl create configmap config --from-file ~/.kube/config -n moon +kubectl create secret generic mysql-root-pass --from-file=kubernetes/conf/password_root.txt -n moon +kubectl create secret generic mysql-pass --from-file=kubernetes/conf/password_moon.txt -n moon + +kubectl create -n moon -f kubernetes/templates/consul.yaml +kubectl create -n moon -f kubernetes/templates/db.yaml +kubectl create -n moon -f kubernetes/templates/keystone.yaml + +echo ========================================= +kubectl get pods -n moon +echo ========================================= + +sleep 10 +kubectl create -n moon -f kubernetes/templates/moon_configuration.yaml + +echo Waiting for jobs moonforming +sleep 5 +kubectl get jobs -n moon +kubectl logs -n moon jobs/moonforming + +sleep 5 + +kubectl create -n moon -f kubernetes/templates/moon_manager.yaml + +sleep 2 + +kubectl create -n moon -f kubernetes/templates/moon_orchestrator.yaml + +kubectl create -n moon -f kubernetes/templates/moon_gui.yaml + + diff --git a/moonv4/kubernetes/templates/consul.yaml b/moonv4/kubernetes/templates/consul.yaml new file mode 100644 index 00000000..f0fb764e --- /dev/null +++ b/moonv4/kubernetes/templates/consul.yaml @@ -0,0 +1,33 @@ +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + namespace: moon + name: consul +spec: + replicas: 1 + template: + metadata: + labels: + app: consul + spec: + hostname: consul + containers: + - name: consul + image: consul:latest + ports: + - containerPort: 8500 +--- + +apiVersion: v1 +kind: Service +metadata: + name: consul + namespace: moon +spec: + ports: + - port: 8500 + targetPort: 8500 + nodePort: 30005 + selector: + app: consul + type: NodePort diff --git a/moonv4/kubernetes/templates/db.yaml b/moonv4/kubernetes/templates/db.yaml new file mode 100644 index 00000000..38418643 --- /dev/null +++ b/moonv4/kubernetes/templates/db.yaml @@ -0,0 +1,84 @@ +#apiVersion: v1 +#kind: PersistentVolume +#metadata: +# name: local-pv-1 +# labels: +# type: local +#spec: +# capacity: +# storage: 5Gi +# accessModes: +# - ReadWriteOnce +# hostPath: +# path: /tmp/data/pv-1 +#--- +# +#apiVersion: v1 +#kind: PersistentVolumeClaim +#metadata: +# name: mysql-pv-claim +# labels: +# platform: moon +# app: db +#spec: +# accessModes: +# - ReadWriteOnce +# resources: +# requests: +# storage: 5Gi +#--- + +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + namespace: moon + name: db +spec: + replicas: 1 + strategy: + type: Recreate + template: + metadata: + labels: + app: db + spec: + containers: + - name: db + image: mysql:latest + env: + - name: MYSQL_DATABASE + value: "moon" + - name: MYSQL_USER + value: "moon" + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-pass + key: password_moon.txt + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-root-pass + key: password_root.txt + ports: + - containerPort: 3306 + name: mysql +# volumeMounts: +# - name: mysql-persistent-storage +# mountPath: /var/lib/mysql +# volumes: +# - name: mysql-persistent-storage +# persistentVolumeClaim: +# claimName: mysql-pv-claim +--- +apiVersion: v1 +kind: Service +metadata: + namespace: moon + name: db +spec: + ports: + - port: 3306 + selector: + app: db +---
\ No newline at end of file diff --git a/moonv4/kubernetes/templates/keystone.yaml b/moonv4/kubernetes/templates/keystone.yaml new file mode 100644 index 00000000..9d188758 --- /dev/null +++ b/moonv4/kubernetes/templates/keystone.yaml @@ -0,0 +1,39 @@ +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + namespace: moon + name: keystone +spec: + replicas: 1 + template: + metadata: + labels: + app: keystone + spec: + hostname: keystone + containers: + - name: keystone + image: asteroide/keystone:pike + env: + - name: KEYSTONE_HOSTNAME + value: "127.0.0.1" + - name: KEYSTONE_PORT + value: "30006" + ports: + - containerPort: 35357 + containerPort: 5000 +--- + +apiVersion: v1 +kind: Service +metadata: + name: keystone + namespace: moon +spec: + ports: + - port: 5000 + targetPort: 5000 + nodePort: 30006 + selector: + app: keystone + type: NodePort diff --git a/moonv4/kubernetes/templates/kube-dns.yaml b/moonv4/kubernetes/templates/kube-dns.yaml new file mode 100644 index 00000000..c8f18fd8 --- /dev/null +++ b/moonv4/kubernetes/templates/kube-dns.yaml @@ -0,0 +1,183 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + deployment.kubernetes.io/revision: "2" + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"extensions/v1beta1","kind":"Deployment","metadata":{"annotations":{"deployment.kubernetes.io/revision":"1"},"creationTimestamp":"2017-10-30T09:03:59Z","generation":1,"labels":{"k8s-app":"kube-dns"},"name":"kube-dns","namespace":"kube-system","resourceVersion":"556","selfLink":"/apis/extensions/v1beta1/namespaces/kube-system/deployments/kube-dns","uid":"4433b709-bd51-11e7-a055-80fa5b15034a"},"spec":{"replicas":1,"selector":{"matchLabels":{"k8s-app":"kube-dns"}},"strategy":{"rollingUpdate":{"maxSurge":"10%","maxUnavailable":0},"type":"RollingUpdate"},"template":{"metadata":{"creationTimestamp":null,"labels":{"k8s-app":"kube-dns"}},"spec":{"affinity":{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"beta.kubernetes.io/arch","operator":"In","values":["amd64"]}]}]}}},"containers":[{"args":["--domain=cluster.local.","--dns-port=10053","--config-dir=/kube-dns-config","--v=2"],"env":[{"name":"PROMETHEUS_PORT","value":"10055"}],"image":"gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.5","imagePullPolicy":"IfNotPresent","livenessProbe":{"failureThreshold":5,"httpGet":{"path":"/healthcheck/kubedns","port":10054,"scheme":"HTTP"},"initialDelaySeconds":60,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"name":"kubedns","ports":[{"containerPort":10053,"name":"dns-local","protocol":"UDP"},{"containerPort":10053,"name":"dns-tcp-local","protocol":"TCP"},{"containerPort":10055,"name":"metrics","protocol":"TCP"}],"readinessProbe":{"failureThreshold":3,"httpGet":{"path":"/readiness","port":8081,"scheme":"HTTP"},"initialDelaySeconds":3,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"resources":{"limits":{"memory":"170Mi"},"requests":{"cpu":"100m","memory":"70Mi"}},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","volumeMounts":[{"mountPath":"/kube-dns-config","name":"kube-dns-config"}]},{"args":["-v=2","-logtostderr","-configDir=/etc/k8s/dns/dnsmasq-nanny","-restartDnsmasq=true","--","-k","--cache-size=1000","--log-facility=-","--server=/cluster.local/127.0.0.1#10053","--server=/in-addr.arpa/127.0.0.1#10053","--server=/ip6.arpa/127.0.0.1#10053","--server=8.8.8.8"],"image":"gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.5","imagePullPolicy":"IfNotPresent","livenessProbe":{"failureThreshold":5,"httpGet":{"path":"/healthcheck/dnsmasq","port":10054,"scheme":"HTTP"},"initialDelaySeconds":60,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"name":"dnsmasq","ports":[{"containerPort":53,"name":"dns","protocol":"UDP"},{"containerPort":53,"name":"dns-tcp","protocol":"TCP"}],"resources":{"requests":{"cpu":"150m","memory":"20Mi"}},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","volumeMounts":[{"mountPath":"/etc/k8s/dns/dnsmasq-nanny","name":"kube-dns-config"}]},{"args":["--v=2","--logtostderr","--probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local,5,A","--probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local,5,A"],"image":"gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.5","imagePullPolicy":"IfNotPresent","livenessProbe":{"failureThreshold":5,"httpGet":{"path":"/metrics","port":10054,"scheme":"HTTP"},"initialDelaySeconds":60,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"name":"sidecar","ports":[{"containerPort":10054,"name":"metrics","protocol":"TCP"}],"resources":{"requests":{"cpu":"10m","memory":"20Mi"}},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File"}],"dnsPolicy":"Default","restartPolicy":"Always","schedulerName":"default-scheduler","securityContext":{},"serviceAccount":"kube-dns","serviceAccountName":"kube-dns","terminationGracePeriodSeconds":30,"tolerations":[{"key":"CriticalAddonsOnly","operator":"Exists"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/master"}],"volumes":[{"configMap":{"defaultMode":420,"name":"kube-dns","optional":true},"name":"kube-dns-config"}]}}},"status":{"availableReplicas":1,"conditions":[{"lastTransitionTime":"2017-10-30T09:05:11Z","lastUpdateTime":"2017-10-30T09:05:11Z","message":"Deployment has minimum availability.","reason":"MinimumReplicasAvailable","status":"True","type":"Available"}],"observedGeneration":1,"readyReplicas":1,"replicas":1,"updatedReplicas":1}} + creationTimestamp: 2017-10-30T09:03:59Z + generation: 2 + labels: + k8s-app: kube-dns + name: kube-dns + namespace: kube-system + resourceVersion: "300076" + selfLink: /apis/extensions/v1beta1/namespaces/kube-system/deployments/kube-dns + uid: 4433b709-bd51-11e7-a055-80fa5b15034a +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: kube-dns + strategy: + rollingUpdate: + maxSurge: 10% + maxUnavailable: 0 + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + k8s-app: kube-dns + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - amd64 + containers: + - args: + - --domain=cluster.local. + - --dns-port=10053 + - --config-dir=/kube-dns-config + - --v=2 + env: + - name: PROMETHEUS_PORT + value: "10055" + image: gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.5 + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthcheck/kubedns + port: 10054 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: kubedns + ports: + - containerPort: 10053 + name: dns-local + protocol: UDP + - containerPort: 10053 + name: dns-tcp-local + protocol: TCP + - containerPort: 10055 + name: metrics + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /readiness + port: 8081 + scheme: HTTP + initialDelaySeconds: 3 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + resources: + limits: + memory: 340Mi + requests: + cpu: 200m + memory: 140Mi + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /kube-dns-config + name: kube-dns-config + - args: + - -v=2 + - -logtostderr + - -configDir=/etc/k8s/dns/dnsmasq-nanny + - -restartDnsmasq=true + - -- + - -k + - --dns-forward-max=300 + - --cache-size=1000 + - --log-facility=- + - --server=/cluster.local/127.0.0.1#10053 + - --server=/in-addr.arpa/127.0.0.1#10053 + - --server=/ip6.arpa/127.0.0.1#10053 + - --server=8.8.8.8 + image: gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.5 + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthcheck/dnsmasq + port: 10054 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: dnsmasq + ports: + - containerPort: 53 + name: dns + protocol: UDP + - containerPort: 53 + name: dns-tcp + protocol: TCP + resources: + requests: + cpu: 150m + memory: 20Mi + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /etc/k8s/dns/dnsmasq-nanny + name: kube-dns-config + - args: + - --v=2 + - --logtostderr + - --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local,5,A + - --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local,5,A + image: gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.5 + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 5 + httpGet: + path: /metrics + port: 10054 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: sidecar + ports: + - containerPort: 10054 + name: metrics + protocol: TCP + resources: + requests: + cpu: 10m + memory: 20Mi + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: Default + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + serviceAccount: kube-dns + serviceAccountName: kube-dns + terminationGracePeriodSeconds: 30 + tolerations: + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/master + volumes: + - configMap: + defaultMode: 420 + name: kube-dns + optional: true + name: kube-dns-config diff --git a/moonv4/kubernetes/templates/moon_configuration.yaml b/moonv4/kubernetes/templates/moon_configuration.yaml new file mode 100644 index 00000000..3bcaa533 --- /dev/null +++ b/moonv4/kubernetes/templates/moon_configuration.yaml @@ -0,0 +1,25 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: moonforming + namespace: moon +spec: + template: + metadata: + name: moonforming + spec: + containers: + - name: moonforming + image: asteroide/moonforming:v1.3 + env: + - name: POPULATE_ARGS + value: "--verbose" # debug mode: --debug + volumeMounts: + - name: config-volume + mountPath: /etc/moon + volumes: + - name: config-volume + configMap: + name: moon-config + restartPolicy: Never + #backoffLimit: 4
\ No newline at end of file diff --git a/moonv4/kubernetes/templates/moon_gui.yaml b/moonv4/kubernetes/templates/moon_gui.yaml new file mode 100644 index 00000000..2d355216 --- /dev/null +++ b/moonv4/kubernetes/templates/moon_gui.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + namespace: moon + name: gui +spec: + replicas: 1 + template: + metadata: + labels: + app: gui + spec: + hostname: gui + containers: + - name: gui + image: wukongsun/moon_gui:v4.3.1 + env: + - name: MANAGER_HOST + value: "127.0.0.1" + - name: MANAGER_PORT + value: "30001" + - name: KEYSTONE_HOST + value: "127.0.0.1" + - name: KEYSTONE_PORT + value: "30006" + ports: + - containerPort: 80 +--- + +apiVersion: v1 +kind: Service +metadata: + name: gui + namespace: moon +spec: + ports: + - port: 80 + targetPort: 80 + nodePort: 30002 + selector: + app: gui + type: NodePort diff --git a/moonv4/kubernetes/templates/moon_manager.yaml b/moonv4/kubernetes/templates/moon_manager.yaml new file mode 100644 index 00000000..9d4a09a8 --- /dev/null +++ b/moonv4/kubernetes/templates/moon_manager.yaml @@ -0,0 +1,33 @@ +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: manager + namespace: moon +spec: + replicas: 3 + template: + metadata: + labels: + app: manager + spec: + hostname: manager + containers: + - name: manager + image: wukongsun/moon_manager:v4.3.1 + ports: + - containerPort: 8082 +--- + +apiVersion: v1 +kind: Service +metadata: + name: manager + namespace: moon +spec: + ports: + - port: 8082 + targetPort: 8082 + nodePort: 30001 + selector: + app: manager + type: NodePort diff --git a/moonv4/kubernetes/templates/moon_orchestrator.yaml b/moonv4/kubernetes/templates/moon_orchestrator.yaml new file mode 100644 index 00000000..419f2d52 --- /dev/null +++ b/moonv4/kubernetes/templates/moon_orchestrator.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + namespace: moon + name: orchestrator +spec: + replicas: 1 + template: + metadata: + labels: + app: orchestrator + spec: + hostname: orchestrator + containers: + - name: orchestrator + image: wukongsun/moon_orchestrator:v4.3 + ports: + - containerPort: 8083 + volumeMounts: + - name: config-volume + mountPath: /root/.kube + volumes: + - name: config-volume + configMap: + name: config +--- + +apiVersion: v1 +kind: Service +metadata: + name: orchestrator + namespace: moon +spec: + ports: + - port: 8083 + targetPort: 8083 + nodePort: 30003 + selector: + app: orchestrator + type: NodePort diff --git a/moonv4/moon_authz/Dockerfile b/moonv4/moon_authz/Dockerfile index 6ecc8f2d..4189c333 100644 --- a/moonv4/moon_authz/Dockerfile +++ b/moonv4/moon_authz/Dockerfile @@ -1,13 +1,12 @@ FROM ubuntu:latest -ENV UUID=null - RUN apt update && apt install python3.5 python3-pip -y -RUN pip3 install moon_utilities moon_db pip --upgrade +RUN pip3 install pip --upgrade ADD . /root WORKDIR /root/ -RUN pip3 install -r requirements.txt +RUN pip3 install -r requirements.txt --upgrade +#RUN pip3 install /root/dist/* --upgrade RUN pip3 install . CMD ["python3", "-m", "moon_authz"]
\ No newline at end of file diff --git a/moonv4/moon_authz/LICENSE b/moonv4/moon_authz/LICENSE index 4143aac2..d6456956 100644 --- a/moonv4/moon_authz/LICENSE +++ b/moonv4/moon_authz/LICENSE @@ -174,31 +174,29 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/moonv4/moon_authz/moon_authz/__main__.py b/moonv4/moon_authz/moon_authz/__main__.py index be483962..699c008c 100644 --- a/moonv4/moon_authz/moon_authz/__main__.py +++ b/moonv4/moon_authz/moon_authz/__main__.py @@ -1,3 +1,4 @@ from moon_authz.server import main -main() +server = main() +server.run() diff --git a/moonv4/moon_authz/moon_authz/api/authorization.py b/moonv4/moon_authz/moon_authz/api/authorization.py index 94f1e13d..caa41082 100644 --- a/moonv4/moon_authz/moon_authz/api/authorization.py +++ b/moonv4/moon_authz/moon_authz/api/authorization.py @@ -3,17 +3,15 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -import hashlib +import binascii import itertools -from oslo_log import log as logging -from oslo_config import cfg -import oslo_messaging -from moon_utilities.security_functions import call, Context, notify -from moon_utilities.misc import get_uuid_from_name +import pickle +from uuid import uuid4 +import logging from moon_utilities import exceptions -from moon_db.core import PDPManager -from moon_db.core import ModelManager -from moon_db.core import PolicyManager +import flask +from flask import request +from flask_restful import Resource # TODO (asteroide): # - end the dev of the context @@ -21,43 +19,85 @@ from moon_db.core import PolicyManager # - call the next security function # - call the master if an element is absent -LOG = logging.getLogger(__name__) -CONF = cfg.CONF +LOG = logging.getLogger("moon.api." + __name__) -class Authorization(object): +class Authz(Resource): """ - Retrieve the current status of all components. + Endpoint for authz requests """ + __urls__ = ( + "/authz", + "/authz/", + "/authz/<string:uuid>/<string:subject_name>/<string:object_name>/<string:action_name>", + ) __version__ = "0.1.0" pdp_id = None meta_rule_id = None keystone_project_id = None payload = None - def __init__(self, component_desc): - self.component_id = component_desc - LOG.info("ext={}".format(component_desc)) - self.filter_rule = oslo_messaging.NotificationFilter( - event_type='^authz$', - context={'container_id': "\w+_"+hashlib.sha224(component_desc.encode("utf-8")).hexdigest()} - ) + def __init__(self, **kwargs): + component_data = kwargs.get("component_data", {}) + self.component_id = component_data['component_id'] + self.pdp_id = component_data['pdp_id'] + self.meta_rule_id = component_data['meta_rule_id'] + self.keystone_project_id = component_data['keystone_project_id'] + self.cache = kwargs.get("cache") + self.context = None - for _id_value in component_desc.split("_"): - _type, _id = _id_value.split(":") - if _type == "pdp": - self.pdp_id = _id - elif _type == "metarule": - self.meta_rule_id = _id - elif _type == "project": - self.keystone_project_id = _id + def post(self, uuid=None, subject_name=None, object_name=None, action_name=None): + """Get a response on an authorization request - def __check_rules(self, context): + :param uuid: uuid of a tenant or an intra_extension + :param subject_name: name of the subject or the request + :param object_name: name of the object + :param action_name: name of the action + :return: { + "args": {}, + "ctx": { + "action_name": "4567", + "id": "123456", + "method": "authz", + "object_name": "234567", + "subject_name": "123456", + "user_id": "admin" + }, + "error": { + "code": 500, + "description": "", + "title": "Moon Error" + }, + "intra_extension_id": "123456", + "result": false + } + :internal_api: authz + """ + self.context = pickle.loads(request.data) + self.context.set_cache(self.cache) + self.context.increment_index() + self.run() + self.context.delete_cache() + response = flask.make_response(pickle.dumps(self.context)) + response.headers['content-type'] = 'application/octet-stream' + return response + + def run(self): + LOG.info("self.context.pdp_set={}".format(self.context.pdp_set)) + result, message = self.__check_rules() + if result: + return self.__exec_instructions(result) + else: + self.context.current_state = "deny" + # self.__exec_next_state(result) + return + + def __check_rules(self): scopes_list = list() - current_header_id = context['headers'][context['index']] - Context.update_target(context) - current_pdp = context['pdp_set'][current_header_id] + current_header_id = self.context.headers[self.context.index] + # Context.update_target(context) + current_pdp = self.context.pdp_set[current_header_id] category_list = list() category_list.extend(current_pdp["meta_rules"]["subject_categories"]) category_list.extend(current_pdp["meta_rules"]["object_categories"]) @@ -65,13 +105,12 @@ class Authorization(object): for category in category_list: scope = list(current_pdp['target'][category]) scopes_list.append(scope) - policy_id = PolicyManager.get_policy_from_meta_rules("admin", current_header_id) - rules = PolicyManager.get_rules(user_id="admin", - policy_id=policy_id, - meta_rule_id=current_header_id) + # policy_id = self.cache.get_policy_from_meta_rules("admin", current_header_id) + for item in itertools.product(*scopes_list): req = list(item) - for rule in rules['rules']: + for rule in self.cache.rules[self.context.current_policy_id]["rules"]: + LOG.info("rule={}".format(rule)) if req == rule['rule']: return rule['instructions'], "" LOG.warning("No rule match the request...") @@ -84,13 +123,12 @@ class Authorization(object): except ValueError: LOG.error("Cannot understand value in instruction ({})".format(target)) return False - pdp_set = self.payload["authz_context"]['pdp_set'] - for meta_rule_id in self.payload["authz_context"]['pdp_set']: - policy_id = PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id) + # pdp_set = self.payload["authz_context"]['pdp_set'] + for meta_rule_id in self.context.pdp_set: if meta_rule_id == "effect": continue - if pdp_set[meta_rule_id]["meta_rules"]["name"] == policy_name: - for category_id, category_value in ModelManager.get_subject_categories("admin").items(): + if self.context.pdp_set[meta_rule_id]["meta_rules"]["name"] == policy_name: + for category_id, category_value in self.cache.subject_categories.items(): if category_value["name"] == "role": subject_category_id = category_id break @@ -131,95 +169,96 @@ class Authorization(object): return self.payload["container_chaining"][index] def __update_headers(self, name): - context = self.payload["authz_context"] - for meta_rule_id, meta_rule_value in context["pdp_set"].items(): + # context = self.payload["authz_context"] + for meta_rule_id, meta_rule_value in self.context.pdp_set.items(): if meta_rule_id == "effect": continue if meta_rule_value["meta_rules"]["name"] == name: - self.payload["authz_context"]['headers'].append(meta_rule_id) + self.context.headers.append(meta_rule_id) return True return False - def __exec_next_state(self, rule_found): - index = self.payload["authz_context"]['index'] - current_meta_rule = self.payload["authz_context"]['headers'][index] - current_container = self.__get_container_from_meta_rule(current_meta_rule) - current_container_genre = current_container["genre"] - try: - next_meta_rule = self.payload["authz_context"]['headers'][index+1] - except IndexError: - next_meta_rule = None - if current_container_genre == "authz": - if rule_found: - return self.__return_to_router() - pass - if next_meta_rule: - # next will be session if current is deny and session is unset - if self.payload["authz_context"]['pdp_set'][next_meta_rule]['effect'] == "unset": - return notify( - request_id=self.payload["authz_context"]["request_id"], - container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], - payload=self.payload) - # next will be delegation if current is deny and session is passed or deny and delegation is unset - else: - LOG.error("Delegation is not developed!") + # def __exec_next_state(self, rule_found): + # index = self.context.index + # current_meta_rule = self.context.headers[index] + # current_container = self.__get_container_from_meta_rule(current_meta_rule) + # current_container_genre = current_container["genre"] + # try: + # next_meta_rule = self.context.headers[index + 1] + # except IndexError: + # next_meta_rule = None + # if current_container_genre == "authz": + # if rule_found: + # return True + # pass + # if next_meta_rule: + # # next will be session if current is deny and session is unset + # if self.payload["authz_context"]['pdp_set'][next_meta_rule]['effect'] == "unset": + # return notify( + # request_id=self.payload["authz_context"]["request_id"], + # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], + # payload=self.payload) + # # next will be delegation if current is deny and session is passed or deny and delegation is unset + # else: + # LOG.error("Delegation is not developed!") + # + # else: + # # else next will be None and the request is sent to router + # return self.__return_to_router() + # elif current_container_genre == "session": + # pass + # # next will be next container in headers if current is passed + # if self.payload["authz_context"]['pdp_set'][current_meta_rule]['effect'] == "passed": + # return notify( + # request_id=self.payload["authz_context"]["request_id"], + # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], + # payload=self.payload) + # # next will be None if current is grant and the request is sent to router + # else: + # return self.__return_to_router() + # elif current_container_genre == "delegation": + # LOG.error("Delegation is not developed!") + # # next will be authz if current is deny + # # next will be None if current is grant and the request is sent to router - else: - # else next will be None and the request is sent to router - return self.__return_to_router() - elif current_container_genre == "session": - pass - # next will be next container in headers if current is passed - if self.payload["authz_context"]['pdp_set'][current_meta_rule]['effect'] == "passed": - return notify( - request_id=self.payload["authz_context"]["request_id"], - container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], - payload=self.payload) - # next will be None if current is grant and the request is sent to router - else: - return self.__return_to_router() - elif current_container_genre == "delegation": - LOG.error("Delegation is not developed!") - # next will be authz if current is deny - # next will be None if current is grant and the request is sent to router - - def __return_to_router(self): - call(endpoint="security_router", - ctx={"id": self.component_id, - "call_master": False, - "method": "return_authz", - "request_id": self.payload["authz_context"]["request_id"]}, - method="route", - args=self.payload["authz_context"]) + # def __return_to_router(self): + # call(endpoint="security_router", + # ctx={"id": self.component_id, + # "call_master": False, + # "method": "return_authz", + # "request_id": self.payload["authz_context"]["request_id"]}, + # method="route", + # args=self.payload["authz_context"]) def __exec_instructions(self, instructions): - current_header_id = self.payload["authz_context"]['headers'][self.payload["authz_context"]['index']] for instruction in instructions: for key in instruction: if key == "decision": if instruction["decision"] == "grant": - self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "grant" - self.__return_to_router() + self.context.current_state = "grant" + LOG.info("__exec_instructions True {}".format( + self.context.current_state)) + return True else: - self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = instruction["decision"] + self.context.current_state = instruction["decision"].lower() elif key == "chain": result = self.__update_headers(**instruction["chain"]) if not result: - self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "deny" + self.context.current_state = "deny" else: - self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "passed" + self.context.current_state = "passed" elif key == "update": result = self.__update_subject_category_in_policy(**instruction["update"]) if not result: - self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "deny" + self.context.current_state = "deny" else: - self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "passed" - # LOG.info("__exec_instructions {}".format(self.payload["authz_context"])) + self.context.current_state = "passed" + LOG.info("__exec_instructions False {}".format(self.context.current_state)) def __update_current_request(self): index = self.payload["authz_context"]["index"] current_header_id = self.payload["authz_context"]['headers'][index] - previous_header_id = self.payload["authz_context"]['headers'][index-1] + previous_header_id = self.payload["authz_context"]['headers'][index - 1] current_policy_id = PolicyManager.get_policy_from_meta_rules("admin", current_header_id) previous_policy_id = PolicyManager.get_policy_from_meta_rules("admin", previous_header_id) # FIXME (asteroide): must change those lines to be ubiquitous against any type of policy @@ -233,11 +272,11 @@ class Authorization(object): break for assignment_id, assignment_value in PolicyManager.get_subject_assignments( "admin", previous_policy_id, subject, subject_category_id).items(): - for data_id in assignment_value["assignments"]: - data = PolicyManager.get_subject_data("admin", previous_policy_id, data_id, subject_category_id) - for _data in data: - for key, value in _data["data"].items(): - role_names.append(value["name"]) + for data_id in assignment_value["assignments"]: + data = PolicyManager.get_subject_data("admin", previous_policy_id, data_id, subject_category_id) + for _data in data: + for key, value in _data["data"].items(): + role_names.append(value["name"]) new_role_ids = [] for perimeter_id, perimeter_value in PolicyManager.get_objects("admin", current_policy_id).items(): if perimeter_value["name"] in role_names: @@ -251,72 +290,65 @@ class Authorization(object): self.payload["authz_context"]['current_request']['object'] = new_role_ids[0] self.payload["authz_context"]['current_request']['action'] = perimeter_id elif self.payload["authz_context"]['pdp_set'][current_header_id]['meta_rules']['name'] == "rbac": - self.payload["authz_context"]['current_request']['subject'] = self.payload["authz_context"]['initial_request']['subject'] - self.payload["authz_context"]['current_request']['object'] = self.payload["authz_context"]['initial_request']['object'] - self.payload["authz_context"]['current_request']['action'] = self.payload["authz_context"]['initial_request']['action'] + self.payload["authz_context"]['current_request']['subject'] = \ + self.payload["authz_context"]['initial_request']['subject'] + self.payload["authz_context"]['current_request']['object'] = \ + self.payload["authz_context"]['initial_request']['object'] + self.payload["authz_context"]['current_request']['action'] = \ + self.payload["authz_context"]['initial_request']['action'] - def critical(self, ctxt, publisher_id, event_type, payload, metadata): - """This is the authz endpoint - but due to the oslo_messaging notification architecture, we must call it "critical" - - :param ctxt: context of the request - :param publisher_id: ID of the publisher - :param event_type: type of event ("authz" here) - :param payload: content of the authz request - :param metadata: metadata of the notification - :return: result of the authorization for the current component - """ - LOG.info("calling authz {} {}".format(ctxt, payload)) - self.keystone_project_id = payload["id"] - self.payload = payload + def get_authz(self): + # self.keystone_project_id = payload["id"] + # LOG.info("get_authz {}".format(payload)) + # self.payload = payload try: - if "authz_context" not in payload: - try: - self.payload["authz_context"] = Context(self.keystone_project_id, - self.payload["subject_name"], - self.payload["object_name"], - self.payload["action_name"], - self.payload["request_id"]).to_dict() - except exceptions.SubjectUnknown: - ctx = { - "subject_name": self.payload["subject_name"], - "object_name": self.payload["object_name"], - "action_name": self.payload["action_name"], - } - call("moon_manager", method="update_from_master", ctx=ctx, args={}) - self.payload["authz_context"] = Context(self.keystone_project_id, - self.payload["subject_name"], - self.payload["object_name"], - self.payload["action_name"], - self.payload["request_id"]).to_dict() - except exceptions.ObjectUnknown: - ctx = { - "subject_name": self.payload["subject_name"], - "object_name": self.payload["object_name"], - "action_name": self.payload["action_name"], - } - call("moon_manager", method="update_from_master", ctx=ctx, args={}) - self.payload["authz_context"] = Context(self.keystone_project_id, - self.payload["subject_name"], - self.payload["object_name"], - self.payload["action_name"], - self.payload["request_id"]).to_dict() - except exceptions.ActionUnknown: - ctx = { - "subject_name": self.payload["subject_name"], - "object_name": self.payload["object_name"], - "action_name": self.payload["action_name"], - } - call("moon_manager", method="update_from_master", ctx=ctx, args={}) - self.payload["authz_context"] = Context(self.keystone_project_id, - self.payload["subject_name"], - self.payload["object_name"], - self.payload["action_name"], - self.payload["request_id"]).to_dict() - self.__update_container_chaining() - else: - self.payload["authz_context"]["index"] += 1 - self.__update_current_request() + # if "authz_context" not in payload: + # try: + # self.payload["authz_context"] = Context(self.keystone_project_id, + # self.payload["subject_name"], + # self.payload["object_name"], + # self.payload["action_name"], + # self.payload["request_id"]).to_dict() + # except exceptions.SubjectUnknown: + # ctx = { + # "subject_name": self.payload["subject_name"], + # "object_name": self.payload["object_name"], + # "action_name": self.payload["action_name"], + # } + # call("moon_manager", method="update_from_master", ctx=ctx, args={}) + # self.payload["authz_context"] = Context(self.keystone_project_id, + # self.payload["subject_name"], + # self.payload["object_name"], + # self.payload["action_name"], + # self.payload["request_id"]).to_dict() + # except exceptions.ObjectUnknown: + # ctx = { + # "subject_name": self.payload["subject_name"], + # "object_name": self.payload["object_name"], + # "action_name": self.payload["action_name"], + # } + # call("moon_manager", method="update_from_master", ctx=ctx, args={}) + # self.payload["authz_context"] = Context(self.keystone_project_id, + # self.payload["subject_name"], + # self.payload["object_name"], + # self.payload["action_name"], + # self.payload["request_id"]).to_dict() + # except exceptions.ActionUnknown: + # ctx = { + # "subject_name": self.payload["subject_name"], + # "object_name": self.payload["object_name"], + # "action_name": self.payload["action_name"], + # } + # call("moon_manager", method="update_from_master", ctx=ctx, args={}) + # self.payload["authz_context"] = Context(self.keystone_project_id, + # self.payload["subject_name"], + # self.payload["object_name"], + # self.payload["action_name"], + # self.payload["request_id"]).to_dict() + # self.__update_container_chaining() + # else: + # self.payload["authz_context"]["index"] += 1 + # self.__update_current_request() result, message = self.__check_rules(self.payload["authz_context"]) current_header_id = self.payload["authz_context"]['headers'][self.payload["authz_context"]['index']] if result: @@ -327,7 +359,7 @@ class Authorization(object): return {"authz": result, "error": message, "pdp_id": self.pdp_id, - "ctx": ctxt, "args": self.payload} + "args": self.payload} except Exception as e: try: LOG.error(self.payload["authz_context"]) @@ -337,5 +369,8 @@ class Authorization(object): return {"authz": False, "error": str(e), "pdp_id": self.pdp_id, - "ctx": ctxt, "args": self.payload} + "args": self.payload} + def head(self, uuid=None, subject_name=None, object_name=None, action_name=None): + LOG.info("HEAD request") + return "", 200
\ No newline at end of file diff --git a/moonv4/moon_authz/moon_authz/api/generic.py b/moonv4/moon_authz/moon_authz/api/generic.py index db61188b..66169b15 100644 --- a/moonv4/moon_authz/moon_authz/api/generic.py +++ b/moonv4/moon_authz/moon_authz/api/generic.py @@ -2,27 +2,130 @@ # 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'. +""" +Those API are helping API used to manage the Moon platform. +""" +from flask_restful import Resource, request +from oslo_log import log as logging +import moon_authz.api +from moon_utilities.security_functions import check_auth -class Status(object): +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.authz.api." + __name__) + + +class Status(Resource): """ - Retrieve the current status of all components. + Endpoint for status requests """ - __version__ = "0.1.0" + __urls__ = ("/status", "/status/", "/status/<string:component_id>") - def get_status(self, ctx, args): - return {"status": "Running"} + def get(self, component_id=None): + """Retrieve status of all components + :return: { + "orchestrator": { + "status": "Running" + }, + "security_router": { + "status": "Running" + } + } + """ + raise NotImplemented -class Logs(object): + +class Logs(Resource): """ - Retrieve the current status of all components. + Endpoint for logs requests """ - __version__ = "0.1.0" + __urls__ = ("/logs", "/logs/", "/logs/<string:component_id>") + + def get(self, component_id=None): + """Get logs from the Moon platform + + :param component_id: the ID of the component your are looking for (optional) + :return: [ + "2015-04-15-13:45:20 + "2015-04-15-13:45:21 + "2015-04-15-13:45:22 + "2015-04-15-13:45:23 + ] + """ + filter_str = request.args.get('filter', '') + from_str = request.args.get('from', '') + to_str = request.args.get('to', '') + event_number = request.args.get('event_number', '') + try: + event_number = int(event_number) + except ValueError: + event_number = None + args = dict() + args["filter"] = filter_str + args["from"] = from_str + args["to"] = to_str + args["event_number"] = event_number + + raise NotImplemented + + +class API(Resource): + """ + Endpoint for API requests + """ - def get_logs(self, ctx, args): - return {"error": "NotImplemented"} + __urls__ = ( + "/api", + "/api/", + "/api/<string:group_id>", + "/api/<string:group_id>/", + "/api/<string:group_id>/<string:endpoint_id>") + @check_auth + def get(self, group_id="", endpoint_id="", user_id=""): + """Retrieve all API endpoints or a specific endpoint if endpoint_id is given + :param group_id: the name of one existing group (ie generic, ...) + :param endpoint_id: the name of one existing component (ie Logs, Status, ...) + :return: { + "group_name": { + "endpoint_name": { + "description": "a description", + "methods": { + "get": "description of the HTTP method" + }, + "urls": ('/api', '/api/', '/api/<string:endpoint_id>') + } + } + """ + __methods = ("get", "post", "put", "delete", "options", "patch") + api_list = filter(lambda x: "__" not in x, dir(moon_authz.api)) + api_desc = dict() + for api_name in api_list: + api_desc[api_name] = {} + group_api_obj = eval("moon_interface.api.{}".format(api_name)) + api_desc[api_name]["description"] = group_api_obj.__doc__ + if "__version__" in dir(group_api_obj): + api_desc[api_name]["version"] = group_api_obj.__version__ + object_list = list(filter(lambda x: "__" not in x, dir(group_api_obj))) + for obj in map(lambda x: eval("moon_interface.api.{}.{}".format(api_name, x)), object_list): + if "__urls__" in dir(obj): + api_desc[api_name][obj.__name__] = dict() + api_desc[api_name][obj.__name__]["urls"] = obj.__urls__ + api_desc[api_name][obj.__name__]["methods"] = dict() + for _method in filter(lambda x: x in __methods, dir(obj)): + docstring = eval("moon_interface.api.{}.{}.{}.__doc__".format(api_name, obj.__name__, _method)) + api_desc[api_name][obj.__name__]["methods"][_method] = docstring + api_desc[api_name][obj.__name__]["description"] = str(obj.__doc__) + if group_id in api_desc: + if endpoint_id in api_desc[group_id]: + return {group_id: {endpoint_id: api_desc[group_id][endpoint_id]}} + elif len(endpoint_id) > 0: + LOG.error("Unknown endpoint_id {}".format(endpoint_id)) + return {"error": "Unknown endpoint_id {}".format(endpoint_id)} + return {group_id: api_desc[group_id]} + return api_desc diff --git a/moonv4/moon_consul/moon_consul/http_server.py b/moonv4/moon_authz/moon_authz/http_server.py index c3d13378..b6818a9f 100644 --- a/moonv4/moon_consul/moon_consul/http_server.py +++ b/moonv4/moon_authz/moon_authz/http_server.py @@ -4,19 +4,18 @@ # or at 'http://www.apache.org/licenses/LICENSE-2.0'. from flask import Flask, request -from flask_cors import CORS, cross_origin +# from flask_cors import CORS, cross_origin from flask_restful import Resource, Api, reqparse import logging -from moon_consul import __version__ -from moon_consul.api.generic import API -from moon_consul.api.database import Database -from moon_consul.api.messenger import Messenger -from moon_consul.api.openstack import Keystone -from moon_consul.api.slave import Slave -from moon_consul.api.system import Docker, Components from moon_utilities import exceptions +from moon_authz import __version__ +from moon_authz.api.authorization import Authz +from moon_utilities.cache import Cache -logger = logging.getLogger(__name__) +logger = logging.getLogger("moon." + __name__) + +CACHE = Cache() +CACHE.update() class Server: @@ -63,8 +62,7 @@ class Server: raise NotImplementedError() __API__ = ( - API, - Database, Docker, Messenger, Keystone, Slave, Components + Authz, ) @@ -90,15 +88,24 @@ class Root(Resource): "tree": tree } + def head(self): + return "", 201 + class HTTPServer(Server): - def __init__(self, host="localhost", port=80, conf=None, **kwargs): + def __init__(self, host="0.0.0.0", port=38001, **kwargs): super(HTTPServer, self).__init__(host=host, port=port, **kwargs) + self.component_data = kwargs.get("component_data", {}) + logger.info("HTTPServer port={} {}".format(port, kwargs)) self.app = Flask(__name__) - self.conf = conf + self._port = port + self._host = host # Todo : specify only few urls instead of * # CORS(self.app) + self.component_id = kwargs.get("component_id") + self.keystone_project_id = kwargs.get("keystone_project_id") + self.container_chaining = kwargs.get("container_chaining") self.api = Api(self.app) self.__set_route() # self.__hook_errors() @@ -122,13 +129,12 @@ class HTTPServer(Server): self.api.add_resource(Root, '/') for api in __API__: - self.api.add_resource( - api, *api.__urls__, - resource_class_kwargs={ - "conf": self.conf, - } - ) + self.api.add_resource(api, *api.__urls__, + resource_class_kwargs={ + "component_data": self.component_data, + "cache": CACHE + } + ) def run(self): - self.app.run(debug=True, host=self._host, port=self._port) # nosec - + self.app.run(host=self._host, port=self._port) # nosec diff --git a/moonv4/moon_authz/moon_authz/messenger.py b/moonv4/moon_authz/moon_authz/messenger.py deleted file mode 100644 index 6fa34770..00000000 --- a/moonv4/moon_authz/moon_authz/messenger.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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 oslo_config import cfg -import oslo_messaging -import time -from oslo_log import log as logging -from moon_authz.api.generic import Status, Logs -from moon_authz.api.authorization import Authorization -from moon_utilities.api import APIList - -LOG = logging.getLogger(__name__) -CONF = cfg.CONF - - -class Server: - - def __init__(self, component_id, keystone_project_id): - self.TOPIC = "authz-workers" - transport = oslo_messaging.get_notification_transport(cfg.CONF) - targets = [ - oslo_messaging.Target(topic=self.TOPIC), - ] - self.endpoints = [ - APIList((Status, Logs)), - Status(), - Logs(), - Authorization(component_id) - ] - pool = "authz-workers" - self.server = oslo_messaging.get_notification_listener(transport, targets, - self.endpoints, executor='threading', - pool=pool) - LOG.info("Starting MQ notification server with topic: {}".format(self.TOPIC)) - - def run(self): - try: - self.server.start() - while True: - time.sleep(0.1) - except KeyboardInterrupt: - print("Stopping server by crtl+c") - except SystemExit: - print("Stopping server") - - self.server.stop() - - diff --git a/moonv4/moon_authz/moon_authz/server.py b/moonv4/moon_authz/moon_authz/server.py index 0c2a36ff..40143ba9 100644 --- a/moonv4/moon_authz/moon_authz/server.py +++ b/moonv4/moon_authz/moon_authz/server.py @@ -4,32 +4,44 @@ # or at 'http://www.apache.org/licenses/LICENSE-2.0'. import os -from oslo_config import cfg from oslo_log import log as logging -# cfg.CONF.register_cli_opt(cfg.StrOpt('function_type', positional=True, -# help="The type of function managed by this component (example 'authz').")) -cfg.CONF.register_cli_opt(cfg.StrOpt('uuid', positional=True, - help="The ID of the component managed here.")) -cfg.CONF.register_cli_opt(cfg.StrOpt('keystone_project_id', positional=True, - help="The ID of the component managed here.")) -from moon_utilities import options # noqa -from moon_authz.messenger import Server - -LOG = logging.getLogger(__name__) -CONF = cfg.CONF +from moon_authz.http_server import HTTPServer as Server +from moon_utilities import configuration + +LOG = logging.getLogger("moon.server") DOMAIN = "moon_authz" __CWD__ = os.path.dirname(os.path.abspath(__file__)) def main(): - component_id = CONF.uuid - keystone_project_id = CONF.keystone_project_id - # function_type = CONF.intra_extension_id.replace(component_id, "").strip('_') - LOG.info("Starting server with IP {} on component {}".format( - CONF.security_router.host, component_id)) - server = Server(component_id=component_id, keystone_project_id=keystone_project_id) - server.run() + component_id = os.getenv("UUID") + component_type = os.getenv("TYPE") + tcp_port = os.getenv("PORT") + pdp_id = os.getenv("PDP_ID") + meta_rule_id = os.getenv("META_RULE_ID") + keystone_project_id = os.getenv("KEYSTONE_PROJECT_ID") + configuration.init_logging() + LOG.info("component_type={}".format(component_type)) + conf = configuration.get_configuration("plugins/{}".format(component_type)) + conf["plugins/{}".format(component_type)]['id'] = component_id + hostname = conf["plugins/{}".format(component_type)].get('hostname', component_id) + port = conf["plugins/{}".format(component_type)].get('port', tcp_port) + bind = conf["plugins/{}".format(component_type)].get('bind', "0.0.0.0") + + LOG.info("Starting server with IP {} on port {} bind to {}".format(hostname, port, bind)) + server = Server( + host=bind, + port=int(port), + component_data={ + 'component_id': component_id, + 'component_type': component_type, + 'pdp_id': pdp_id, + 'meta_rule_id': meta_rule_id, + 'keystone_project_id': keystone_project_id, + } + ) + return server if __name__ == '__main__': diff --git a/moonv4/moon_authz/requirements.txt b/moonv4/moon_authz/requirements.txt index 8faf9439..344bec52 100644 --- a/moonv4/moon_authz/requirements.txt +++ b/moonv4/moon_authz/requirements.txt @@ -1 +1,8 @@ -kombu !=4.0.1,!=4.0.0
\ No newline at end of file +kombu !=4.0.1,!=4.0.0 +oslo.log +flask +oslo.config +flask_restful +flask_cors +moon_db +moon_utilities diff --git a/moonv4/moon_authz/tests/unit_python/conftest.py b/moonv4/moon_authz/tests/unit_python/conftest.py new file mode 100644 index 00000000..a6e62078 --- /dev/null +++ b/moonv4/moon_authz/tests/unit_python/conftest.py @@ -0,0 +1,29 @@ +import pytest +import requests_mock +import mock_pods +import os +from utilities import CONTEXT + + +@pytest.fixture +def context(): + return CONTEXT + + +def set_env_variables(): + os.environ['UUID'] = "1111111111" + os.environ['TYPE'] = "authz" + os.environ['PORT'] = "8081" + os.environ['PDP_ID'] = "b3d3e18abf3340e8b635fd49e6634ccd" + os.environ['META_RULE_ID'] = "f8f49a779ceb47b3ac810f01ef71b4e0" + os.environ['KEYSTONE_PROJECT_ID'] = CONTEXT['project_id'] + + +@pytest.fixture(autouse=True) +def no_requests(monkeypatch): + """ Modify the response from Requests module + """ + set_env_variables() + with requests_mock.Mocker(real_http=True) as m: + mock_pods.register_pods(m) + yield m diff --git a/moonv4/moon_authz/tests/unit_python/mock_pods.py b/moonv4/moon_authz/tests/unit_python/mock_pods.py new file mode 100644 index 00000000..7488f4f3 --- /dev/null +++ b/moonv4/moon_authz/tests/unit_python/mock_pods.py @@ -0,0 +1,545 @@ +from utilities import CONF, get_b64_conf, COMPONENTS + +pdp_mock = { + "b3d3e18abf3340e8b635fd49e6634ccd": { + "description": "test", + "security_pipeline": [ + "f8f49a779ceb47b3ac810f01ef71b4e0" + ], + "name": "pdp_rbac", + "keystone_project_id": "a64beb1cc224474fb4badd43173e7101" + }, + "pdp_id1": { + "name": "...", + "security_pipeline": ["policy_id_1", "policy_id_2"], + "keystone_project_id": "keystone_project_id1", + "description": "...", + }, + "pdp_id12": { + "name": "...", + "security_pipeline": ["policy_id_1", "policy_id_2"], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } +} + +meta_rules_mock = { + "f8f49a779ceb47b3ac810f01ef71b4e0": { + "subject_categories": [ + "14e6ae0ba34d458b876c791b73aa17bd" + ], + "action_categories": [ + "241a2a791554421a91c9f1bc564aa94d" + ], + "description": "", + "name": "rbac", + "object_categories": [ + "6d48500f639d4c2cab2b1f33ef93a1e8" + ] + }, + "meta_rule_id1": { + "name": "meta_rule1", + "algorithm": "name of the meta rule algorithm", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + }, + "meta_rule_id2": { + "name": "name of the meta rules2", + "algorithm": "name of the meta rule algorithm", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + } +} + +policies_mock = { + "f8f49a779ceb47b3ac810f01ef71b4e0": { + "name": "RBAC policy example", + "model_id": "cd923d8633ff4978ab0e99938f5153d6", + "description": "test", + "genre": "authz" + }, + "policy_id_1": { + "name": "test_policy1", + "model_id": "model_id_1", + "genre": "authz", + "description": "test", + }, + "policy_id_2": { + "name": "test_policy2", + "model_id": "model_id_2", + "genre": "authz", + "description": "test", + } +} + +subject_mock = { + "f8f49a779ceb47b3ac810f01ef71b4e0": { + "89ba91c18dd54abfbfde7a66936c51a6": { + "description": "test", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ], + "name": "testuser", + "email": "mail", + "id": "89ba91c18dd54abfbfde7a66936c51a6", + "partner_id": "" + } + }, + "policy_id_1": { + "subject_id": { + "name": "subject_name", + "keystone_id": "keystone_project_id1", + "description": "a description" + } + }, + "policy_id_2": { + "subject_id": { + "name": "subject_name", + "keystone_id": "keystone_project_id1", + "description": "a description" + } + } +} + +subject_assignment_mock = { + "826c1156d0284fc9b4b2ddb279f63c52": { + "category_id": "14e6ae0ba34d458b876c791b73aa17bd", + "assignments": [ + "24ea95256c5f4c888c1bb30a187788df", + "6b227b77184c48b6a5e2f3ed1de0c02a", + "31928b17ec90438ba5a2e50ae7650e63", + "4e60f554dd3147af87595fb6b37dcb13", + "7a5541b63a024fa88170a6b59f99ccd7", + "dd2af27812f742029d289df9687d6126" + ], + "id": "826c1156d0284fc9b4b2ddb279f63c52", + "subject_id": "89ba91c18dd54abfbfde7a66936c51a6", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + }, + "7407ffc1232944279b0cbcb0847c86f7": { + "category_id": "315072d40d774c43a89ff33937ed24eb", + "assignments": [ + "6b227b77184c48b6a5e2f3ed1de0c02a", + "31928b17ec90438ba5a2e50ae7650e63", + "7a5541b63a024fa88170a6b59f99ccd7", + "dd2af27812f742029d289df9687d6126" + ], + "id": "7407ffc1232944279b0cbcb0847c86f7", + "subject_id": "89ba91c18dd54abfbfde7a66936c51a6", + "policy_id": "3e65256389b448cb9897917ea235f0bb" + } +} + +object_mock = { + "f8f49a779ceb47b3ac810f01ef71b4e0": { + "9089b3d2ce5b4e929ffc7e35b55eba1a": { + "name": "vm1", + "description": "test", + "id": "9089b3d2ce5b4e929ffc7e35b55eba1a", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + }, + }, + "policy_id_1": { + "object_id": { + "name": "object_name", + "description": "a description" + } + }, + "policy_id_2": { + "object_id": { + "name": "object_name", + "description": "a description" + } + } +} + +object_assignment_mock = { + "201ad05fd3f940948b769ab9214fe295": { + "object_id": "9089b3d2ce5b4e929ffc7e35b55eba1a", + "assignments": [ + "030fbb34002e4236a7b74eeb5fd71e35", + "06bcb8655b9d46a9b90e67ef7c825b50", + "34eb45d7f46d4fb6bc4965349b8e4b83", + "4b7793dbae434c31a77da9d92de9fa8c" + ], + "id": "201ad05fd3f940948b769ab9214fe295", + "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + }, + "90c5e86f8be34c0298fbd1973e4fb043": { + "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e", + "assignments": [ + "a098918e915b4b12bccb89f9a3f3b4e4", + "06bcb8655b9d46a9b90e67ef7c825b50", + "7dc76c6142af47c88b60cc2b0df650ba", + "4b7793dbae434c31a77da9d92de9fa8c" + ], + "id": "90c5e86f8be34c0298fbd1973e4fb043", + "category_id": "33aece52d45b4474a20dc48a76800daf", + "policy_id": "3e65256389b448cb9897917ea235f0bb" + } +} + +action_mock = { + "f8f49a779ceb47b3ac810f01ef71b4e0": { + "cdb3df220dc05a6ea3334b994827b068": { + "name": "boot", + "description": "test", + "id": "cdb3df220dc04a6ea3334b994827b068", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + }, + "cdb3df220dc04a6ea3334b994827b068": { + "name": "stop", + "description": "test", + "id": "cdb3df220dc04a6ea3334b994827b068", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + }, + "9f5112afe9b34a6c894eb87246ccb7aa": { + "name": "start", + "description": "test", + "id": "9f5112afe9b34a6c894eb87246ccb7aa", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + } + }, + "policy_id_1": { + "action_id": { + "name": "action_name", + "description": "a description" + } + }, + "policy_id_2": { + "action_id": { + "name": "action_name", + "description": "a description" + } + } +} + +action_assignment_mock = { + "2128e3ffbd1c4ef5be515d625745c2d4": { + "category_id": "241a2a791554421a91c9f1bc564aa94d", + "action_id": "cdb3df220dc05a6ea3334b994827b068", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "id": "2128e3ffbd1c4ef5be515d625745c2d4", + "assignments": [ + "570c036781e540dc9395b83098c40ba7", + "7fe17d7a2e3542719f8349c3f2273182", + "015ca6f40338422ba3f692260377d638", + "23d44c17bf88480f83e8d57d2aa1ea79" + ] + }, + "cffb98852f3a4110af7a0ddfc4e19201": { + "category_id": "4a2c5abaeaf644fcaf3ca8df64000d53", + "action_id": "cdb3df220dc04a6ea3334b994827b068", + "policy_id": "3e65256389b448cb9897917ea235f0bb", + "id": "cffb98852f3a4110af7a0ddfc4e19201", + "assignments": [ + "570c036781e540dc9395b83098c40ba7", + "7fe17d7a2e3542719f8349c3f2273182", + "015ca6f40338422ba3f692260377d638", + "23d44c17bf88480f83e8d57d2aa1ea79" + ] + } +} + +models_mock = { + "cd923d8633ff4978ab0e99938f5153d6": { + "name": "RBAC", + "meta_rules": [ + "f8f49a779ceb47b3ac810f01ef71b4e0" + ], + "description": "test" + }, + "model_id_1": { + "name": "test_model", + "description": "test", + "meta_rules": ["meta_rule_id1"] + }, + "model_id_2": { + "name": "test_model", + "description": "test", + "meta_rules": ["meta_rule_id2"] + }, +} + +rules_mock = { + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "rules": [ + { + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "rule": [ + "24ea95256c5f4c888c1bb30a187788df", + "030fbb34002e4236a7b74eeb5fd71e35", + "570c036781e540dc9395b83098c40ba7" + ], + "enabled": True, + "id": "0201a2bcf56943c1904dbac016289b71", + "instructions": [ + { + "decision": "grant" + } + ], + "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + }, + { + "policy_id": "ecc2451c494e47b5bca7250cd324a360", + "rule": [ + "54f574cd2043468da5d65e4f6ed6e3c9", + "6559686961a3490a978f246ac9f85fbf", + "ac0d1f600bf447e8bd2f37b7cc47f2dc" + ], + "enabled": True, + "id": "a83fed666af8436192dfd8b3c83a6fde", + "instructions": [ + { + "decision": "grant" + } + ], + "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + } + ] +} + + +def register_pods(m): + """ Modify the response from Requests module + """ + register_consul(m) + register_pdp(m) + register_meta_rules(m) + register_policies(m) + register_models(m) + register_orchestrator(m) + register_policy_subject(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + # register_policy_subject(m, "policy_id_2") + register_policy_object(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + # register_policy_object(m, "policy_id_2") + register_policy_action(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + # register_policy_action(m, "policy_id_2") + register_policy_subject_assignment(m, "f8f49a779ceb47b3ac810f01ef71b4e0", "89ba91c18dd54abfbfde7a66936c51a6") + # register_policy_subject_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + # register_policy_subject_assignment(m, "policy_id_2", "subject_id") + # register_policy_subject_assignment_list(m1, "policy_id_2") + register_policy_object_assignment(m, "f8f49a779ceb47b3ac810f01ef71b4e0", "9089b3d2ce5b4e929ffc7e35b55eba1a") + # register_policy_object_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + # register_policy_object_assignment(m, "policy_id_2", "object_id") + # register_policy_object_assignment_list(m1, "policy_id_2") + register_policy_action_assignment(m, "f8f49a779ceb47b3ac810f01ef71b4e0", "cdb3df220dc05a6ea3334b994827b068") + # register_policy_action_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + # register_policy_action_assignment(m, "policy_id_2", "action_id") + # register_policy_action_assignment_list(m1, "policy_id_2") + register_rules(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + register_rules(m, "policy_id_1") + register_rules(m, "policy_id_2") + + +def register_consul(m): + for component in COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': get_b64_conf(component)}] + ) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/components_port_start', + json=[ + { + "LockIndex": 0, + "Key": "components_port_start", + "Flags": 0, + "Value": "MzEwMDE=", + "CreateIndex": 9, + "ModifyIndex": 9 + } + ], + ) + m.register_uri( + 'PUT', 'http://consul:8500/v1/kv/components_port_start', + json=[], + ) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/plugins?recurse=true', + json=[ + { + "LockIndex": 0, + "Key": "plugins/authz", + "Flags": 0, + "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=", + "CreateIndex": 14, + "ModifyIndex": 656 + } + ], + ) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/components?recurse=true', + json=[ + {"Key": key, "Value": get_b64_conf(key)} for key in COMPONENTS + ], + ) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/plugins/authz', + json=[ + { + "LockIndex": 0, + "Key": "plugins/authz", + "Flags": 0, + "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=", + "CreateIndex": 14, + "ModifyIndex": 656 + } + ], + ) + + +def register_orchestrator(m): + m.register_uri( + 'GET', 'http://orchestrator:8083/pods', + json={ + "pods": { + "1234567890": [ + {"name": "wrapper-quiet", "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3.1", + "namespace": "moon"}]}} + ) + + +def register_pdp(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'pdp'), + json={'pdps': pdp_mock} + ) + + +def register_meta_rules(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'meta_rules'), + json={'meta_rules': meta_rules_mock} + ) + + +def register_policies(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies'), + json={'policies': policies_mock} + ) + + +def register_models(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'models'), + json={'models': models_mock} + ) + + +def register_policy_subject(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subjects'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'subjects': subject_mock[policy_id]} + ) + + +def register_policy_object(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/objects'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'objects': object_mock[policy_id]} + ) + + +def register_policy_action(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/actions'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'actions': action_mock[policy_id]} + ) + + +def register_policy_subject_assignment(m, policy_id, subj_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subject_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + subj_id), + json={'subject_assignments': subject_assignment_mock} + ) + + +def register_policy_subject_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subject_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'subject_assignments': subject_assignment_mock} + ) + + +def register_policy_object_assignment(m, policy_id, obj_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/object_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + obj_id), + json={'object_assignments': object_assignment_mock} + ) + + +def register_policy_object_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/object_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'object_assignments': object_assignment_mock} + ) + + +def register_policy_action_assignment(m, policy_id, action_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/action_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + action_id), + json={'action_assignments': action_assignment_mock} + ) + + +def register_policy_action_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/action_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'action_assignments': action_assignment_mock} + ) + + +def register_rules(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, 'rules'), + json={'rules': rules_mock} + )
\ No newline at end of file diff --git a/moonv4/moon_consul/requirements.txt b/moonv4/moon_authz/tests/unit_python/requirements.txt index ab99edaa..8bd8449f 100644 --- a/moonv4/moon_consul/requirements.txt +++ b/moonv4/moon_authz/tests/unit_python/requirements.txt @@ -1,5 +1,5 @@ -oslo.messaging flask -flask_restful flask_cors +flask_restful +moon_db moon_utilities
\ No newline at end of file diff --git a/moonv4/moon_authz/tests/unit_python/test_authz.py b/moonv4/moon_authz/tests/unit_python/test_authz.py new file mode 100644 index 00000000..147f7c5d --- /dev/null +++ b/moonv4/moon_authz/tests/unit_python/test_authz.py @@ -0,0 +1,50 @@ +import json +import pickle + + +def get_data(data): + return pickle.loads(data) + + +def get_json(data): + return json.loads(data.decode("utf-8")) + + +def test_authz_true(context): + import moon_authz.server + from moon_utilities.security_functions import Context + from moon_utilities.cache import Cache + server = moon_authz.server.main() + client = server.app.test_client() + CACHE = Cache() + CACHE.update() + print(CACHE.pdp) + _context = Context(context, CACHE) + req = client.post("/authz", data=pickle.dumps(_context)) + assert req.status_code == 200 + data = get_data(req.data) + assert data + assert isinstance(data, Context) + policy_id = data.headers[0] + assert policy_id + assert "effect" in data.pdp_set[policy_id] + assert data.pdp_set[policy_id]['effect'] == "grant" + + +def test_user_not_allowed(context): + import moon_authz.server + from moon_utilities.security_functions import Context + from moon_utilities.cache import Cache + server = moon_authz.server.main() + client = server.app.test_client() + CACHE = Cache() + CACHE.update() + context['subject_name'] = "user_not_allowed" + _context = Context(context, CACHE) + req = client.post("/authz", data=pickle.dumps(_context)) + assert req.status_code == 400 + data = get_json(req.data) + assert data + assert isinstance(data, dict) + assert "message" in data + assert data["message"] == "Cannot find subject user_not_allowed" diff --git a/moonv4/moon_authz/tests/unit_python/utilities.py b/moonv4/moon_authz/tests/unit_python/utilities.py new file mode 100644 index 00000000..19b9354c --- /dev/null +++ b/moonv4/moon_authz/tests/unit_python/utilities.py @@ -0,0 +1,173 @@ +import base64 +import json +import pytest +from uuid import uuid4 + + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "orchestrator" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + + +CONTEXT = { + "project_id": "a64beb1cc224474fb4badd43173e7101", + "subject_name": "testuser", + "object_name": "vm1", + "action_name": "boot", + "request_id": uuid4().hex, + "interface_name": "interface", + "manager_url": "http://{}:{}".format( + CONF["components"]["manager"]["hostname"], + CONF["components"]["manager"]["port"] + ), + "cookie": uuid4().hex, + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", + "security_pipeline": ["f8f49a779ceb47b3ac810f01ef71b4e0"] + } + + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", + "components/orchestrator", + "components/interface", + "components/wrapper", +) + + +def get_b64_conf(component=None): + if component == "components": + return base64.b64encode( + json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8') + elif component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif not component: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') + + +def get_json(data): + return json.loads(data.decode("utf-8")) + + diff --git a/moonv4/moon_bouchon/Dockerfile b/moonv4/moon_bouchon/Dockerfile new file mode 100644 index 00000000..ed013935 --- /dev/null +++ b/moonv4/moon_bouchon/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3 + +ADD . /root +RUN pip install -r /root/requirements.txt --upgrade +WORKDIR /root +RUN pip install . + +CMD ["python", "-m", "moon_bouchon"]
\ No newline at end of file diff --git a/moonv4/moon_bouchon/README.md b/moonv4/moon_bouchon/README.md new file mode 100644 index 00000000..11733cef --- /dev/null +++ b/moonv4/moon_bouchon/README.md @@ -0,0 +1,42 @@ +#Moon Bouchon + +Moon_bouchon is a fake interface to the Moon platform. +Moon platform can be requested through 2 interfaces: + +- ''wrapper'', interface for the OpenStack platform +- ''interface'', interface for other components + +## Usage: + +### server + +To start the server: + + docker run -ti -p 31002:31002 wukongsun/moon_bouchon:v1.0 + # or docker run -dti -p 31002:31002 wukongsun/moon_bouchon:v1.0 + +### wrapper + +Here are the URL, you can request: + + POST /wrapper/authz/grant to request the wrapper component with always a "True" response + POST /wrapper/authz/deny to request the wrapper component with always a "False" response + POST /wrapper/authz to request the wrapper component with always a "True" or "False" response + +In each request you must pass the following data (or similar): + + {'rule': 'start', 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', 'credentials': 'null'} + +You have examples in the moon_bouchon/tests directory. + +### interface + +Here are the URL, you can request: + + GET /interface/authz/grant/<string:project_id>/<string:subject_name>/<string:object_name>/<string:action_name> to request the interface component with always a "True" response + GET /interface/authz/deny/<string:project_id>/<string:subject_name>/<string:object_name>/<string:action_name> to request the interface component with always a "False" response + GET /interface/authz/<string:project_id>/<string:subject_name>/<string:object_name>/<string:action_name> to request the interface component with always a "True" or "False" response + +You have examples in the moon_bouchon/tests directory. + + diff --git a/moonv4/moon_router/moon_router/__init__.py b/moonv4/moon_bouchon/moon_bouchon/__init__.py index 903c6518..8811d91d 100644 --- a/moonv4/moon_router/moon_router/__init__.py +++ b/moonv4/moon_bouchon/moon_bouchon/__init__.py @@ -3,4 +3,5 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -__version__ = "0.1.0" + +__version__ = "1.1" diff --git a/moonv4/moon_consul/MANIFEST.in b/moonv4/moon_bouchon/moon_bouchon/__main__.py index ba8a657e..4499a96b 100644 --- a/moonv4/moon_consul/MANIFEST.in +++ b/moonv4/moon_bouchon/moon_bouchon/__main__.py @@ -3,9 +3,7 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -include README.rst -include LICENSE -include setup.py -include requirements.txt -# graft tests -graft bin
\ No newline at end of file + +import moon_bouchon.server + +moon_bouchon.server.main() diff --git a/moonv4/moon_bouchon/moon_bouchon/server.py b/moonv4/moon_bouchon/moon_bouchon/server.py new file mode 100644 index 00000000..29e9101e --- /dev/null +++ b/moonv4/moon_bouchon/moon_bouchon/server.py @@ -0,0 +1,138 @@ +# 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'. + +import sys +import flask +from flask import Flask +from flask import request +import json +import logging +import random + +logger = logging.getLogger(__name__) +app = Flask(__name__) + + +@app.route("/interface/authz/grant/<string:project_id>/<string:subject_name>/" + "<string:object_name>/<string:action_name>", + methods=["GET"]) +def interface_grant(project_id, subject_name, object_name, action_name): + logger.info("Requesting interface authz on {} {} {} {}".format( + project_id, subject_name, object_name, action_name)) + return json.dumps({ + "result": True, + "context": { + "project_id": project_id, + "subject_name": subject_name, + "object_name": object_name, + "action_name": action_name + } + }) + + +@app.route("/interface/authz/deny/<string:project_id>/<string:subject_name>/" + "<string:object_name>/<string:action_name>", + methods=["GET"]) +def interface_deny(project_id, subject_name, object_name, action_name): + logger.info("Requesting interface authz on {} {} {} {}".format( + project_id, subject_name, object_name, action_name)) + return json.dumps({ + "result": False, + "context": { + "project_id": project_id, + "subject_name": subject_name, + "object_name": object_name, + "action_name": action_name + } + }) + + +@app.route("/interface/authz/<string:project_id>/<string:subject_name>/" + "<string:object_name>/<string:action_name>", + methods=["GET"]) +def interface_authz(project_id, subject_name, object_name, action_name): + logger.info("Requesting interface authz on {} {} {} {}".format( + project_id, subject_name, object_name, action_name)) + return json.dumps({ + "result": random.choice((True, False)), + "context": { + "project_id": project_id, + "subject_name": subject_name, + "object_name": object_name, + "action_name": action_name + } + }) + + +def test_data(): + data = request.form + if not dict(request.form): + data = json.loads(request.data.decode("utf-8")) + try: + target = json.loads(data.get('target', {})) + except Exception: + raise Exception("Error reading target") + try: + credentials = json.loads(data.get('credentials', {})) + except Exception: + raise Exception("Error reading credentials") + try: + rule = data.get('rule', "") + except Exception: + raise Exception("Error reading rule") + + +@app.route("/wrapper/authz/grant", methods=["POST"]) +def wrapper_grant(): + logger.info("Requesting wrapper authz") + try: + test_data() + except Exception as e: + logger.exception(e) + return str(e), 400 + response = flask.make_response("True") + response.headers['content-type'] = 'application/octet-stream' + return response + + +@app.route("/wrapper/authz/deny", methods=["POST"]) +def wrapper_deny(): + logger.info("Requesting wrapper authz") + try: + test_data() + except Exception as e: + logger.exception(e) + return str(e), 400 + response = flask.make_response("False") + response.headers['content-type'] = 'application/octet-stream' + return response + + +@app.route("/wrapper/authz", methods=["POST"]) +def wrapper_authz(): + logger.info("Requesting wrapper authz") + try: + test_data() + except Exception as e: + logger.exception(e) + return str(e), 400 + response = flask.make_response(random.choice(("True", "False"))) + response.headers['content-type'] = 'application/octet-stream' + return response + + +def main(): + port = 31002 + if len(sys.argv) > 1: + try: + port = int(sys.argv[1]) + except ValueError: + logger.error("Argument for Port in command line is not an integer") + sys.exit(1) + app.run(host="0.0.0.0", port=port) + + +if __name__ == "__main__": + main() diff --git a/moonv4/moon_bouchon/requirements.txt b/moonv4/moon_bouchon/requirements.txt new file mode 100644 index 00000000..8ab6294c --- /dev/null +++ b/moonv4/moon_bouchon/requirements.txt @@ -0,0 +1 @@ +flask
\ No newline at end of file diff --git a/moonv4/moon_bouchon/setup.cfg b/moonv4/moon_bouchon/setup.cfg new file mode 100644 index 00000000..7c2b2874 --- /dev/null +++ b/moonv4/moon_bouchon/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal = 1
\ No newline at end of file diff --git a/moonv4/moon_router/setup.py b/moonv4/moon_bouchon/setup.py index aabe8349..a875be40 100644 --- a/moonv4/moon_router/setup.py +++ b/moonv4/moon_bouchon/setup.py @@ -4,14 +4,14 @@ # or at 'http://www.apache.org/licenses/LICENSE-2.0'. from setuptools import setup, find_packages -import moon_router +import moon_bouchon setup( - name='moon_router', + name='moon_bouchon', - version=moon_router.__version__, + version=moon_bouchon.__version__, packages=find_packages(), @@ -23,7 +23,7 @@ setup( long_description=open('README.md').read(), - # install_requires= , + install_requires=["flask"], include_package_data=True, @@ -40,7 +40,8 @@ setup( entry_points={ 'console_scripts': [ - 'moon_router = moon_router.server:main', + 'moon_bouchon = moon_bouchon.server:main', ], } + ) diff --git a/moonv4/moon_bouchon/tests/test_interface.py b/moonv4/moon_bouchon/tests/test_interface.py new file mode 100644 index 00000000..425ba2e5 --- /dev/null +++ b/moonv4/moon_bouchon/tests/test_interface.py @@ -0,0 +1,61 @@ +import requests +from uuid import uuid4 +import pytest + + +@pytest.fixture +def args(): + return { + "project_id": uuid4().hex, + "subject_id": uuid4().hex, + "object_id": uuid4().hex, + "action_id": uuid4().hex + } + + +def test_false(args): + url = "http://127.0.0.1:31002/interface/authz/deny/{project_id}" \ + "/{subject_id}/{object_id}/{action_id}".format(**args) + data = {'rule': 'start', + 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', + 'credentials': 'null'} + req = requests.get( + url, json=data, + headers={'content-type': "application/x-www-form-urlencode"} + ) + assert req.status_code == 200 + assert "result" in req.json() + assert req.json()["result"] == False + + +def test_true(args): + url = "http://127.0.0.1:31002/interface/authz/grant/{project_id}" \ + "/{subject_id}/{object_id}/{action_id}".format(**args) + + data = {'rule': 'start', + 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', + 'credentials': 'null'} + req = requests.get( + url, json=data, + headers={'content-type': "application/x-www-form-urlencode"} + ) + assert req.status_code == 200 + assert "result" in req.json() + assert req.json()["result"] == True + + +def test_random(args): + url = "http://127.0.0.1:31002/interface/authz/{project_id}" \ + "/{subject_id}/{object_id}/{action_id}".format(**args) + + data = {'rule': 'start', + 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', + 'credentials': 'null'} + req = requests.get( + url, json=data, + headers={'content-type': "application/x-www-form-urlencode"} + ) + assert req.status_code == 200 + assert "result" in req.json() + assert req.json()["result"] in (False, True) + diff --git a/moonv4/moon_bouchon/tests/test_wrapper.py b/moonv4/moon_bouchon/tests/test_wrapper.py new file mode 100644 index 00000000..3d5e150c --- /dev/null +++ b/moonv4/moon_bouchon/tests/test_wrapper.py @@ -0,0 +1,38 @@ +import requests + + +def test_false(): + url = "http://127.0.0.1:31002/wrapper/authz/deny" + + data = {'rule': 'start', 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', 'credentials': 'null'} + req = requests.post( + url, json=data, + headers={'content-type': "application/x-www-form-urlencode"} + ) + assert req.status_code == 200 + assert req.text == "False" + + +def test_true(): + url = "http://127.0.0.1:31002/wrapper/authz/grant" + + data = {'rule': 'start', 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', 'credentials': 'null'} + req = requests.post( + url, json=data, + headers={'content-type': "application/x-www-form-urlencode"} + ) + assert req.status_code == 200 + assert req.text == "True" + + +def test_random(): + url = "http://127.0.0.1:31002/wrapper/authz" + + data = {'rule': 'start', 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', 'credentials': 'null'} + req = requests.post( + url, json=data, + headers={'content-type': "application/x-www-form-urlencode"} + ) + assert req.status_code == 200 + assert req.text in ("False", "True") + diff --git a/moonv4/moon_consul/Dockerfile b/moonv4/moon_consul/Dockerfile deleted file mode 100644 index 1d3c7108..00000000 --- a/moonv4/moon_consul/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# Pull base image. -FROM ubuntu:latest - -ENV DB_URL="mysql+pymysql://moon:p4sswOrd1@db/moon" -ENV DB_DRIVER=sql -ENV TRANSPORT_URL="rabbit://moon:p4sswOrd1@messenger:5672/moon" -ENV DOCKER_URL="unix://var/run/docker.sock" -ENV SLAVE_NAME= -ENV MASTER_URL= -ENV MASTER_LOGIN= -ENV MASTER_PASSWORD= -ENV INTERFACE_PORT=8080 -ENV CONSUL_HOST="172.88.88.88" -ENV CONSUL_PORT=88 -ENV KEYSTONE_URL="http://keystone:5000/v3" -ENV KEYSTONE_USER=admin -ENV KEYSTONE_PASSWORD=p4ssw0rd -ENV KEYSTONE_DOMAIN=default -ENV KEYSTONE_PROJECT=admin -ENV KEYSTONE_CHECK_TOKEN=False -ENV KEYSTONE_SERVER_CRT=False -ENV PLUGIN_CONTAINERS="asteroide/authz:latest,asteroide/session:latest" -ENV COMPONENTS_PORT_START=38001 - -RUN apt-get update && apt-get install python3.5 python3-pip -y - -RUN pip3 install pip --upgrade -#RUN pip3 install moon_db - -ADD . /root - -WORKDIR /root/ -RUN pip3 install -r requirements.txt -RUN pip3 install . -EXPOSE ${CONSUL_PORT} - -CMD ["python3", "-m", "moon_consul"]
\ No newline at end of file diff --git a/moonv4/moon_consul/LICENSE b/moonv4/moon_consul/LICENSE deleted file mode 100644 index 4143aac2..00000000 --- a/moonv4/moon_consul/LICENSE +++ /dev/null @@ -1,204 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/moonv4/moon_consul/README.md b/moonv4/moon_consul/README.md deleted file mode 100644 index afee9be5..00000000 --- a/moonv4/moon_consul/README.md +++ /dev/null @@ -1,9 +0,0 @@ -DB module for the Moon project -============================== - -This package contains the database module for the Moon project -It is designed to provide a driver to access the Moon database. - -For any other information, refer to the parent project: - - https://git.opnfv.org/moon diff --git a/moonv4/moon_consul/moon_consul/__init__.py b/moonv4/moon_consul/moon_consul/__init__.py deleted file mode 100644 index 3dc1f76b..00000000 --- a/moonv4/moon_consul/moon_consul/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "0.1.0" diff --git a/moonv4/moon_consul/moon_consul/__main__.py b/moonv4/moon_consul/moon_consul/__main__.py deleted file mode 100644 index 4d64288e..00000000 --- a/moonv4/moon_consul/moon_consul/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from moon_consul.server import main - -main() diff --git a/moonv4/moon_consul/moon_consul/api/database.py b/moonv4/moon_consul/moon_consul/api/database.py deleted file mode 100644 index 5533b1a5..00000000 --- a/moonv4/moon_consul/moon_consul/api/database.py +++ /dev/null @@ -1,72 +0,0 @@ -# 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'. -""" -Assignments allow to connect data with elements of perimeter - -""" - -from flask import request -from flask_restful import Resource -# from oslo_config import cfg -from oslo_log import log as logging -# from moon_interface.tools import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger(__name__) -# CONF = cfg.CONF - - -class Database(Resource): - """ - Endpoint for database requests - """ - - __urls__ = ( - "/configuration/database", - ) - - def __init__(self, *args, **kwargs): - self.conf = kwargs.get('conf', {}) - - # @check_auth - def get(self): - """Retrieve database configuration - - :return: { - "database": { - "hostname": "hostname for the main database", - "port": "port for the main database", - "user": "user for the main database", - "password": "password for the main database", - "protocol": "protocol to use (eg. mysql+pymysql)", - "driver": "driver to use", - } - } - """ - url = self.conf.DB_URL - driver = self.conf.DB_DRIVER - hostname = url.split("@")[-1].split(":")[0].split("/")[0] - try: - port = int(url.split("@")[-1].split(":")[1].split("/")[0]) - except ValueError: - port = None - except IndexError: - port = None - user = url.split("//")[1].split(":")[0] - # TODO: password must be encrypted - password = url.split(":")[2].split("@")[0] - protocol = url.split(":")[0] - return { - "database": { - "hostname": hostname, - "port": port, - "user": user, - "password": password, - "protocol": protocol, - "driver": driver - } - } - diff --git a/moonv4/moon_consul/moon_consul/api/messenger.py b/moonv4/moon_consul/moon_consul/api/messenger.py deleted file mode 100644 index 28026baf..00000000 --- a/moonv4/moon_consul/moon_consul/api/messenger.py +++ /dev/null @@ -1,67 +0,0 @@ -# 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'. -""" -Assignments allow to connect data with elements of perimeter - -""" - -from flask import request -from flask_restful import Resource -# from oslo_config import cfg -from oslo_log import log as logging -# from moon_interface.tools import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger(__name__) -# CONF = cfg.CONF - - -class Messenger(Resource): - """ - Endpoint for messenger requests - """ - - __urls__ = ( - "/configuration/messenger", - ) - - def __init__(self, *args, **kwargs): - self.conf = kwargs.get('conf', {}) - - # @check_auth - def get(self): - """Retrieve messenger configuration - - :return: { - "messenger": { - "hostname": "hostname for the messenger server", - "port": "port for the main messenger server", - "user": "user for the main messenger server", - "password": "password for the main messenger server", - "protocol": "protocol to use (eg. rabbit)" - } - } - """ - url = self.conf.TRANSPORT_URL - hostname = url.split("@")[-1].split(":")[0].split("/")[0] - try: - port = int(url.split("@")[-1].split(":")[1].split("/")[0]) - except ValueError: - port = None - user = url.split("//")[1].split(":")[0] - # TODO: password must be encrypted - password = url.split(":")[2].split("@")[0] - protocol = url.split(":")[0] - return { - "messenger": { - "hostname": hostname, - "port": port, - "user": user, - "password": password, - "protocol": protocol, - } - } - diff --git a/moonv4/moon_consul/moon_consul/api/openstack.py b/moonv4/moon_consul/moon_consul/api/openstack.py deleted file mode 100644 index 5d776981..00000000 --- a/moonv4/moon_consul/moon_consul/api/openstack.py +++ /dev/null @@ -1,63 +0,0 @@ -# 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'. -""" -Assignments allow to connect data with elements of perimeter - -""" - -from flask import request -from flask_restful import Resource -# from oslo_config import cfg -from oslo_log import log as logging -# from moon_interface.tools import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger(__name__) -# CONF = cfg.CONF - - -class Keystone(Resource): - """ - Endpoint for Keystone requests - """ - - __urls__ = ( - "/configuration/os/keystone", - ) - - def __init__(self, *args, **kwargs): - self.conf = kwargs.get('conf', {}) - - # @check_auth - def get(self): - """Retrieve Keystone configuration - - :return: { - "keystone": { - "url": "hostname for the Keystone server", - "user": "user for the Keystone server", - "password": "password for the Keystone server", - "domain": "domain to use against Keystone server", - "project": "main project to use", - "check_token": "yes, no or strict", - "server_crt": "certificate to use when using https" - } - } - """ - # TODO: password must be encrypted - # TODO: check_token is a sensitive information it must not be update through the network - return { - "keystone": { - "url": self.conf.KEYSTONE_URL, - "user": self.conf.KEYSTONE_USER, - "password": self.conf.KEYSTONE_PASSWORD, - "domain": self.conf.KEYSTONE_DOMAIN, - "project": self.conf.KEYSTONE_PROJECT, - "check_token": self.conf.KEYSTONE_CHECK_TOKEN, - "server_crt": self.conf.KEYSTONE_SERVER_CRT - } - } - diff --git a/moonv4/moon_consul/moon_consul/api/slave.py b/moonv4/moon_consul/moon_consul/api/slave.py deleted file mode 100644 index 7f8acb28..00000000 --- a/moonv4/moon_consul/moon_consul/api/slave.py +++ /dev/null @@ -1,72 +0,0 @@ -# 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'. -""" -Assignments allow to connect data with elements of perimeter - -""" - -from flask import request -from flask_restful import Resource -# from oslo_config import cfg -from oslo_log import log as logging -# from moon_interface.tools import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger(__name__) -# CONF = cfg.CONF - - -class Slave(Resource): - """ - Endpoint for slave requests - """ - - __urls__ = ( - "/configuration/slave", - ) - - def __init__(self, *args, **kwargs): - self.conf = kwargs.get('conf', {}) - - # @check_auth - def get(self): - """Retrieve slave configuration - - If current server is a slave: - :return: { - "slave": { - "name": "name of the slave", - "master_url": "URL of the master", - "user": [ - { - "username": "user to be used to connect to the master", - "password": "password to be used to connect to the master" - } - ] - } - } - else: - :return: { - "slave": {} - } - """ - # TODO: password must be encrypted - if self.conf.SLAVE_NAME: - return { - "slave": { - "name": self.conf.SLAVE_NAME, - "master_url": self.conf.MASTER_URL, - "user": [ - { - "username": self.conf.MASTER_LOGIN, - "password": self.conf.MASTER_PASSWORD - } - ] - } - } - else: - return {"slave": {}} - diff --git a/moonv4/moon_consul/moon_consul/api/system.py b/moonv4/moon_consul/moon_consul/api/system.py deleted file mode 100644 index e21d9de2..00000000 --- a/moonv4/moon_consul/moon_consul/api/system.py +++ /dev/null @@ -1,169 +0,0 @@ -# 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'. -""" -Assignments allow to connect data with elements of perimeter - -""" - -from flask import request -from flask_restful import Resource -# from oslo_config import cfg -from oslo_log import log as logging -# from moon_interface.tools import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger(__name__) -# CONF = cfg.CONF - - -class Docker(Resource): - """ - Endpoint for system requests - """ - - __urls__ = ( - "/configuration/docker", - ) - - def __init__(self, *args, **kwargs): - self.conf = kwargs.get('conf', {}) - - # @check_auth - def get(self): - """Retrieve docker configuration - - :return: { - "docker": { - "url": "hostname for the docker server (eg. /var/run/docker.sock)", - "port": "port of the server", - "user": "user of the server", - "password": "password of the server", - "protocol": "protocol to use (eg. unix)" - } - } - """ - url = self.conf.DOCKER_URL - # LOG.info(url) - # hostname = url.split("@")[-1].split(":")[0].split("/")[0] - # try: - # port = int(url.split("@")[-1].split(":")[1].split("/")[0]) - # except ValueError: - # port = None - # user = url.split("//")[1].split(":")[0] - # # TODO: password must be encrypted - # try: - # password = url.split(":")[2].split("@")[0] - # except IndexError: - # password = "" - # protocol = url.split(":")[0] - return { - "docker": { - "url": self.conf.DOCKER_URL, - # "port": port, - # "user": user, - # "password": password, - # "protocol": protocol, - } - } - - -class Components(Resource): - """ - Endpoint for requests on components - """ - - __urls__ = ( - "/configuration/components", - "/configuration/components/", - "/configuration/components/<string:id_or_name>", - ) - - def __init__(self, *args, **kwargs): - self.conf = kwargs.get('conf', {}) - - # @check_auth - def get(self, id_or_name=None): - """Retrieve component list - - :param id_or_name: ID or name of the component - - :return: { - "components": [ - { - "hostname": "hostname of the component", - "port": "port of the server in this component", - "id": "id of the component", - "keystone_id": "Keystone project ID served by this component if needed" - }, - ] - } - """ - if id_or_name: - for _component in self.conf.COMPONENTS: - if id_or_name in (_component["hostname"], _component["id"]): - return { - "components": [_component, ] - } - return {"components": []} - return {"components": self.conf.COMPONENTS} - - # @check_auth - def put(self, id_or_name=None): - """Ask for adding a new component - The response gives the TCP port to be used - - :param id_or_name: ID or name of the component - :request body: { - "hostname": "hostname of the new component", - "keystone_id": "Keystone ID mapped to that component (if needed)" - } - :return: { - "components": [ - { - "hostname": "hostname of the component", - "port": "port of the server in this component", - "id": "id of the component", - "keystone_id": "Keystone project ID served by this component" - } - ] - } - """ - if not id_or_name: - return "Need a name for that component", 400 - for _component in self.conf.COMPONENTS: - if id_or_name in (_component["hostname"], _component["id"]): - return "ID already used", 409 - self.conf.COMPONENTS_PORT_START += 1 - port = self.conf.COMPONENTS_PORT_START - data = request.json - new_component = { - "hostname": data.get("hostname", id_or_name), - "port": port, - "id": id_or_name, - "keystone_id": data.get("keystone_id", "") - } - self.conf.COMPONENTS.append(new_component) - return { - "components": [new_component, ] - } - - # @check_auth - def delete(self, id_or_name=None): - """Delete a component - - :param id_or_name: ID or name of the component - :return: { - "result": true - } - """ - if not id_or_name: - return "Need a name for that component", 400 - for index, _component in enumerate(self.conf.COMPONENTS): - if id_or_name in (_component["hostname"], _component["id"]): - self.conf.COMPONENTS.pop(index) - return {"result": True} - return "Cannot find component named {}".format(id_or_name), 403 - diff --git a/moonv4/moon_consul/moon_consul/server.py b/moonv4/moon_consul/moon_consul/server.py deleted file mode 100644 index 7d42228b..00000000 --- a/moonv4/moon_consul/moon_consul/server.py +++ /dev/null @@ -1,82 +0,0 @@ -# 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'. - -import os -# from oslo_config import cfg -from oslo_log import log as logging -# from moon_utilities import options # noqa -from moon_consul.http_server import HTTPServer - -LOG = logging.getLogger(__name__) -# CONF = cfg.CONF -# DOMAIN = "moon_consul" - -# __CWD__ = os.path.dirname(os.path.abspath(__file__)) - - -class Configuration: - DB_URL = None - DB_DRIVER = None - TRANSPORT_URL = None - DOCKER_URL = None - SLAVE_NAME = None - MASTER_URL = None - MASTER_LOGIN = None - MASTER_PASSWORD = None - INTERFACE_PORT = None - CONSUL_HOST = None - CONSUL_PORT = None - KEYSTONE_URL = None - KEYSTONE_USER = None - KEYSTONE_PASSWORD = None - KEYSTONE_DOMAIN = None - KEYSTONE_PROJECT = None - KEYSTONE_CHECK_TOKEN = None - KEYSTONE_SERVER_CRT = None - PLUGIN_CONTAINERS = None - - -def get_configuration(): - conf = Configuration() - conf.DB_URL = os.getenv("DB_URL", "mysql+pymysql://moon:p4sswOrd1@db/moon") - conf.DB_DRIVER = os.getenv("DB_DRIVER", "sql") - conf.TRANSPORT_URL = os.getenv("TRANSPORT_URL", "rabbit://moon:p4sswOrd1@messenger:5672/moon") - conf.DOCKER_URL = os.getenv("DOCKER_URL", "unix://var/run/docker.sock") - conf.SLAVE_NAME = os.getenv("SLAVE_NAME", "") - conf.MASTER_URL = os.getenv("MASTER_URL", "") - conf.MASTER_LOGIN = os.getenv("MASTER_LOGIN", "") - conf.MASTER_PASSWORD = os.getenv("MASTER_PASSWORD", "") - conf.INTERFACE_PORT = os.getenv("INTERFACE_PORT", "8080") - conf.CONSUL_HOST = os.getenv("CONSUL_HOST", "172.88.88.88") - conf.CONSUL_PORT = os.getenv("CONSUL_PORT", "88") - conf.KEYSTONE_URL = os.getenv("KEYSTONE_URL", "http://keystone:5000/v3") - conf.KEYSTONE_USER = os.getenv("KEYSTONE_USER", "admin") - conf.KEYSTONE_PASSWORD = os.getenv("KEYSTONE_PASSWORD", "p4ssw0rd") - conf.KEYSTONE_DOMAIN = os.getenv("KEYSTONE_DOMAIN", "default") - conf.KEYSTONE_PROJECT = os.getenv("KEYSTONE_PROJECT", "admin") - conf.KEYSTONE_CHECK_TOKEN = os.getenv("KEYSTONE_CHECK_TOKEN", False) - conf.KEYSTONE_SERVER_CRT = os.getenv("KEYSTONE_SERVER_CRT", False) - conf.PLUGIN_CONTAINERS = os.getenv("PLUGIN_CONTAINERS", "asteroide/authz:latest,asteroide/session:latest") - conf.COMPONENTS_PORT_START = int(os.getenv("COMPONENTS_PORT_START", "38001")) - conf.COMPONENTS = [ - { - "hostname": conf.CONSUL_HOST, - "port": conf.CONSUL_PORT, - "id": "consul", - "keystone_id": None - }, - ] - return conf - - -def main(): - conf = get_configuration() - LOG.info("Starting server with IP {} on port {}".format(conf.CONSUL_HOST, conf.CONSUL_PORT)) - server = HTTPServer(host=conf.CONSUL_HOST, port=int(conf.CONSUL_PORT), conf=conf) - server.run() - - -if __name__ == '__main__': - main() diff --git a/moonv4/moon_consul/setup.py b/moonv4/moon_consul/setup.py deleted file mode 100644 index d4aac83c..00000000 --- a/moonv4/moon_consul/setup.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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 setuptools import setup, find_packages -import moon_consul - - -with open('requirements.txt') as f: - required = f.read().splitlines() - -setup( - - name='moon_consul', - - version=moon_consul.__version__, - - packages=find_packages(), - - author="Thomas Duval", - - author_email="thomas.duval@orange.com", - - description="This component is a helper to retrieve configuration across the Moon platform.", - - long_description=open('README.md').read(), - - install_requires=required, - - include_package_data=True, - - url='https://git.opnfv.org/cgit/moon/', - - classifiers=[ - "Programming Language :: Python", - "Development Status :: 1 - Planning", - "License :: OSI Approved", - "Natural Language :: English", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3", - ], - - entry_points={ - 'console_scripts': [ - 'moon_consul = moon_consul.server:run', - ], - } - -) diff --git a/moonv4/moon_db/Changelog b/moonv4/moon_db/Changelog index 16452f6e..de04eadc 100644 --- a/moonv4/moon_db/Changelog +++ b/moonv4/moon_db/Changelog @@ -28,3 +28,23 @@ CHANGES - Fix a bug in core.py - Update db_manager +1.1.0 +----- +- When adding a subject, check the existence of that user in the Keystone DB and + create it if necessary + +1.2.0 +----- +- Update the db_manager in order to use it for tests + +1.2.1 +----- +- Update moon_db_manager in order to use it for unit tests + +1.2.2 +----- +- Fix a bug in moon_db_manager + +1.2.3 +----- +- Cleanup moon_db code diff --git a/moonv4/moon_db/LICENSE b/moonv4/moon_db/LICENSE index 4143aac2..d6456956 100644 --- a/moonv4/moon_db/LICENSE +++ b/moonv4/moon_db/LICENSE @@ -174,31 +174,29 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/moonv4/moon_db/MANIFEST.in b/moonv4/moon_db/MANIFEST.in index ba8a657e..82b40140 100644 --- a/moonv4/moon_db/MANIFEST.in +++ b/moonv4/moon_db/MANIFEST.in @@ -7,5 +7,4 @@ include README.rst include LICENSE include setup.py include requirements.txt -# graft tests graft bin
\ No newline at end of file diff --git a/moonv4/moon_db/README.md b/moonv4/moon_db/README.md new file mode 100644 index 00000000..5aa877fc --- /dev/null +++ b/moonv4/moon_db/README.md @@ -0,0 +1,32 @@ +# moon_db + +This package contains the database module for the Moon project +It is designed to provide a driver to access the Moon database. + +For any other information, refer to the parent project: + + https://git.opnfv.org/moon + +## Build +### Build Python Package +```bash +cd ${MOON_HOME}/moonv4/moon_db +python3 setup.py sdist bdist_wheel +``` + +### Push Python Package to PIP +```bash +cd ${MOON_HOME}/moonv4/moon_db +gpg --detach-sign -u "${GPG_ID}" -a dist/moon_db-X.Y.Z-py3-none-any.whl +gpg --detach-sign -u "${GPG_ID}" -a dist/moon_db-X.Y.Z.tar.gz +twine upload dist/moon_db-X.Y.Z-py3-none-any.whl dist/moon_db-X.Y.Z-py3-none-any.whl.asc +twine upload dist/moon_db-X.Y.Z.tar.gz dist/moon_db-X.Y.Z.tar.gz.asc +``` + +## Test +### Python Unit Test +launch Docker for Python unit tests +```bash +cd ${MOON_HOME}/moonv4/moon_db +docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest +```
\ No newline at end of file diff --git a/moonv4/moon_db/README.rst b/moonv4/moon_db/README.rst deleted file mode 100644 index afee9be5..00000000 --- a/moonv4/moon_db/README.rst +++ /dev/null @@ -1,9 +0,0 @@ -DB module for the Moon project -============================== - -This package contains the database module for the Moon project -It is designed to provide a driver to access the Moon database. - -For any other information, refer to the parent project: - - https://git.opnfv.org/moon diff --git a/moonv4/moon_db/build.sh b/moonv4/moon_db/build.sh new file mode 100644 index 00000000..f109e9b8 --- /dev/null +++ b/moonv4/moon_db/build.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +VERSION=moon_db-$(grep __version__ moon_db/__init__.py | cut -d "\"" -f 2) + +python3 setup.py sdist bdist_wheel + +rm dist/*.asc 2>/dev/null + +gpg --detach-sign -u "A0A96E75" -a dist/${VERSION}-py3-none-any.whl +gpg --detach-sign -u "A0A96E75" -a dist/${VERSION}.tar.gz + +if [ "$1" = "upload" ]; then + twine upload dist/${VERSION}-py3-none-any.whl dist/${VERSION}-py3-none-any.whl.asc + twine upload dist/${VERSION}.tar.gz dist/${VERSION}.tar.gz.asc + rm -f ../moon_orchestrator/dist/moon_db* + rm -f ../moon_interface/dist/moon_db* + rm -f ../moon_manager/dist/moon_db* + rm -f ../moon_authz/dist/moon_db* + rm -f ../moon_wrapper/dist/moon_db* +fi + +if [ "$1" = "copy" ]; then + mkdir -p ../moon_orchestrator/dist/ 2>/dev/null + rm -f ../moon_orchestrator/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_orchestrator/dist/ + mkdir -p ../moon_interface/dist/ 2>/dev/null + rm -f ../moon_interface/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_interface/dist/ + mkdir -p ../moon_manager/dist/ 2>/dev/null + rm -f ../moon_manager/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_manager/dist/ + mkdir -p ../moon_authz/dist/ 2>/dev/null + rm -f ../moon_authz/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_authz/dist/ + mkdir -p ../moon_wrapper/dist/ 2>/dev/null + rm -f ../moon_wrapper/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_wrapper/dist/ +fi diff --git a/moonv4/moon_db/moon_db/__init__.py b/moonv4/moon_db/moon_db/__init__.py index d42cdbdf..0be29aa0 100644 --- a/moonv4/moon_db/moon_db/__init__.py +++ b/moonv4/moon_db/moon_db/__init__.py @@ -3,5 +3,5 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -__version__ = "1.0.3" +__version__ = "1.2.3" diff --git a/moonv4/moon_db/moon_db/api/policy.py b/moonv4/moon_db/moon_db/api/policy.py index e0413bdc..272872ad 100644 --- a/moonv4/moon_db/moon_db/api/policy.py +++ b/moonv4/moon_db/moon_db/api/policy.py @@ -4,11 +4,10 @@ # or at 'http://www.apache.org/licenses/LICENSE-2.0'. from uuid import uuid4 -from oslo_log import log as logging -from moon_utilities.security_functions import filter_input, enforce +import logging +from moon_utilities.security_functions import enforce from moon_db.api.managers import Managers - LOG = logging.getLogger("moon.db.api.policy") @@ -52,9 +51,22 @@ class PolicyManager(Managers): @enforce(("read", "write"), "perimeter") def add_subject(self, user_id, policy_id, perimeter_id=None, value=None): + k_user = Managers.KeystoneManager.get_user_by_name(value.get('name')) + if not k_user['users']: + k_user = Managers.KeystoneManager.create_user(value) if not perimeter_id: - perimeter_id = uuid4().hex - # TODO (asteroide): must check and add Keystone ID here + try: + LOG.info("k_user={}".format(k_user)) + perimeter_id = k_user['users'][0].get('id', uuid4().hex) + except IndexError: + k_user = Managers.KeystoneManager.get_user_by_name( + value.get('name')) + perimeter_id = uuid4().hex + except KeyError: + k_user = Managers.KeystoneManager.get_user_by_name( + value.get('name')) + perimeter_id = uuid4().hex + value.update(k_user['users'][0]) return self.driver.set_subject(policy_id=policy_id, perimeter_id=perimeter_id, value=value) @enforce(("read", "write"), "perimeter") diff --git a/moonv4/moon_db/moon_db/api/tenants.py b/moonv4/moon_db/moon_db/api/tenants.py deleted file mode 100644 index 527e6712..00000000 --- a/moonv4/moon_db/moon_db/api/tenants.py +++ /dev/null @@ -1,137 +0,0 @@ -# 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 uuid import uuid4 -from moon_utilities import exceptions -from moon_db.api.managers import Managers -from moon_utilities.security_functions import filter_input, enforce -from oslo_log import log as logging - -LOG = logging.getLogger("moon.db.api.tenants") - - -class TenantManager(Managers): - - def __init__(self, connector=None): - self.driver = connector.driver - Managers.TenantManager = self - - @filter_input - @enforce("read", "tenants") - def get_tenants_dict(self, user_id): - """ - Return a dictionary with all tenants - :return: { - tenant_id1: { - name: xxx, - description: yyy, - intra_authz_extension_id: zzz, - intra_admin_extension_id: zzz, - }, - tenant_id2: {...}, - ... - } - """ - return self.driver.get_tenants_dict() - - def __get_keystone_tenant_dict(self, tenant_id="", tenant_name=""): - tenants = Managers.KeystoneManager.list_projects() - for tenant in tenants: - if tenant_id and tenant_id == tenant['id']: - return tenant - if tenant_name and tenant_name == tenant['name']: - return tenant - if not tenant_id: - tenant_id = uuid4().hex - if not tenant_name: - tenant_name = tenant_id - tenant = { - "id": tenant_id, - "name": tenant_name, - "description": "Auto generated tenant from Moon platform", - "enabled": True, - "domain_id": "default" - } - keystone_tenant = Managers.KeystoneManager.create_project(tenant["id"], tenant) - return keystone_tenant - - @filter_input - @enforce(("read", "write"), "tenants") - def add_tenant_dict(self, user_id, tenant_id, tenant_dict): - tenants_dict = self.driver.get_tenants_dict() - for tenant_id in tenants_dict: - if tenants_dict[tenant_id]['name'] == tenant_dict['name']: - raise exceptions.TenantAddedNameExisting() - - # Check (and eventually sync) Keystone tenant - if 'id' not in tenant_dict: - tenant_dict['id'] = None - keystone_tenant = self.__get_keystone_tenant_dict(tenant_dict['id'], tenant_dict['name']) - for att in keystone_tenant: - if keystone_tenant[att]: - tenant_dict[att] = keystone_tenant[att] - # Sync users between intra_authz_extension and intra_admin_extension - LOG.debug("add_tenant_dict {}".format(tenant_dict)) - if 'intra_admin_extension_id' in tenant_dict and tenant_dict['intra_admin_extension_id']: - if 'intra_authz_extension_id' in tenant_dict and tenant_dict['intra_authz_extension_id']: - authz_subjects_dict = Managers.IntraExtensionAdminManager.get_subjects_dict( - Managers.IntraExtensionRootManager.root_admin_id, tenant_dict['intra_authz_extension_id']) - authz_subject_names_list = [authz_subjects_dict[subject_id]["name"] for subject_id in authz_subjects_dict] - admin_subjects_dict = Managers.IntraExtensionAdminManager.get_subjects_dict( - Managers.IntraExtensionRootManager.root_admin_id, tenant_dict['intra_admin_extension_id']) - admin_subject_names_list = [admin_subjects_dict[subject_id]["name"] for subject_id in admin_subjects_dict] - for _subject_id in authz_subjects_dict: - if authz_subjects_dict[_subject_id]["name"] not in admin_subject_names_list: - Managers.IntraExtensionAdminManager.add_subject_dict( - Managers.IntraExtensionRootManager.root_admin_id, tenant_dict['intra_admin_extension_id'], authz_subjects_dict[_subject_id]) - for _subject_id in admin_subjects_dict: - if admin_subjects_dict[_subject_id]["name"] not in authz_subject_names_list: - Managers.IntraExtensionAdminManager.add_subject_dict( - Managers.IntraExtensionRootManager.root_admin_id, tenant_dict['intra_authz_extension_id'], admin_subjects_dict[_subject_id]) - - return self.driver.add_tenant_dict(tenant_dict['id'], tenant_dict) - - @filter_input - @enforce("read", "tenants") - def get_tenant_dict(self, user_id, tenant_id): - tenants_dict = self.driver.get_tenants_dict() - if tenant_id not in tenants_dict: - raise exceptions.TenantUnknown() - return tenants_dict[tenant_id] - - @filter_input - @enforce(("read", "write"), "tenants") - def del_tenant(self, user_id, tenant_id): - if tenant_id not in self.driver.get_tenants_dict(): - raise exceptions.TenantUnknown() - self.driver.del_tenant(tenant_id) - - @filter_input - @enforce(("read", "write"), "tenants") - def set_tenant_dict(self, user_id, tenant_id, tenant_dict): - tenants_dict = self.driver.get_tenants_dict() - if tenant_id not in tenants_dict: - raise exceptions.TenantUnknown() - - # Sync users between intra_authz_extension and intra_admin_extension - if 'intra_admin_extension_id' in tenant_dict: - if 'intra_authz_extension_id' in tenant_dict: - authz_subjects_dict = Managers.IntraExtensionAdminManager.get_subjects_dict( - Managers.IntraExtensionRootManager.root_admin_id, tenant_dict['intra_authz_extension_id']) - authz_subject_names_list = [authz_subjects_dict[subject_id]["name"] for subject_id in authz_subjects_dict] - admin_subjects_dict = Managers.IntraExtensionAdminManager.get_subjects_dict( - Managers.IntraExtensionRootManager.root_admin_id, tenant_dict['intra_admin_extension_id']) - admin_subject_names_list = [admin_subjects_dict[subject_id]["name"] for subject_id in admin_subjects_dict] - for _subject_id in authz_subjects_dict: - if authz_subjects_dict[_subject_id]["name"] not in admin_subject_names_list: - Managers.IntraExtensionAdminManager.add_subject_dict( - Managers.IntraExtensionRootManager.root_admin_id, tenant_dict['intra_admin_extension_id'], authz_subjects_dict[_subject_id]) - for _subject_id in admin_subjects_dict: - if admin_subjects_dict[_subject_id]["name"] not in authz_subject_names_list: - Managers.IntraExtensionAdminManager.add_subject_dict( - Managers.IntraExtensionRootManager.root_admin_id, tenant_dict['intra_authz_extension_id'], admin_subjects_dict[_subject_id]) - - return self.driver.set_tenant_dict(tenant_id, tenant_dict) - diff --git a/moonv4/moon_db/moon_db/backends/memory.py b/moonv4/moon_db/moon_db/backends/memory.py deleted file mode 100644 index 5762b183..00000000 --- a/moonv4/moon_db/moon_db/backends/memory.py +++ /dev/null @@ -1,60 +0,0 @@ -# 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'. - -import os -import json -import logging -import hashlib -from glob import glob -from oslo_config import cfg -from moon_db.core import ConfigurationDriver - -LOG = logging.getLogger("moon.db.driver.memory") -CONF = cfg.CONF - - -class ConfigurationConnector(object): - - def __init__(self, engine): - super(ConfigurationConnector, self).__init__() - self.policy_directory = CONF.policy_directory - self.aggregation_algorithms_dict = dict() - self.aggregation_algorithms_dict[hashlib.sha224("all_true".encode("utf-8")).hexdigest()[:32]] = \ - {'name': 'all_true', 'description': 'all rules must match'} - self.aggregation_algorithms_dict[hashlib.sha224("one_true".encode("utf-8")).hexdigest()[:32]] = \ - {'name': 'one_true', 'description': 'only one rule has to match'} - self.sub_meta_rule_algorithms_dict = dict() - self.sub_meta_rule_algorithms_dict[hashlib.sha224("inclusion".encode("utf-8")).hexdigest()[:32]] = \ - {'name': 'inclusion', 'description': 'inclusion'} - self.sub_meta_rule_algorithms_dict[hashlib.sha224("comparison".encode("utf-8")).hexdigest()[:32]] = \ - {'name': 'comparison', 'description': 'comparison'} - - def get_policy_templates_dict(self): - """ - :return: { - template_id1: {name: template_name, description: template_description}, - template_id2: {name: template_name, description: template_description}, - ... - } - """ - nodes = glob(os.path.join(self.policy_directory, "*")) - LOG.info("get_policy_templates_dict {} {}".format(self.policy_directory, nodes)) - templates = dict() - for node in nodes: - try: - metadata = json.load(open(os.path.join(node, "metadata.json"))) - except IOError: - # Note (asteroide): it's not a true policy directory, so we forgive it - continue - templates[os.path.basename(node)] = dict() - templates[os.path.basename(node)]["name"] = metadata["name"] - templates[os.path.basename(node)]["description"] = metadata["description"] - return templates - - def get_aggregation_algorithms_dict(self): - return self.aggregation_algorithms_dict - - def get_sub_meta_rule_algorithms_dict(self): - return self.sub_meta_rule_algorithms_dict diff --git a/moonv4/moon_db/moon_db/db_manager.py b/moonv4/moon_db/moon_db/db_manager.py index 81e6fe77..75cbcdb0 100644 --- a/moonv4/moon_db/moon_db/db_manager.py +++ b/moonv4/moon_db/moon_db/db_manager.py @@ -14,51 +14,69 @@ from sqlalchemy import create_engine from moon_db.migrate_repo import versions from moon_utilities import configuration -parser = argparse.ArgumentParser() -parser.add_argument('command', help='command (upgrade or downgrade)', nargs=1) -parser.add_argument("--verbose", "-v", action='store_true', help="verbose mode") -parser.add_argument("--debug", "-d", action='store_true', help="debug mode") -args = parser.parse_args() -FORMAT = '%(asctime)-15s %(levelname)s %(message)s' -if args.debug: - logging.basicConfig( - format=FORMAT, - level=logging.DEBUG) -elif args.verbose: - logging.basicConfig( - format=FORMAT, - level=logging.INFO) -else: - logging.basicConfig( - format=FORMAT, - level=logging.WARNING) +def init_args(): + parser = argparse.ArgumentParser() + parser.add_argument('command', help='command (upgrade or downgrade)', + nargs=1) + parser.add_argument("--verbose", "-v", action='store_true', + help="verbose mode") + parser.add_argument("--debug", "-d", action='store_true', + help="debug mode") + args = parser.parse_args() -requests_log = logging.getLogger("requests.packages.urllib3") -requests_log.setLevel(logging.WARNING) -requests_log.propagate = True + FORMAT = '%(asctime)-15s %(levelname)s %(message)s' + if args.debug: + logging.basicConfig( + format=FORMAT, + level=logging.DEBUG) + elif args.verbose: + logging.basicConfig( + format=FORMAT, + level=logging.INFO) + else: + logging.basicConfig( + format=FORMAT, + level=logging.WARNING) -logger = logging.getLogger("moon.db.manager") + requests_log = logging.getLogger("requests.packages.urllib3") + requests_log.setLevel(logging.WARNING) + requests_log.propagate = True -db_conf = configuration.get_configuration("database")["database"] -engine = create_engine(db_conf['url']) + logger = logging.getLogger("moon.db.manager") + return args, logger -def format_data(ext): - return ext.name, ext.obj.upgrade() +def init_engine(): + db_conf = configuration.get_configuration("database")["database"] + return create_engine(db_conf['url']) -def run(): +def main(command, logger, engine): files = glob.glob(versions.__path__[0] + "/[0-9][0-9][0-9]*.py") for filename in files: filename = os.path.basename(filename).replace(".py", "") - o = importlib.import_module("moon_db.migrate_repo.versions.{}".format(filename)) - logger.info("Command is {}".format(args.command[0])) - if args.command[0] in ("upgrade", "u", "up"): - logger.info("upgrading moon_db.migrate_repo.versions.{}".format(filename)) + o = importlib.import_module( + "moon_db.migrate_repo.versions.{}".format(filename)) + logger.info("Command is {}".format(command)) + if command in ("upgrade", "u", "up"): + logger.info( + "upgrading moon_db.migrate_repo.versions.{}".format(filename)) o.upgrade(engine) - elif args.command[0] in ("downgrade", "d", "down"): - logger.info("downgrading moon_db.migrate_repo.versions.{}".format(filename)) + elif command in ("downgrade", "d", "down"): + logger.info( + "downgrading moon_db.migrate_repo.versions.{}".format( + filename)) o.downgrade(engine) else: logger.critical("Cannot understand the command!") + + +def run(): + args, logger = init_args() + engine = init_engine() + main(args.command[0], logger, engine) + + +if __name__ == "__main__": + run() diff --git a/moonv4/moon_db/setup.py b/moonv4/moon_db/setup.py index 0d2aa1bf..0cd90940 100644 --- a/moonv4/moon_db/setup.py +++ b/moonv4/moon_db/setup.py @@ -24,7 +24,7 @@ setup( description="This library is a helper to interact with the Moon database.", - long_description=open('README.rst').read(), + long_description=open('README.md').read(), install_requires=required, @@ -46,7 +46,6 @@ setup( [ "sql = moon_db.backends.sql:SQLConnector", "flat = moon_db.backends.flat:LogConnector", - "memory = moon_db.backends.memory:ConfigurationConnector", ], 'console_scripts': [ 'moon_db_manager = moon_db.db_manager:run', diff --git a/moonv4/moon_db/tests/configure_db.sh b/moonv4/moon_db/tests/configure_db.sh deleted file mode 100644 index bdc259fe..00000000 --- a/moonv4/moon_db/tests/configure_db.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -apt-get install mysql-server python-mysqldb python-pymysql - -mysql -uroot -ppassword <<EOF -CREATE DATABASE moon DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; -GRANT ALL ON moon.* TO 'moonuser'@'%' IDENTIFIED BY 'password'; -GRANT ALL ON moon.* TO 'moonuser'@'localhost' IDENTIFIED BY 'password'; -EOF diff --git a/moonv4/moon_db/tests/test_intraextension.py b/moonv4/moon_db/tests/test_intraextension.py deleted file mode 100644 index a2267214..00000000 --- a/moonv4/moon_db/tests/test_intraextension.py +++ /dev/null @@ -1,44 +0,0 @@ -# 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'. - - -import moon_db -import uuid - -Connector = moon_db.Driver("sql", "mysql+pymysql://moonuser:password@localhost/moon") -Connector.driver.init_db() - - -def create_intra_extension(policy_model="policy_authz"): - ie = dict() - ie['id'] = uuid.uuid4().hex - ie["name"] = "test IE " + uuid.uuid4().hex - ie["policymodel"] = "policy_authz" - ie["description"] = "a simple description." - ie["model"] = policy_model - genre = "admin" - if "authz" in policy_model: - genre = "authz" - ie["genre"] = genre - # ref = self.admin_api.load_intra_extension_dict(self.root_api.root_admin_id, - # intra_extension_dict=ie) - # self.admin_api.populate_default_data(ref) - return ie - - -def test_get_intraextension(): - t = Connector.driver.get_intra_extensions_dict() - assert type(t) == dict - - -def test_set_intra_extension(): - number_of_ie = len(Connector.driver.get_intra_extensions_dict()) - ie = create_intra_extension() - data = Connector.driver.set_intra_extension_dict(ie['id'], ie) - assert type(data) == dict - assert len(Connector.driver.get_intra_extensions_dict()) == number_of_ie+1 - - -# TODO (dthom): all tests can be got from keystone-moon diff --git a/moonv4/moon_db/tests/test_tenant.py b/moonv4/moon_db/tests/test_tenant.py deleted file mode 100644 index 7e6cfa82..00000000 --- a/moonv4/moon_db/tests/test_tenant.py +++ /dev/null @@ -1,86 +0,0 @@ -# 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'. - -import moon_db -import uuid - -Connector = moon_db.Driver("sql", "mysql+pymysql://moonuser:password@localhost/moon") -Connector.driver.init_db() - - -def test_get_tenants(): - t = Connector.driver.get_tenants_dict() - print(t) - assert type(t) == dict - - -def test_add_tenant(): - new_tenant = { - "id": uuid.uuid4().hex, - "name": "demo", - "description": uuid.uuid4().hex, - "intra_authz_extension_id": "", - "intra_admin_extension_id": "", - } - data = Connector.driver.add_tenant_dict(tenant_id=new_tenant['id'], - tenant_dict=new_tenant) - data_id = list(data.keys())[0] - assert new_tenant["id"] == data_id - assert new_tenant["name"] == data[data_id]["name"] - assert new_tenant["intra_authz_extension_id"] == data[data_id]["intra_authz_extension_id"] - assert new_tenant["intra_admin_extension_id"] == data[data_id]["intra_admin_extension_id"] - data = Connector.driver.get_tenants_dict() - assert data != {} - - -def test_del_tenant(): - new_tenant = { - "id": uuid.uuid4().hex, - "name": "demo", - "description": uuid.uuid4().hex, - "intra_authz_extension_id": "", - "intra_admin_extension_id": "", - } - data = Connector.driver.get_tenants_dict() - number_of_tenant = len(data.keys()) - data = Connector.driver.add_tenant_dict(tenant_id=new_tenant['id'], - tenant_dict=new_tenant) - data_id = list(data.keys())[0] - assert new_tenant["name"] == data[data_id]["name"] - assert new_tenant["intra_authz_extension_id"] == data[data_id]["intra_authz_extension_id"] - assert new_tenant["intra_admin_extension_id"] == data[data_id]["intra_admin_extension_id"] - data = Connector.driver.get_tenants_dict() - assert len(data.keys()) == number_of_tenant+1 - Connector.driver.del_tenant(data_id) - data = Connector.driver.get_tenants_dict() - assert len(data.keys()) == number_of_tenant - - -def test_set_tenant(): - new_tenant = { - "id": uuid.uuid4().hex, - "name": "demo", - "description": uuid.uuid4().hex, - "intra_authz_extension_id": "123456", - "intra_admin_extension_id": "0987654", - } - data = Connector.driver.get_tenants_dict() - number_of_tenant = len(data.keys()) - data = Connector.driver.add_tenant_dict(tenant_id=new_tenant['id'], - tenant_dict=new_tenant) - data_id = list(data.keys())[0] - assert new_tenant["name"] == data[data_id]["name"] - assert new_tenant["intra_authz_extension_id"] == data[data_id]["intra_authz_extension_id"] - assert new_tenant["intra_admin_extension_id"] == data[data_id]["intra_admin_extension_id"] - data = Connector.driver.get_tenants_dict() - assert len(data.keys()) == number_of_tenant+1 - - new_tenant["name"] = "demo2" - data = Connector.driver.set_tenant_dict(tenant_id=data_id, tenant_dict=new_tenant) - data_id = list(data.keys())[0] - assert new_tenant["name"] == data[data_id]["name"] - assert new_tenant["intra_authz_extension_id"] == data[data_id]["intra_authz_extension_id"] - assert new_tenant["intra_admin_extension_id"] == data[data_id]["intra_admin_extension_id"] - diff --git a/moonv4/moon_db/tests/unit_python/conftest.py b/moonv4/moon_db/tests/unit_python/conftest.py new file mode 100644 index 00000000..c2e5e579 --- /dev/null +++ b/moonv4/moon_db/tests/unit_python/conftest.py @@ -0,0 +1,145 @@ +import base64 +import json +import logging +import os +import pytest +import requests_mock +import mock_components +import mock_keystone + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "interface" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + + +@pytest.fixture +def db(): + return CONF['database'] + + +@pytest.fixture(autouse=True) +def set_consul_and_db(monkeypatch): + """ Modify the response from Requests module + """ + with requests_mock.Mocker(real_http=True) as m: + mock_components.register_components(m) + mock_keystone.register_keystone(m) + + from moon_db.db_manager import init_engine, main + engine = init_engine() + main("upgrade", logging.getLogger("db_manager"), engine) + yield m + os.unlink(CONF['database']['url'].replace("sqlite:///", "")) + + diff --git a/moonv4/moon_db/tests/unit_python/mock_components.py b/moonv4/moon_db/tests/unit_python/mock_components.py new file mode 100644 index 00000000..a0319e1a --- /dev/null +++ b/moonv4/moon_db/tests/unit_python/mock_components.py @@ -0,0 +1,27 @@ +import utilities + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", + "components/orchestrator", + "components/interface", +) + + +def register_components(m): + for component in COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': utilities.get_b64_conf(component)}] + ) + + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/components?recurse=true', + json=[ + {"Key": key, "Value": utilities.get_b64_conf(key)} for key in COMPONENTS + ], + # json={'Key': "components", 'Value': get_b64_conf("components")} + )
\ No newline at end of file diff --git a/moonv4/moon_db/tests/unit_python/mock_keystone.py b/moonv4/moon_db/tests/unit_python/mock_keystone.py new file mode 100644 index 00000000..c0b26b88 --- /dev/null +++ b/moonv4/moon_db/tests/unit_python/mock_keystone.py @@ -0,0 +1,23 @@ +def register_keystone(m): + m.register_uri( + 'POST', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'DELETE', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users/', + json={"users": [{ + "id": "1111111111111" + }]} + )
\ No newline at end of file diff --git a/moonv4/moon_db/tests/unit_python/requirements.txt b/moonv4/moon_db/tests/unit_python/requirements.txt new file mode 100644 index 00000000..d6110d12 --- /dev/null +++ b/moonv4/moon_db/tests/unit_python/requirements.txt @@ -0,0 +1,5 @@ +sqlalchemy +pymysql +pytest +requests_mock +moon_utilities
\ No newline at end of file diff --git a/moonv4/moon_db/tests/unit_python/test_policies.py b/moonv4/moon_db/tests/unit_python/test_policies.py new file mode 100644 index 00000000..3bd1360e --- /dev/null +++ b/moonv4/moon_db/tests/unit_python/test_policies.py @@ -0,0 +1,77 @@ +# 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'. + + +def get_policies(): + from moon_db.core import PolicyManager + return PolicyManager.get_policies("admin") + + +def add_policies(value=None): + from moon_db.core import PolicyManager + if not value: + value = { + "name": "test_policiy", + "model_id": "", + "genre": "authz", + "description": "test", + } + return PolicyManager.add_policy("admin", value=value) + + +def delete_policies(uuid=None, name=None): + from moon_db.core import PolicyManager + if not uuid: + for policy_id, policy_value in get_policies(): + if name == policy_value['name']: + uuid = policy_id + break + PolicyManager.delete_policy("admin", uuid) + + +def test_get_policies(db): + policies = get_policies() + assert isinstance(policies, dict) + assert not policies + + +def test_add_policies(db): + value = { + "name": "test_policy", + "model_id": "", + "genre": "authz", + "description": "test", + } + policies = add_policies(value) + assert isinstance(policies, dict) + assert policies + assert len(policies.keys()) == 1 + policy_id = list(policies.keys())[0] + for key in ("genre", "name", "model_id", "description"): + assert key in policies[policy_id] + assert policies[policy_id][key] == value[key] + + +def test_delete_policies(db): + value = { + "name": "test_policy1", + "model_id": "", + "genre": "authz", + "description": "test", + } + policies = add_policies(value) + policy_id1 = list(policies.keys())[0] + value = { + "name": "test_policy2", + "model_id": "", + "genre": "authz", + "description": "test", + } + policies = add_policies(value) + policy_id2 = list(policies.keys())[0] + assert policy_id1 != policy_id2 + delete_policies(policy_id1) + policies = get_policies() + assert policy_id1 not in policies diff --git a/moonv4/moon_db/tests/unit_python/utilities.py b/moonv4/moon_db/tests/unit_python/utilities.py new file mode 100644 index 00000000..1d79d890 --- /dev/null +++ b/moonv4/moon_db/tests/unit_python/utilities.py @@ -0,0 +1,136 @@ +import base64 +import json + + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "interface" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + + +def get_b64_conf(component=None): + if component == "components": + return base64.b64encode( + json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8') + elif component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif not component: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') diff --git a/moonv4/moon_gui/DEV.md b/moonv4/moon_gui/DEV.md new file mode 100644 index 00000000..28743da3 --- /dev/null +++ b/moonv4/moon_gui/DEV.md @@ -0,0 +1,49 @@ +# How-to develop on the Moon platform + +## Install the platform + +Follow the `moon/moonv4/README.md` file. + +## GUI + +The GUI code is located at `moon/moonv4/moon_gui` +The configuration values is at `moonv4/moon_gui/static/app/moon.constants.js` + +To be able to only develop the GUI, you can install the Moon platform and run the GUI outside the platform. +To link the outside GUI to the Moon Manager, you must update the configuration values and specially the +following variables : + +- `{{MANAGER_HOST}}` : the hostname of the Manager (example: 127.0.0.1) +- `{{MANAGER_PORT}}` : the TCP port of the Manager (30001) +- `{{KEYSTONE_HOST}}` : the hostname of the Keystone server (example: 127.0.0.1) +- `{{KEYSTONE_PORT}}` : the TCP port of the Keystone server (30006) + +To run the GUI service, follow the `README.md` file. + +## Current bugs + +1) Models -> "`List of Meta rules`", after updating the meta_rule +"`Actions` -> `edit`" and clicking on `close`, the main screen doesn't refresh + +2) idem if we want to remove the meta_rule + +3) after deleting an action perimeter (`Policy` -> `Add an action` -> `select a perimeter` and delete it), +the dropdown list is not updated + +4) when adding a data subject (`Policy` -> `Data` -> `Add a Data Subject`), only the right category names must +be listed in `Catagory list`. Hide the categories that doesn't belong to that policy. + +5) idem for object data + +6) idem for action data + +7) after adding data (subject, object, action), the dropdown list in `Rules` -> `Add a rules` are not updated +if the page is not manually refresh by the user and if the `Rules` window is already showing. + +8) typographic error in `Add a rules` + +9) in `Data` -> `Add a Data Object`, the `Create Data` never create the data in the backend + +10) Move the `project` tabular to the end + +11) create a simplified version (to be discussed) diff --git a/moonv4/moon_gui/Dockerfile b/moonv4/moon_gui/Dockerfile index ef809668..428e1037 100644 --- a/moonv4/moon_gui/Dockerfile +++ b/moonv4/moon_gui/Dockerfile @@ -1,11 +1,18 @@ FROM ubuntu:latest -RUN apt update && apt install nodejs nodejs-legacy npm -y +RUN apt update && apt install git nodejs nodejs-legacy npm apache2 -y RUN npm install --global gulp-cli +ENV MANAGER_HOST="127.0.0.1" +ENV MANAGER_PORT=8080 +ENV KEYSTONE_HOST="127.0.0.1" +ENV KEYSTONE_PORT=5000 + ADD . /root WORKDIR /root/ + RUN npm install -RUN gulp delivery -CMD ["gulp", "webServerDelivery"]
\ No newline at end of file +#CMD ["gulp"] +#CMD ["gulp", "webServerDelivery"] +CMD ["sh", "/root/run.sh"]
\ No newline at end of file diff --git a/moonv4/moon_gui/readme.md b/moonv4/moon_gui/README.md index ff6e5a97..ff6e5a97 100644 --- a/moonv4/moon_gui/readme.md +++ b/moonv4/moon_gui/README.md diff --git a/moonv4/moon_gui/run.sh b/moonv4/moon_gui/run.sh new file mode 100644 index 00000000..94bc8360 --- /dev/null +++ b/moonv4/moon_gui/run.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +service apache2 start + +sed "s/{{MANAGER_HOST}}/$MANAGER_HOST/g" -i /root/static/app/moon.constants.js +sed "s/{{MANAGER_PORT}}/$MANAGER_PORT/g" -i /root/static/app/moon.constants.js +sed "s/{{KEYSTONE_HOST}}/$KEYSTONE_HOST/g" -i /root/static/app/moon.constants.js +sed "s/{{KEYSTONE_PORT}}/$KEYSTONE_PORT/g" -i /root/static/app/moon.constants.js + +echo "--------------------------" +cat /root/static/app/moon.constants.js +echo "--------------------------" + +gulp delivery +cp -rv /root/delivery/* /var/www/html + +tail -f /var/log/apache2/error.log diff --git a/moonv4/moon_gui/static/app/authentication/authentication.controller.js b/moonv4/moon_gui/static/app/authentication/authentication.controller.js index ce38bc5f..ce38bc5f 100644..100755 --- a/moonv4/moon_gui/static/app/authentication/authentication.controller.js +++ b/moonv4/moon_gui/static/app/authentication/authentication.controller.js diff --git a/moonv4/moon_gui/static/app/authentication/authentication.tpl.html b/moonv4/moon_gui/static/app/authentication/authentication.tpl.html index 77d1646b..77d1646b 100644..100755 --- a/moonv4/moon_gui/static/app/authentication/authentication.tpl.html +++ b/moonv4/moon_gui/static/app/authentication/authentication.tpl.html diff --git a/moonv4/moon_gui/static/app/common/404/404.tpl.html b/moonv4/moon_gui/static/app/common/404/404.tpl.html index 61e0420c..61e0420c 100644..100755 --- a/moonv4/moon_gui/static/app/common/404/404.tpl.html +++ b/moonv4/moon_gui/static/app/common/404/404.tpl.html diff --git a/moonv4/moon_gui/static/app/common/compatibility/compatibility.tpl.html b/moonv4/moon_gui/static/app/common/compatibility/compatibility.tpl.html index 0e32dc4f..0e32dc4f 100644..100755 --- a/moonv4/moon_gui/static/app/common/compatibility/compatibility.tpl.html +++ b/moonv4/moon_gui/static/app/common/compatibility/compatibility.tpl.html diff --git a/moonv4/moon_gui/static/app/common/footer/footer.controller.js b/moonv4/moon_gui/static/app/common/footer/footer.controller.js index d7506840..d7506840 100644..100755 --- a/moonv4/moon_gui/static/app/common/footer/footer.controller.js +++ b/moonv4/moon_gui/static/app/common/footer/footer.controller.js diff --git a/moonv4/moon_gui/static/app/common/footer/footer.tpl.html b/moonv4/moon_gui/static/app/common/footer/footer.tpl.html index aacb392d..aacb392d 100644..100755 --- a/moonv4/moon_gui/static/app/common/footer/footer.tpl.html +++ b/moonv4/moon_gui/static/app/common/footer/footer.tpl.html diff --git a/moonv4/moon_gui/static/app/common/header/header.controller.js b/moonv4/moon_gui/static/app/common/header/header.controller.js index 13ef4d6f..13ef4d6f 100644..100755 --- a/moonv4/moon_gui/static/app/common/header/header.controller.js +++ b/moonv4/moon_gui/static/app/common/header/header.controller.js diff --git a/moonv4/moon_gui/static/app/common/header/header.tpl.html b/moonv4/moon_gui/static/app/common/header/header.tpl.html index f703fa79..f703fa79 100644..100755 --- a/moonv4/moon_gui/static/app/common/header/header.tpl.html +++ b/moonv4/moon_gui/static/app/common/header/header.tpl.html diff --git a/moonv4/moon_gui/static/app/common/loader/loader.dir.js b/moonv4/moon_gui/static/app/common/loader/loader.dir.js index ba40c121..ba40c121 100644..100755 --- a/moonv4/moon_gui/static/app/common/loader/loader.dir.js +++ b/moonv4/moon_gui/static/app/common/loader/loader.dir.js diff --git a/moonv4/moon_gui/static/app/common/loader/loader.tpl.html b/moonv4/moon_gui/static/app/common/loader/loader.tpl.html index 51da439f..51da439f 100644..100755 --- a/moonv4/moon_gui/static/app/common/loader/loader.tpl.html +++ b/moonv4/moon_gui/static/app/common/loader/loader.tpl.html diff --git a/moonv4/moon_gui/static/app/common/waiting/waiting.tpl.html b/moonv4/moon_gui/static/app/common/waiting/waiting.tpl.html index 6c042635..6c042635 100644..100755 --- a/moonv4/moon_gui/static/app/common/waiting/waiting.tpl.html +++ b/moonv4/moon_gui/static/app/common/waiting/waiting.tpl.html diff --git a/moonv4/moon_gui/static/app/dashboard/dashboard.tpl.html b/moonv4/moon_gui/static/app/dashboard/dashboard.tpl.html index 67184bcc..67184bcc 100644..100755 --- a/moonv4/moon_gui/static/app/dashboard/dashboard.tpl.html +++ b/moonv4/moon_gui/static/app/dashboard/dashboard.tpl.html diff --git a/moonv4/moon_gui/static/app/logs/logs.controller.js b/moonv4/moon_gui/static/app/logs/logs.controller.js index e48e2b8b..e48e2b8b 100644..100755 --- a/moonv4/moon_gui/static/app/logs/logs.controller.js +++ b/moonv4/moon_gui/static/app/logs/logs.controller.js diff --git a/moonv4/moon_gui/static/app/logs/logs.tpl.html b/moonv4/moon_gui/static/app/logs/logs.tpl.html index fecc0289..fecc0289 100644..100755 --- a/moonv4/moon_gui/static/app/logs/logs.tpl.html +++ b/moonv4/moon_gui/static/app/logs/logs.tpl.html diff --git a/moonv4/moon_gui/static/app/model/action/model-add.tpl.html b/moonv4/moon_gui/static/app/model/action/model-add.tpl.html index dee53a97..dee53a97 100644..100755 --- a/moonv4/moon_gui/static/app/model/action/model-add.tpl.html +++ b/moonv4/moon_gui/static/app/model/action/model-add.tpl.html diff --git a/moonv4/moon_gui/static/app/model/action/model-delete.tpl.html b/moonv4/moon_gui/static/app/model/action/model-delete.tpl.html index cde16d0e..cde16d0e 100644..100755 --- a/moonv4/moon_gui/static/app/model/action/model-delete.tpl.html +++ b/moonv4/moon_gui/static/app/model/action/model-delete.tpl.html diff --git a/moonv4/moon_gui/static/app/model/action/model-view.tpl.html b/moonv4/moon_gui/static/app/model/action/model-view.tpl.html index 46c295c7..46c295c7 100644..100755 --- a/moonv4/moon_gui/static/app/model/action/model-view.tpl.html +++ b/moonv4/moon_gui/static/app/model/action/model-view.tpl.html diff --git a/moonv4/moon_gui/static/app/model/action/model.controller.add.js b/moonv4/moon_gui/static/app/model/action/model.controller.add.js index 11d3abf4..11d3abf4 100644..100755 --- a/moonv4/moon_gui/static/app/model/action/model.controller.add.js +++ b/moonv4/moon_gui/static/app/model/action/model.controller.add.js diff --git a/moonv4/moon_gui/static/app/model/action/model.controller.delete.js b/moonv4/moon_gui/static/app/model/action/model.controller.delete.js index 5d9dae1a..5d9dae1a 100644..100755 --- a/moonv4/moon_gui/static/app/model/action/model.controller.delete.js +++ b/moonv4/moon_gui/static/app/model/action/model.controller.delete.js diff --git a/moonv4/moon_gui/static/app/model/action/model.controller.view.js b/moonv4/moon_gui/static/app/model/action/model.controller.view.js index 7605eecf..7605eecf 100644..100755 --- a/moonv4/moon_gui/static/app/model/action/model.controller.view.js +++ b/moonv4/moon_gui/static/app/model/action/model.controller.view.js diff --git a/moonv4/moon_gui/static/app/model/edit/metadata/metadata-edit.tpl.html b/moonv4/moon_gui/static/app/model/edit/metadata/metadata-edit.tpl.html index 2616be1c..2616be1c 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metadata/metadata-edit.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/metadata/metadata-edit.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/metadata/metadata-list.tpl.html b/moonv4/moon_gui/static/app/model/edit/metadata/metadata-list.tpl.html index 30a42dbc..30a42dbc 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metadata/metadata-list.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/metadata/metadata-list.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/metadata/metadata.edit.dir.js b/moonv4/moon_gui/static/app/model/edit/metadata/metadata.edit.dir.js index 10df83b0..10df83b0 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metadata/metadata.edit.dir.js +++ b/moonv4/moon_gui/static/app/model/edit/metadata/metadata.edit.dir.js diff --git a/moonv4/moon_gui/static/app/model/edit/metadata/metadata.list.dir.js b/moonv4/moon_gui/static/app/model/edit/metadata/metadata.list.dir.js index beb2ed86..beb2ed86 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metadata/metadata.list.dir.js +++ b/moonv4/moon_gui/static/app/model/edit/metadata/metadata.list.dir.js diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-add.tpl.html b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-add.tpl.html index a721e6d0..a721e6d0 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-add.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-add.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-map.tpl.html b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-map.tpl.html index 1830204b..1830204b 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-map.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-map.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-unmap.tpl.html b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-unmap.tpl.html index bb02aba2..bb02aba2 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-unmap.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-unmap.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.controller.add.js b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.controller.add.js index a95951fa..a95951fa 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.controller.add.js +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.controller.add.js diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.map.controller.js b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.map.controller.js index cf9ba06c..cf9ba06c 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.map.controller.js +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.map.controller.js diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.unmap.controller.js b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.unmap.controller.js index 30f32d51..30f32d51 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.unmap.controller.js +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.unmap.controller.js diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules-edit-basic.tpl.html b/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules-edit-basic.tpl.html index b6136195..b6136195 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules-edit-basic.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules-edit-basic.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules-edit.tpl.html b/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules-edit.tpl.html index 7b074448..7b074448 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules-edit.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules-edit.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules.controller.edit.js b/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules.controller.edit.js index b2ebc45d..b2ebc45d 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules.controller.edit.js +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules.controller.edit.js diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules.edit.basic.dir.js b/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules.edit.basic.dir.js index 603e7a33..603e7a33 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules.edit.basic.dir.js +++ b/moonv4/moon_gui/static/app/model/edit/metarules/action/metarules.edit.basic.dir.js diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/metarules-list.tpl.html b/moonv4/moon_gui/static/app/model/edit/metarules/metarules-list.tpl.html index ebe307c3..ebe307c3 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/metarules-list.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/metarules/metarules-list.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/metarules/metarules.list.dir.js b/moonv4/moon_gui/static/app/model/edit/metarules/metarules.list.dir.js index 120b6a8b..120b6a8b 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/metarules/metarules.list.dir.js +++ b/moonv4/moon_gui/static/app/model/edit/metarules/metarules.list.dir.js diff --git a/moonv4/moon_gui/static/app/model/edit/model-edit-basic.tpl.html b/moonv4/moon_gui/static/app/model/edit/model-edit-basic.tpl.html index bd73b4ef..bd73b4ef 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/model-edit-basic.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/model-edit-basic.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/model-edit.tpl.html b/moonv4/moon_gui/static/app/model/edit/model-edit.tpl.html index 4955f441..4955f441 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/model-edit.tpl.html +++ b/moonv4/moon_gui/static/app/model/edit/model-edit.tpl.html diff --git a/moonv4/moon_gui/static/app/model/edit/model.controller.edit.js b/moonv4/moon_gui/static/app/model/edit/model.controller.edit.js index 3e10a533..3e10a533 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/model.controller.edit.js +++ b/moonv4/moon_gui/static/app/model/edit/model.controller.edit.js diff --git a/moonv4/moon_gui/static/app/model/edit/model.edit.basic.dir.js b/moonv4/moon_gui/static/app/model/edit/model.edit.basic.dir.js index 54bb7071..54bb7071 100644..100755 --- a/moonv4/moon_gui/static/app/model/edit/model.edit.basic.dir.js +++ b/moonv4/moon_gui/static/app/model/edit/model.edit.basic.dir.js diff --git a/moonv4/moon_gui/static/app/model/model-list.tpl.html b/moonv4/moon_gui/static/app/model/model-list.tpl.html index 89c682cc..89c682cc 100644..100755 --- a/moonv4/moon_gui/static/app/model/model-list.tpl.html +++ b/moonv4/moon_gui/static/app/model/model-list.tpl.html diff --git a/moonv4/moon_gui/static/app/model/model.controller.list.js b/moonv4/moon_gui/static/app/model/model.controller.list.js index 5021a57e..5021a57e 100644..100755 --- a/moonv4/moon_gui/static/app/model/model.controller.list.js +++ b/moonv4/moon_gui/static/app/model/model.controller.list.js diff --git a/moonv4/moon_gui/static/app/moon.constants.js b/moonv4/moon_gui/static/app/moon.constants.js index 872dfd5a..9681e3dc 100644 --- a/moonv4/moon_gui/static/app/moon.constants.js +++ b/moonv4/moon_gui/static/app/moon.constants.js @@ -59,21 +59,21 @@ } }) .constant('REST_URI', { - PDP : 'http://interface:8081/pdp/', - MODELS : 'http://interface:8081/models/', - METARULES: 'http://interface:8081/meta_rules/', - RULES: 'http://interface:8081/rules/', - POLICIES: 'http://interface:8081/policies/', + PDP : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/pdp/', + MODELS : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/models/', + METARULES: 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/meta_rules/', + RULES: 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/rules/', + POLICIES: 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/policies/', METADATA: { - subject : 'http://interface:8081/subject_categories/', - object : 'http://interface:8081/object_categories/', - action : 'http://interface:8081/action_categories/' + subject : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/subject_categories/', + object : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/object_categories/', + action : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/action_categories/' }, PERIMETERS :{ - subject : 'http://interface:8081/subjects/', - object : 'http://interface:8081/objects/', - action : 'http://interface:8081/actions/' + subject : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/subjects/', + object : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/objects/', + action : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/actions/' }, - KEYSTONE : 'http://keystone:5000/v3/' + KEYSTONE : 'http://{{KEYSTONE_HOST}}:{{KEYSTONE_PORT}}/v3/' }); })(); diff --git a/moonv4/moon_gui/static/app/moon.module.js b/moonv4/moon_gui/static/app/moon.module.js index a653f8f3..a653f8f3 100644..100755 --- a/moonv4/moon_gui/static/app/moon.module.js +++ b/moonv4/moon_gui/static/app/moon.module.js diff --git a/moonv4/moon_gui/static/app/pdp/action/pdp-add.tpl.html b/moonv4/moon_gui/static/app/pdp/action/pdp-add.tpl.html index f83fb85c..f83fb85c 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/action/pdp-add.tpl.html +++ b/moonv4/moon_gui/static/app/pdp/action/pdp-add.tpl.html diff --git a/moonv4/moon_gui/static/app/pdp/action/pdp-delete.tpl.html b/moonv4/moon_gui/static/app/pdp/action/pdp-delete.tpl.html index 167ba417..167ba417 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/action/pdp-delete.tpl.html +++ b/moonv4/moon_gui/static/app/pdp/action/pdp-delete.tpl.html diff --git a/moonv4/moon_gui/static/app/pdp/action/pdp.controller.add.js b/moonv4/moon_gui/static/app/pdp/action/pdp.controller.add.js index d1c34c79..d1c34c79 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/action/pdp.controller.add.js +++ b/moonv4/moon_gui/static/app/pdp/action/pdp.controller.add.js diff --git a/moonv4/moon_gui/static/app/pdp/action/pdp.controller.delete.js b/moonv4/moon_gui/static/app/pdp/action/pdp.controller.delete.js index 62557864..62557864 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/action/pdp.controller.delete.js +++ b/moonv4/moon_gui/static/app/pdp/action/pdp.controller.delete.js diff --git a/moonv4/moon_gui/static/app/pdp/edit/pdp-edit-basic.tpl.html b/moonv4/moon_gui/static/app/pdp/edit/pdp-edit-basic.tpl.html index 887d81ca..887d81ca 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/edit/pdp-edit-basic.tpl.html +++ b/moonv4/moon_gui/static/app/pdp/edit/pdp-edit-basic.tpl.html diff --git a/moonv4/moon_gui/static/app/pdp/edit/pdp-edit.tpl.html b/moonv4/moon_gui/static/app/pdp/edit/pdp-edit.tpl.html index 1fbd555a..1fbd555a 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/edit/pdp-edit.tpl.html +++ b/moonv4/moon_gui/static/app/pdp/edit/pdp-edit.tpl.html diff --git a/moonv4/moon_gui/static/app/pdp/edit/pdp.controller.edit.js b/moonv4/moon_gui/static/app/pdp/edit/pdp.controller.edit.js index 41b73098..41b73098 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/edit/pdp.controller.edit.js +++ b/moonv4/moon_gui/static/app/pdp/edit/pdp.controller.edit.js diff --git a/moonv4/moon_gui/static/app/pdp/edit/pdp.edit.basic.dir.js b/moonv4/moon_gui/static/app/pdp/edit/pdp.edit.basic.dir.js index 402422b6..402422b6 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/edit/pdp.edit.basic.dir.js +++ b/moonv4/moon_gui/static/app/pdp/edit/pdp.edit.basic.dir.js diff --git a/moonv4/moon_gui/static/app/pdp/pdp-list.tpl.html b/moonv4/moon_gui/static/app/pdp/pdp-list.tpl.html index 8aa4e653..8aa4e653 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/pdp-list.tpl.html +++ b/moonv4/moon_gui/static/app/pdp/pdp-list.tpl.html diff --git a/moonv4/moon_gui/static/app/pdp/pdp.controller.list.js b/moonv4/moon_gui/static/app/pdp/pdp.controller.list.js index a831cfe3..a831cfe3 100644..100755 --- a/moonv4/moon_gui/static/app/pdp/pdp.controller.list.js +++ b/moonv4/moon_gui/static/app/pdp/pdp.controller.list.js diff --git a/moonv4/moon_gui/static/app/policy/action/mapping/policy-map.tpl.html b/moonv4/moon_gui/static/app/policy/action/mapping/policy-map.tpl.html index 8b787f14..8b787f14 100644..100755 --- a/moonv4/moon_gui/static/app/policy/action/mapping/policy-map.tpl.html +++ b/moonv4/moon_gui/static/app/policy/action/mapping/policy-map.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/action/mapping/policy-unmap.tpl.html b/moonv4/moon_gui/static/app/policy/action/mapping/policy-unmap.tpl.html index a2cda52a..a2cda52a 100644..100755 --- a/moonv4/moon_gui/static/app/policy/action/mapping/policy-unmap.tpl.html +++ b/moonv4/moon_gui/static/app/policy/action/mapping/policy-unmap.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/action/mapping/policy.controller.map.js b/moonv4/moon_gui/static/app/policy/action/mapping/policy.controller.map.js index 6ad8caa7..6ad8caa7 100644..100755 --- a/moonv4/moon_gui/static/app/policy/action/mapping/policy.controller.map.js +++ b/moonv4/moon_gui/static/app/policy/action/mapping/policy.controller.map.js diff --git a/moonv4/moon_gui/static/app/policy/action/mapping/policy.controller.unmap.js b/moonv4/moon_gui/static/app/policy/action/mapping/policy.controller.unmap.js index d309ec0f..d309ec0f 100644..100755 --- a/moonv4/moon_gui/static/app/policy/action/mapping/policy.controller.unmap.js +++ b/moonv4/moon_gui/static/app/policy/action/mapping/policy.controller.unmap.js diff --git a/moonv4/moon_gui/static/app/policy/action/policy-add.tpl.html b/moonv4/moon_gui/static/app/policy/action/policy-add.tpl.html index d20c41be..d20c41be 100644..100755 --- a/moonv4/moon_gui/static/app/policy/action/policy-add.tpl.html +++ b/moonv4/moon_gui/static/app/policy/action/policy-add.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/action/policy-delete.tpl.html b/moonv4/moon_gui/static/app/policy/action/policy-delete.tpl.html index 3b5df88b..3b5df88b 100644..100755 --- a/moonv4/moon_gui/static/app/policy/action/policy-delete.tpl.html +++ b/moonv4/moon_gui/static/app/policy/action/policy-delete.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/action/policy.controller.add.js b/moonv4/moon_gui/static/app/policy/action/policy.controller.add.js index 0320c2e9..0320c2e9 100644..100755 --- a/moonv4/moon_gui/static/app/policy/action/policy.controller.add.js +++ b/moonv4/moon_gui/static/app/policy/action/policy.controller.add.js diff --git a/moonv4/moon_gui/static/app/policy/action/policy.controller.delete.js b/moonv4/moon_gui/static/app/policy/action/policy.controller.delete.js index 9a718ddc..9a718ddc 100644..100755 --- a/moonv4/moon_gui/static/app/policy/action/policy.controller.delete.js +++ b/moonv4/moon_gui/static/app/policy/action/policy.controller.delete.js diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html new file mode 100755 index 00000000..9069dcd0 --- /dev/null +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html @@ -0,0 +1,165 @@ +<div> + + <div class="col-md-12 col-sm-12 col-xs-12"> + + <form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form"> + + <!-- Select Policy --> + <div class="form-group" ng-class="{'has-error': edit.form.policyList.$invalid && edit.form.policyList.$dirty}" > + + <label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.policies">Policy List</label> + + <div class="col-sm-6" ng-if="edit.loadingPolicies" > + <moon-loader></moon-loader> + </div> + + <div class="col-sm-6" ng-if="!edit.loadingPolicies" > + + <ui-select ng-model="edit.selectedPolicy" name="policyList" id="policyList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aPolicy in edit.policyList"> + <div ng-value="aPolicy" ng-bind="aPolicy.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.policyList.$dirty && edit.form.policyList.$invalid"> + <small class="error" ng-show="edit.form.policyList.$error.required" data-translate="moon.policy.assignments.edit.check.policy.required">Policy is required</small> + </div> + + </div> + + </div> + + <!-- Select Perimeter --> + <div class="form-group" ng-class="{'has-error': edit.form.perimeterList.$invalid && edit.form.perimeterList.$dirty}" > + + <label for="perimeterList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.perimeters">Perimeter List</label> + + <div class="col-sm-6" ng-if="edit.loadingPerimeters" > + <moon-loader></moon-loader> + </div> + + <div class="col-sm-6" ng-if="!edit.loadingPerimeters" > + + <ui-select ng-model="edit.selectedPerimeter" name="perimeterList" id="perimeterList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aPerimeter in edit.perimeterList"> + <div ng-value="aPerimeter" ng-bind="aPerimeter.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.perimeterList.$dirty && edit.form.perimeterList.$invalid"> + <small class="error" ng-show="edit.form.perimeterList.$error.required" data-translate="moon.policy.assignments.edit.check.perimeter.required">Perimeter is required</small> + </div> + + </div> + + </div> + + <!-- Select Category --> + <div class="form-group" ng-class="{'has-error': edit.form.categoryList.$invalid && edit.form.categoryList.$dirty}" > + + <label for="categoryList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.categories">Category List</label> + + <div class="col-sm-6" ng-if="edit.loadingCategories" > + <moon-loader></moon-loader> + </div> + + <div class="col-sm-6" ng-if="!edit.loadingCategories" > + + <ui-select ng-model="edit.selectedCategory" name="categoryList" id="categoryList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aCategory in edit.categoryList"> + <div ng-value="aCategory" ng-bind="aCategory.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.categoryList.$dirty && edit.form.categoryList.$invalid"> + <small class="error" ng-show="edit.form.categoryList.$error.required" data-translate="moon.policy.assignments.edit.check.category.required">Category is required</small> + </div> + + </div> + + </div> + + <!-- Select Data --> + <div class="form-group" ng-if="edit.selectedCategory" ng-class="{'has-error': edit.form.dataList.$invalid && edit.form.dataList.$dirty}" > + + <label for="dataList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.data">Data List</label> + + <div class="col-sm-6" ng-if="edit.loadingData" > + <moon-loader></moon-loader> + </div> + + <div class="col-sm-4" ng-if="!edit.loadingData" > + + <ui-select ng-model="edit.selectedData" name="dataList" id="dataList"> + + <ui-select-match placeholder="(None)" ng-bind="edit.getName($select.selected)"></ui-select-match> + <ui-select-choices repeat="aData in edit.dataToBeSelected"> + <div ng-value="aData" ng-bind="edit.getName(aData)"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.dataList.$dirty && edit.form.dataList.$invalid || !edit.assignementsAttributeValid"> + <small class="error" ng-show="edit.form.dataList.$error.required || !edit.assignementsAttributeValid" data-translate="moon.policy.assignments.edit.check.data.required">Data is required</small> + </div> + + </div> + + <div class="col-sm-2 text-center"> + <a href="" ng-if="edit.selectedData" + ng-click="edit.addSelectedData()"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a> + </div> + + </div> + + <!-- Selected DataList --> + <div class="form-group" ng-if="!edit.loadingData"> + + <label class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.selectedData">Selected Data)</label> + + <div class="col-sm-6"> + + <ul> + + <li ng-repeat="(key, value) in edit.selectedDataList"> + + <span ng-bind="edit.getName(value)" ></span> <a href="" ng-click="edit.removeSelectedData(value)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a> + + </li> + + </ul> + + </div> + + </div> + + <div class="form-group"> + + <div class="pull-right"> + + <a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning"> + <span class="glyphicon glyphicon-save"></span> + <span data-translate="moon.policy.assignments.edit.action.create">Create</span> + </a> + + <moon-loader ng-if="edit.loading"></moon-loader> + + </div> + + </div> + + + </form> + + </div> + +</div>
\ No newline at end of file diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-list.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-list.tpl.html index 34bbc7a8..34bbc7a8 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-list.tpl.html +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-list.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js new file mode 100755 index 00000000..5297eccb --- /dev/null +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js @@ -0,0 +1,439 @@ +(function () { + + 'use strict'; + + angular + .module('moon') + .directive('moonAssignmentsEdit', moonAssignmentsEdit); + + moonAssignmentsEdit.$inject = []; + + function moonAssignmentsEdit() { + + return { + templateUrl: 'html/policy/edit/parameter/assignments/assignments-edit.tpl.html', + bindToController: true, + controller: moonAssignmentsEditController, + controllerAs: 'edit', + scope: { + //Type can be 'ACTION', 'OBJECT', 'SUBJECT' + assignmentsType: '=', + policy: '=' + }, + restrict: 'E', + replace: true + }; + } + + angular + .module('moon') + .controller('moonAssignmentsEditController', moonAssignmentsEditController); + + moonAssignmentsEditController.$inject = ['$scope', 'assignmentsService', 'alertService', '$translate', 'formService', + 'policyService', 'utilService', 'perimeterService', 'ASSIGNMENTS_CST', + 'metaDataService', 'dataService']; + + function moonAssignmentsEditController($scope, assignmentsService, alertService, $translate, formService, + policyService, utilService, perimeterService, ASSIGNMENTS_CST, + metaDataService, dataService ) { + + var edit = this; + + edit.assignmentsType = $scope.edit.assignmentsType; + edit.policy = $scope.edit.policy; + + edit.laoading = false; + + edit.form = {}; + + edit.policyList = []; + edit.loadingPolicies = true; + + edit.categoryList = []; + edit.loadingCategories = true; + + edit.perimeterList = []; + edit.loadingPerimeters = true; + + edit.dataList = []; + edit.dataToBeSelected = []; + edit.selectedDataList = []; + edit.loadingData = true; + + edit.assignementsAttributeValid = true; + + edit.addSelectedData = addSelectedData; + edit.removeSelectedData = removeSelectedData; + edit.getName = getName; + edit.create = createAssignments; + + activate(); + + /* + * + */ + + function activate() { + + edit.assignments = {id: null, category_id: null, data_id: null, policy_id: null}; + + loadAllPolicies(); + loadAllCategories(); + + } + + function createAssignments() { + + edit.assignementsAttributeValid = true; + + manageSelectedDataListy(); + + if(formService.isInvalid(edit.form)) { + + formService.checkFieldsValidity(edit.form); + + }else if(edit.assignementsAttributeValid){ + + startLoading(); + + var throwEvent = false; + edit.assignments.id = edit.selectedPerimeter.id; + edit.assignments.category_id = edit.selectedCategory.id; + edit.assignments.policy_id = edit.selectedPolicy.id; + + var selectedDataListTemp = angular.copy(edit.selectedDataList); + + _.each(selectedDataListTemp, function(elem){ + + edit.assignments.data_id = elem.id; + + var assignmentsToSend = angular.copy(edit.assignments); + + switch(edit.assignmentsType){ + + case ASSIGNMENTS_CST.TYPE.SUBJECT: + + assignmentsService.subject.add(assignmentsToSend, edit.policy.id, createSuccess, createError); + break; + + case ASSIGNMENTS_CST.TYPE.OBJECT: + + assignmentsService.object.add(assignmentsToSend, edit.policy.id, createSuccess, createError); + break; + + case ASSIGNMENTS_CST.TYPE.ACTION: + + assignmentsService.action.add(assignmentsToSend, edit.policy.id, createSuccess, createError); + break; + + default : + + break; + + } + + }); + + throwEvent = true; + + } + + function createSuccess(data) { + + var created = {}; + + switch(edit.assignmentsType){ + + case ASSIGNMENTS_CST.TYPE.SUBJECT: + + created = utilService.transformOne(data, 'subject_assignments'); + break; + + case ASSIGNMENTS_CST.TYPE.OBJECT: + + created = utilService.transformOne(data, 'object_assignments'); + break; + + case ASSIGNMENTS_CST.TYPE.ACTION: + + created = utilService.transformOne(data, 'action_assignments'); + break; + + default: + + break; + + } + + $translate('moon.policy.assignments.edit.create.success').then(function (translatedValue) { + alertService.alertSuccess(translatedValue); + }); + + if(throwEvent && created.policy_id === edit.policy.id){ + + $scope.$emit('event:createAssignmentsFromAssignmentsEditSuccess', edit.assignmentsType); + + activate(); + + stopLoading(); + + }else if(throwEvent){ + + activate(); + + stopLoading(); + + } + + } + + function createError(reason) { + + $translate('moon.policy.rules.edit.action.add.create.error').then(function (translatedValue) { + alertService.alertError(translatedValue); + }); + + stopLoading(); + + } + + } + + $scope.$watch('edit.selectedPolicy', function(newValue){ + + if(!_.isUndefined(newValue)){ + + loadRelatedPerimeters(); + + } + + }); + + + $scope.$watch('edit.selectedCategory', function(newValue){ + + clearSelectedCategories(); + + if(!_.isUndefined(newValue)){ + + loadRelatedData(newValue.id); + + } + + }); + + function loadAllPolicies() { + + edit.policyList = []; + edit.loadingPolicies = true; + + policyService.findAllWithCallback( function(data) { + + _.each(data, function(element){ + + if(element.id === edit.policy.id){ + edit.selectedPolicy = element; + } + + }); + + edit.policyList = data; + edit.loadingPolicies = false; + + }); + } + + function loadRelatedPerimeters(){ + + edit.perimeterList = []; + edit.loadingPerimeters = true; + + switch(edit.assignmentsType){ + + case ASSIGNMENTS_CST.TYPE.SUBJECT: + + perimeterService.subject.findAllFromPolicyWithCallback(edit.selectedPolicy.id, callBackList); + break; + + case ASSIGNMENTS_CST.TYPE.OBJECT: + + perimeterService.object.findAllFromPolicyWithCallback(edit.selectedPolicy.id,callBackList); + break; + + case ASSIGNMENTS_CST.TYPE.ACTION: + + perimeterService.action.findAllFromPolicyWithCallback(edit.selectedPolicy.id, callBackList); + break; + + default : + + edit.perimeterList = []; + edit.loadingPerimeters = false; + break; + + } + + function callBackList(list){ + + edit.perimeterList = list; + + edit.loadingPerimeters = false; + + } + } + + function loadAllCategories(){ + + edit.categoryList = []; + edit.loadingCategories = true; + + switch(edit.assignmentsType){ + + case ASSIGNMENTS_CST.TYPE.SUBJECT: + + metaDataService.subject.findAllWithCallback(callBackList); + break; + + case ASSIGNMENTS_CST.TYPE.OBJECT: + + metaDataService.object.findAllWithCallback(callBackList); + break; + + case ASSIGNMENTS_CST.TYPE.ACTION: + + metaDataService.action.findAllWithCallback(callBackList); + break; + + default : + + edit.categoryList = []; + edit.loadingCategories = false; + break; + + } + + function callBackList(list){ + + edit.categoryList = list; + edit.loadingCategories = false; + + } + } + + function loadRelatedData(categoryId){ + + edit.dataList = []; + edit.dataToBeSelected = []; + edit.selectedDataList = []; + edit.loadingData = true; + + switch(edit.assignmentsType){ + + case ASSIGNMENTS_CST.TYPE.SUBJECT: + + dataService.subject.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, categoryId, callBackList); + break; + + case ASSIGNMENTS_CST.TYPE.OBJECT: + + dataService.object.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, categoryId, callBackList); + break; + + case ASSIGNMENTS_CST.TYPE.ACTION: + + dataService.action.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, categoryId, callBackList); + break; + + default : + + edit.loadingData = false; + break; + + } + + function callBackList(list){ + + edit.dataList = list; + edit.dataToBeSelected = angular.copy(edit.dataList); + edit.selectedDataList = []; + edit.loadingData = false; + + } + + } + + function addSelectedData(){ + + edit.dataToBeSelected = _.without(edit.dataToBeSelected, edit.selectedData); + edit.selectedDataList.push(edit.selectedData); + clearSelectedCategories(); + + } + + function removeSelectedData(data){ + + edit.dataToBeSelected.push(data); + edit.selectedDataList = _.without(edit.selectedDataList, data); + + } + + function clearSelectedCategories(){ + + edit.selectedData = undefined; + + } + + function getName(assignment){ + + if(_.isUndefined(assignment)) return '(None)'; + + switch(edit.assignmentsType){ + + case ASSIGNMENTS_CST.TYPE.SUBJECT: + + return assignment.name; + + case ASSIGNMENTS_CST.TYPE.OBJECT: + + return assignment.value.name; + + + case ASSIGNMENTS_CST.TYPE.ACTION: + + return assignment.value.name; + + default : + + return assignment.name; + + } + + } + + function manageSelectedDataListy(){ + + if (edit.selectedDataList.length >= 1 ){ + + edit.assignementsAttributeValid = true; + + }else{ + + edit.assignementsAttributeValid = false; + + } + } + + function startLoading(){ + + edit.loading = true; + + } + + function stopLoading(){ + + edit.loading = false; + + } + } + +})();
\ No newline at end of file diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.list.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.list.dir.js index 22931e4d..22931e4d 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.list.dir.js +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.list.dir.js diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html new file mode 100755 index 00000000..3f11a641 --- /dev/null +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html @@ -0,0 +1,110 @@ +<div> + + <div class="col-md-12 col-sm-12 col-xs-12"> + + <form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form"> + + <div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}"> + + <label for="name" class="col-sm-3 control-label" + data-translate="moon.policy.data.edit.name">Name</label> + + <div class="col-sm-6"> + + <input name="name" id="name" class="form-control" type="text" data-ng-model="edit.data.name" + required/> + + <div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid"> + <small class="error" ng-show="edit.form.name.$error.required" + data-translate="moon.policy.data.edit.check.name.required">Name is required + </small> + </div> + + </div> + + </div> + + <div class="form-group"> + + <label for="description" class="col-sm-3 control-label" + data-translate="moon.policy.data.edit.description">Description</label> + <div class="col-sm-6"> + <textarea id="description" name="description" class="form-control" + data-ng-model="edit.data.description"></textarea> + </div> + + </div> + + <div class="form-group" + ng-class="{'has-error': edit.form.policyList.$invalid && edit.form.policyList.$dirty}"> + + <label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.data.edit.policies">Policy + List </label> + + <div class="col-sm-6"> + + <ui-select ng-model="edit.selectedPolicy" name="policyList" id="policyList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aPolicy in edit.policyList"> + <div ng-value="aPolicy" ng-bind="aPolicy.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.policyList.$dirty && edit.form.policyList.$invalid"> + <small class="error" ng-show="edit.form.policyList.$error.required" + data-translate="moon.policy.data.edit.check.policy.required">Policy is required + </small> + </div> + + </div> + + </div> + + <div class="form-group" + ng-class="{'has-error': edit.form.categoryList.$invalid && edit.form.categoryList.$dirty}"> + + <label for="categoryList" class="col-sm-3 control-label" + data-translate="moon.policy.data.edit.categories">Category List </label> + + <div class="col-sm-6"> + + <ui-select ng-model="edit.selectedCategory" name="categoryList" id="categoryList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aCategory in edit.categoriesToBeSelected"> + <div ng-value="aCategory" ng-bind="aCategory.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.categoryList.$dirty && edit.form.categoryList.$invalid"> + <small class="error" ng-show="edit.form.categoryList.$error.required" + data-translate="moon.policy.data.edit.check.category.required">Category is required + </small> + </div> + + </div> + </div> + + <div class="form-group"> + + <div class="pull-right"> + + <a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning"> + <span class="glyphicon glyphicon-save"></span> + <span data-translate="moon.policy.data.edit.action.create">Create</span> + </a> + + <moon-loader ng-if="edit.loading"></moon-loader> + + </div> + + </div> + + </form> + + </div> + +</div>
\ No newline at end of file diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/data/data-list.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/data/data-list.tpl.html index b69a4eed..b69a4eed 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/parameter/data/data-list.tpl.html +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/data/data-list.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/data/data.edit.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/data/data.edit.dir.js index 57ad0c9b..57ad0c9b 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/parameter/data/data.edit.dir.js +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/data/data.edit.dir.js diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/data/data.list.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/data/data.list.dir.js index 23a7e535..23a7e535 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/parameter/data/data.list.dir.js +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/data/data.list.dir.js diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html new file mode 100755 index 00000000..fa2f93c0 --- /dev/null +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html @@ -0,0 +1,166 @@ +<div> + + <div class="col-md-4 col-sm-4 col-xs-4"> + <a class="btn btn-primary" type="button" style="white-space: normal;" ng-click="edit.fromList = !edit.fromList"> + <span ng-if="!edit.fromList" data-translate="moon.policy.perimeter.edit.action.list">Add from the list</span> + <span ng-if="edit.fromList" data-translate="moon.policy.perimeter.edit.action.new">Add a new Perimeter</span> + </a> + </div> + + <div class="col-md-8 col-sm-8 col-xs-8"> + + <form name="selectMetaData" ng-if="edit.fromList" class="form-horizontal" role="form" > + + <div class="form-group" > + + <ui-select ng-model="edit.selectedPerimeter" name="object"> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aPerimeter in edit.list"> + <div ng-value="aPerimeter" ng-bind="aPerimeter.name"></div> + </ui-select-choices> + + </ui-select> + + </div> + + <div class="form-group"> + + <div class="pull-left col-md-4 col-sm-4 col-xs-4"> + + <a href="" ng-disabled="edit.loading || !edit.selectedPerimeter" ng-click="edit.deletePerimeter()" class="btn btn-warning"> + <span class="glyphicon glyphicon-trash"></span> + <span data-translate="moon.policy.perimeter.edit.action.delete">Delete</span> + </a> + + </div> + + <div class="pull-right col-md-7 col-md-offset-1 col-sm-7 col-sm-offset-1 col-xs-7 col-xs-offset-1 "> + + <a href="" ng-disabled="edit.loading || !edit.selectedPerimeter" ng-click="edit.addToPolicy()" class="btn btn-warning" style="white-space: normal;"> + <span class="glyphicon glyphicon-link"></span> + <span data-translate="moon.policy.perimeter.edit.action.add">Add the selected Perimeter</span> + </a> + + </div> + + </div> + + <moon-loader ng-if="edit.loading"></moon-loader> + + </form> + + <form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form"> + + <div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}"> + + <label for="name" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.name">Name</label> + + <div class="col-sm-6"> + + <input name="name" id="name" class="form-control" type="text" data-ng-model="edit.perimeter.name" required /> + + <div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid"> + <small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.policy.perimeter.edit.check.name.required">Name is required</small> + </div> + + </div> + + </div> + + <div class="form-group"> + + <label for="description" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.description">Description</label> + <div class="col-sm-6"> + <textarea id="description" name="description" class="form-control" data-ng-model="edit.perimeter.description"></textarea> + </div> + + </div> + + <!-- + <div class="form-group"> + + <label for="partnerId" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.partnerId">Partner Id</label> + + <div class="col-sm-6"> + <input name="partnerId" id="partnerId" class="form-control" type="text" data-ng-model="edit.perimeter.partnerId" /> + </div> + + </div> + --> + + + <div class="form-group" ng-if="edit.perimeterType === edit.subjectType" ng-class="{'has-error': edit.form.email.$invalid && edit.form.email.$dirty}"> + + <label for="email" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.email">Email</label> + + <div class="col-sm-6"> + <input name="email" id="email" class="form-control" type="email" data-ng-model="edit.perimeter.email" /> + </div> + + </div> + + + <div class="form-group" > + + <label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.policies">Policy List </label> + + <div class="col-sm-5"> + + <ui-select ng-model="edit.selectedPolicy" id="policyList"> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aPolicy in edit.policiesToBeSelected"> + <div ng-value="aPolicy" ng-bind="aPolicy.name"></div> + </ui-select-choices> + + </ui-select> + + </div> + + <div class="col-sm-1 text-center"> + <a href="" ng-click="edit.addPolicyToPerimeter()"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a> + </div> + + </div> + + <div class="form-group"> + + <label class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.selectedPolicies">Selected Policies</label> + + <div class="col-sm-6"> + + <ul> + + <li ng-repeat="(key, value) in edit.selectedPolicyList"> + + <span ng-bind="value.name" ></span> <a href="" ng-click="edit.removeSelectedPolicy(value)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a> + + </li> + + </ul> + + </div> + + </div> + + <div class="form-group"> + + <div class="pull-right"> + + <a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning"> + <span class="glyphicon glyphicon-save"></span> + <span data-translate="moon.policy.perimeter.edit.action.create">Create</span> + </a> + + <moon-loader ng-if="edit.loading"></moon-loader> + + </div> + + </div> + + </form> + + </div> + +</div>
\ No newline at end of file diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-list.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-list.tpl.html index a94d663e..a94d663e 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-list.tpl.html +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-list.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js new file mode 100755 index 00000000..a96741fe --- /dev/null +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js @@ -0,0 +1,437 @@ +(function () { + + 'use strict'; + + angular + .module('moon') + .directive('moonPerimeterEdit', moonPerimeterEdit); + + moonPerimeterEdit.$inject = []; + + function moonPerimeterEdit() { + + return { + templateUrl: 'html/policy/edit/parameter/perimeter/perimeter-edit.tpl.html', + bindToController: true, + controller: moonPerimeterEditController, + controllerAs: 'edit', + scope: { + //Type can be 'ACTION', 'OBJECT', 'SUBJECT' + perimeterType: '=', + policy: '=' + }, + restrict: 'E', + replace: true + }; + } + + + angular + .module('moon') + .controller('moonPerimeterEditController', moonPerimeterEditController); + + moonPerimeterEditController.$inject = ['$scope', '$rootScope', + 'perimeterService', 'PERIMETER_CST', 'alertService', + '$translate', 'formService', 'policyService', 'utilService']; + + function moonPerimeterEditController($scope, $rootScope, + perimeterService, PERIMETER_CST, alertService, + $translate, formService, policyService, utilService) { + + var edit = this; + + edit.perimeterType = $scope.edit.perimeterType; + // This variable is used in the view in order to display or not display email field + edit.subjectType = PERIMETER_CST.TYPE.SUBJECT; + edit.policy = $scope.edit.policy; + + edit.fromList = true; + + edit.loading = false; + + edit.form = {}; + + edit.perimeter = {name: null, description: null, partner_id: null, policy_list: [], email: null}; + + edit.list = []; + edit.policyList = []; + edit.policiesToBeSelected = []; + edit.selectedPolicyList = []; // List of Policies to be added to a new perimeter + + edit.create = createPerimeter; + edit.addToPolicy = addToPolicy; + edit.addPolicyToPerimeter = addPolicyToPerimeter; + edit.clearSelectedPolicies = clearSelectedPolicies; + edit.removeSelectedPolicy = removeSelectedPolicy; + edit.deletePerimeter = deletePerimeter; + + activate(); + + /* + * + */ + + function activate() { + + loadAllPolicies(); + + switch (edit.perimeterType) { + + case PERIMETER_CST.TYPE.SUBJECT: + + perimeterService.subject.findAllWithCallback(callBackList); + break; + + case PERIMETER_CST.TYPE.OBJECT: + + perimeterService.object.findAllWithCallback(callBackList); + break; + + case PERIMETER_CST.TYPE.ACTION: + + perimeterService.action.findAllWithCallback(callBackList); + break; + + default : + + edit.list = []; + break; + + } + + function callBackList(list) { + + // For each Perimeter, there is a check about the mapping between the perimeter and the policy + _.each(list, function (element) { + + if (_.indexOf(element.policy_list, edit.policy.id) === -1) { + + edit.list.push(element); + + } + + }); + + } + + } + + var rootListeners = { + + 'event:unMapPerimeterFromPerimeterList': $rootScope.$on('event:unMapPerimeterFromPerimeterList', manageUnMappedPerimeter) + + }; + + _.each(rootListeners, function(unbind){ + $scope.$on('$destroy', rootListeners[unbind]); + }); + + + function loadAllPolicies() { + + edit.policyList = []; + + policyService.findAllWithCallback( function(data) { + + edit.policyList = data; + edit.policiesToBeSelected = angular.copy(edit.policyList); + + }); + } + + function addPolicyToPerimeter() { + + if (!edit.selectedPolicy || _.contains(edit.perimeter.policy_list, edit.selectedPolicy.id)) { + return; + } + + edit.perimeter.policy_list.push(edit.selectedPolicy.id); + edit.selectedPolicyList.push(edit.selectedPolicy); + edit.policiesToBeSelected = _.without(edit.policiesToBeSelected, edit.selectedPolicy); + + } + + function clearSelectedPolicies() { + + edit.perimeter.policy_list = []; + edit.selectedPolicyList = []; + edit.policiesToBeSelected = angular.copy(edit.policyList); + + } + + function removeSelectedPolicy(policy) { + + edit.policiesToBeSelected.push(policy); + edit.perimeter.policy_list = _.without(edit.perimeter.policy_list, policy.id); + edit.selectedPolicyList = _.without(edit.selectedPolicyList, policy); + + } + + /** + * Add + */ + + function addToPolicy() { + + if (!edit.selectedPerimeter) { + + return; + + } + + startLoading(); + + var perimeterToSend = edit.selectedPerimeter; + + perimeterToSend.policy_list.push(edit.policy.id); + + switch (edit.perimeterType) { + + case PERIMETER_CST.TYPE.SUBJECT: + + perimeterService.subject.update(perimeterToSend, updatePerimeterSuccess, updatePerimeterError); + break; + + case PERIMETER_CST.TYPE.OBJECT: + + perimeterService.object.update(perimeterToSend, updatePerimeterSuccess, updatePerimeterError); + break; + + case PERIMETER_CST.TYPE.ACTION: + + perimeterService.action.update(perimeterToSend, updatePerimeterSuccess, updatePerimeterError); + break; + } + + + function updatePerimeterSuccess(data) { + + $translate('moon.perimeter.update.success', {policyName: perimeterToSend.name}).then(function (translatedValue) { + + alertService.alertSuccess(translatedValue); + + }); + + stopLoading(); + + } + + function updatePerimeterError(reason) { + + $translate('moon.policy.update.error', { + policyName: perimeterToSend.name, + reason: reason.message + }).then(function (translatedValue) { + + alertService.alertError(translatedValue); + + }); + + stopLoading(); + + } + + } + + /** + * Create + */ + + function createPerimeter() { + + if (formService.isInvalid(edit.form)) { + + formService.checkFieldsValidity(edit.form); + + } else { + + startLoading(); + + var perimeterToSend = angular.copy(edit.perimeter); + + switch (edit.perimeterType) { + + case PERIMETER_CST.TYPE.SUBJECT: + + perimeterService.subject.add(perimeterToSend, createSuccess, createError); + break; + + case PERIMETER_CST.TYPE.OBJECT: + + perimeterService.object.add(perimeterToSend, createSuccess, createError); + break; + + case PERIMETER_CST.TYPE.ACTION: + + perimeterService.action.add(perimeterToSend, createSuccess, createError); + break; + } + + } + + function createSuccess(data) { + + var created = {}; + + switch (edit.perimeterType) { + + case PERIMETER_CST.TYPE.SUBJECT: + + created = utilService.transformOne(data, 'subjects'); + break; + + case PERIMETER_CST.TYPE.OBJECT: + + created = utilService.transformOne(data, 'objects'); + break; + + case PERIMETER_CST.TYPE.ACTION: + + created = utilService.transformOne(data, 'actions'); + break; + } + + $translate('moon.policy.perimeter.edit.create.success', {name: created.name}).then(function (translatedValue) { + alertService.alertSuccess(translatedValue); + }); + + stopLoading(); + + /** + * If during the creating the created assignments has be mapped with the current policy, then it is not required to push the new Assignments in the list + */ + if (_.indexOf(created.policy_list, edit.policy.id) === -1) { + + edit.list.push(created); + + }else{ + + $scope.$emit('event:createAssignmentsFromAssignmentsEditSuccess', created, edit.perimeterType); + + } + + displayList(); + + clearSelectedPolicies(); + + } + + function createError(reason) { + + $translate('moon.policy.perimeter.edit.create.error', {name: perimeterToSend.name}).then(function (translatedValue) { + alertService.alertError(translatedValue); + }); + + stopLoading(); + + } + + } + + /** + * Delete + */ + function deletePerimeter() { + + if (!edit.selectedPerimeter) { + + return; + + } + + startLoading(); + + var perimeterToDelete = angular.copy(edit.selectedPerimeter); + + switch (edit.perimeterType) { + case PERIMETER_CST.TYPE.SUBJECT: + + perimeterService.subject.delete(perimeterToDelete, deleteSuccess, deleteError); + break; + + case PERIMETER_CST.TYPE.OBJECT: + + perimeterService.object.delete(perimeterToDelete, deleteSuccess, deleteError); + break; + + case PERIMETER_CST.TYPE.ACTION: + + perimeterService.action.delete(perimeterToDelete, deleteSuccess, deleteError); + break; + } + + + function deleteSuccess(data) { + + $translate('moon.policy.perimeter.edit.delete.success', {name: perimeterToDelete.name}) + .then(function (translatedValue) { + alertService.alertSuccess(translatedValue); + }); + + policyService.findOneReturningPromise(edit.policy.id).then(function (data) { + + edit.policy = utilService.transformOne(data, 'policies'); + + cleanSelectedValue(); + activate(); + stopLoading(); + + $scope.$emit('event:deletePerimeterFromPerimeterAddSuccess', edit.policy); + + }); + + } + + function deleteError(reason) { + + $translate('moon.policy.perimeter.edit.delete.error', {name: perimeterToDelete.name}).then(function (translatedValue) { + alertService.alertError(translatedValue); + }); + + stopLoading(); + + } + } + + function cleanSelectedValue() { + + delete edit.selectedPerimeter; + + } + + function startLoading() { + + edit.loading = true; + + } + + function stopLoading() { + + edit.loading = false; + + } + + function displayList() { + + edit.fromList = true; + + } + + /** + * If A perimeter has been unMapped, maybe it has to be display into the available list of Perimeter + * @param perimeter + * @param type + */ + function manageUnMappedPerimeter(event, perimeter, type){ + + if(type === edit.perimeterType && _.indexOf(perimeter.policy_list, edit.policy.id) === -1){ + + edit.list.push(perimeter); + + } + + } + + } + +})();
\ No newline at end of file diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.list.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.list.dir.js index dffa7783..dffa7783 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.list.dir.js +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.list.dir.js diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html new file mode 100755 index 00000000..685046a5 --- /dev/null +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html @@ -0,0 +1,341 @@ +<div> + + <div class="col-md-12 col-sm-12 col-xs-12"> + + <form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form"> + + <!-- Select Policy --> + <div class="form-group" ng-class="{'has-error': edit.form.policyList.$invalid && edit.form.policyList.$dirty}" > + + <label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.policies">Policy List</label> + + <div class="col-sm-6" > + + <ui-select ng-model="edit.selectedPolicy" name="policyList" id="policyList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aPolicy in edit.policyList"> + <div ng-value="aPolicy" ng-bind="aPolicy.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.policyList.$dirty && edit.form.policyList.$invalid"> + <small class="error" ng-show="edit.form.policyList.$error.required" data-translate="moon.policy.rules.edit.action.add.check.policy.required">Policy is required</small> + </div> + + </div> + + </div> + + <div ng-if="!edit.selectedPolicy.meta_rules_values"> + <div class="col-sm-6 col-sm-offset-3"> + <moon-loader></moon-loader> + </div> + </div> + + <div ng-if="edit.selectedPolicy.meta_rules_values"> + + <!-- Select Meta Rules --> + <div class="form-group" ng-class="{'has-error': edit.form.metaRulesList.$invalid && edit.form.metaRulesList.$dirty}" > + + <label for="metaRulesList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.metarules">MetaRules List</label> + + <div class="col-sm-6" > + + <ui-select ng-model="edit.selectedMetaRules" name="metaRulesList" id="metaRulesList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aMetaRules in edit.selectedPolicy.meta_rules_values"> + <div ng-value="aMetaRules" ng-bind="aMetaRules.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.metaRulesList.$dirty && edit.form.metaRulesList.$invalid"> + <small class="error" ng-show="edit.form.metaRulesList.$error.required" data-translate="moon.policy.rules.edit.action.add.check.metarules.required">A MetaRules is required</small> + </div> + + </div> + + <div> + <a href="" ng-if="edit.selectedMetaRules" ng-click="edit.showDetailselectedMetaRules = !edit.showDetailselectedMetaRules"> + + <span ng-if="!edit.showDetailselectedMetaRules"> + <span data-translate="moon.policy.rules.edit.action.add.details.show">Show</span> + <span class="glyphicon glyphicon-eye-open"></span> + </span> + + <span ng-if="edit.showDetailselectedMetaRules"> + <span data-translate="moon.policy.rules.edit.action.add.details.close">Close</span> + <span class="glyphicon glyphicon-eye-close"></span> + </span> + + </a> + </div> + + </div> + + <div class="form-group" ng-if="edit.showDetailselectedMetaRules && edit.selectedMetaRules"> + <moon-meta-data-list edit-mode="edit.editMode" meta-rule="edit.selectedMetaRules" short-display="true"></moon-meta-data-list> + </div> + + <!-- Select Data --> + <div class="form-group" ng-if="edit.selectedMetaRules"> + + <div class="col-md-4"> + + <div ng-if="edit.selectedMetaRules.subject_categories.length > 0"> + + <div class="row"> + + <div ng-if="!edit.data.loadingSubjects"> + + <label for="subjectsList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.categories.subject" data-translate-values="{ number: edit.selectedMetaRules.subject_categories.length }">Select Subject(s)</label> + + <div class="col-sm-7" > + + <ui-select ng-model="edit.selectedSubject" name="subjectsList" id="subjectsList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match> + <ui-select-choices repeat="aSubject in edit.data.subjectsToBeSelected"> + <div ng-value="aSubject" ng-bind="aSubject.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.subjectsList.$dirty && edit.form.subjectsList.$invalid || !edit.numberOfSelectedSubjectValid"> + <small class="error" ng-show="edit.form.subjectsList.$error.required || !edit.numberOfSelectedSubjectValid" data-translate="moon.policy.rules.edit.action.add.check.subject.required" data-translate-values="{ number: edit.selectedMetaRules.subject_categories.length }">Some subject are required</small> + </div> + + </div> + + <div class="col-sm-2 text-center"> + <a href="" ng-if="edit.selectedSubject && !edit.isNumberSelectedDataAtMaximum(edit.data.subjectCST)" + ng-click="edit.addDataToRules(edit.data.subjectCST)"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a> + </div> + + </div> + + <div ng-if="edit.data.loadingSubjects"> + + <moon-loader></moon-loader> + + </div> + + </div> + + <div class="row" ng-if="!edit.data.loadingSubjects"> + + <div class="form-group"> + + <label class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.selectedSubjects">Selected Subjcet(s)</label> + + <div class="col-sm-6"> + + <ul> + + <li ng-repeat="(key, value) in edit.data.selectedSubjectsList"> + + <span ng-bind="value.name" ></span> <a href="" ng-click="edit.removeSelectedDataFromRules(value, edit.data.subjectCST)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a> + + </li> + + </ul> + + </div> + + </div> + + </div> + + </div> + + <div ng-if="edit.selectedMetaRules.subject_categories.length === 0"> + + </div> + + </div> + + <div class="col-md-4"> + + <div ng-if="edit.selectedMetaRules.object_categories.length > 0"> + + <div class="row"> + + <div ng-if="!edit.data.loadingObjects"> + + <label for="objectsList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.categories.object" data-translate-values="{ number: edit.selectedMetaRules.object_categories.length }">Select Object(s)</label> + + <div class="col-sm-7" > + + <ui-select ng-model="edit.selectedObject" name="objectsList" id="objectsList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.value.name"></ui-select-match> + <ui-select-choices repeat="aObject in edit.data.objectsToBeSelected"> + <div ng-value="aObject" ng-bind="aObject.value.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.objectsList.$dirty && edit.form.objectsList.$invalid || !edit.numberOfSelectedObjecttValid"> + <small class="error" ng-show="edit.form.objectsList.$error.required || !edit.numberOfSelectedObjecttValid" data-translate="moon.policy.rules.edit.action.add.check.object.required" data-translate-values="{ number: edit.selectedMetaRules.object_categories.length }">Some objects are required</small> + </div> + + </div> + + <div class="col-sm-2 text-center"> + <a href="" ng-if="edit.selectedObject && !edit.isNumberSelectedDataAtMaximum(edit.data.objectCST)" + ng-click="edit.addDataToRules(edit.data.objectCST)"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a> + </div> + + </div> + + <div ng-if="edit.data.loadingObjects"> + + <moon-loader></moon-loader> + + </div> + + </div> + + <div class="row" ng-if="!edit.data.loadingObjects"> + + <div class="form-group"> + + <label class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.selectedObjects">Selected Objcet(s)</label> + + <div class="col-sm-6"> + + <ul> + + <li ng-repeat="(key, value) in edit.data.selectedObjectsList"> + + <span ng-bind="value.value.name" ></span> <a href="" ng-click="edit.removeSelectedDataFromRules(value, edit.data.objectCST)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a> + + </li> + + </ul> + + </div> + </div> + + </div> + + </div> + + <div ng-if="edit.selectedMetaRules.object_categories.length === 0"> + + </div> + + </div> + + <div class="col-md-4"> + + <div ng-if="edit.selectedMetaRules.action_categories.length > 0"> + + <div class="row"> + + <div ng-if="!edit.data.loadingActions"> + + <label for="actionsList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.categories.action" data-translate-values="{ number: edit.selectedMetaRules.action_categories.length }">Select Action(s)</label> + + <div class="col-sm-7" > + + <ui-select ng-model="edit.selectedAction" name="actionsList" id="actionsList" required> + + <ui-select-match placeholder="(None)" ng-bind="$select.selected.value.name"></ui-select-match> + <ui-select-choices repeat="aAction in edit.data.actionsToBeSelected"> + <div ng-value="aAction" ng-bind="aAction.value.name"></div> + </ui-select-choices> + + </ui-select> + + <div class="help-block" ng-show="edit.form.actionsList.$dirty && edit.form.actionsList.$invalid || !edit.numberOfSelectedActionsValid"> + <small class="error" ng-show="edit.form.actionsList.$error.required || !edit.numberOfSelectedActionsValid" data-translate="moon.policy.rules.edit.action.add.check.action.required" data-translate-values="{ number: edit.selectedMetaRules.action_categories.length }">Some action are required</small> + </div> + </div> + + <div class="col-sm-2 text-center"> + <a href="" ng-if="edit.selectedAction && !edit.isNumberSelectedDataAtMaximum(edit.data.actionCST)" + ng-click="edit.addDataToRules(edit.data.actionCST)"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a> + </div> + + </div> + + <div ng-if="edit.data.loadingActions"> + + <moon-loader></moon-loader> + + </div> + + </div> + + <div class="row" ng-if="!edit.data.loadingActions"> + + <div class="form-group"> + + <label class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.selectedActions">Selected Action(s)</label> + + <div class="col-sm-6"> + + <ul> + + <li ng-repeat="(key, value) in edit.data.selectedActionsList"> + + <span ng-bind="value.value.name" ></span> <a href="" ng-click="edit.removeSelectedDataFromRules(value, edit.data.actionCST)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a> + + </li> + + </ul> + + </div> + </div> + + </div> + + </div> + + <div ng-if="edit.selectedMetaRules.action_categories.length === 0"> + + </div> + + </div> + + </div> + + <div class="form-group" ng-class="{'has-error': edit.form.instructions.$invalid && edit.form.instructions.$dirty || !edit.instructionsValid}"> + + <label for="instructions" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.instructions">Instruction</label> + + <div class="col-sm-6"> + <textarea id="instructions" name="instructions" class="form-control" ng-model="edit.rules.instructions" rows="6" required></textarea> + <div class="help-block" ng-show="edit.form.instructions.$dirty && edit.form.instructions.$invalid || !edit.instructionsValid "> + <small class="error" data-translate="moon.policy.rules.edit.action.add.check.instructions.required">An instructions is required</small> + </div> + </div> + + </div> + + <div class="form-group"> + + <div class="pull-right"> + + <a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning"> + <span class="glyphicon glyphicon-save"></span> + <span data-translate="moon.policy.rules.edit.action.create">Create</span> + </a> + + <moon-loader ng-if="edit.loading"></moon-loader> + + </div> + + </div> + + </div> + + </form> + + </div> + +</div>
\ No newline at end of file diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-list.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-list.tpl.html index 76ac4365..76ac4365 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-list.tpl.html +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-list.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js new file mode 100755 index 00000000..b7bb7614 --- /dev/null +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js @@ -0,0 +1,537 @@ +(function() { + + 'use strict'; + + angular + .module('moon') + .directive('moonRulesEdit', moonRulesEdit); + + moonRulesEdit.$inject = []; + + function moonRulesEdit() { + + return { + templateUrl : 'html/policy/edit/parameter/rules/rules-edit.tpl.html', + bindToController : true, + controller : moonRulesEditController, + controllerAs : 'edit', + scope : { + policy : '=' + }, + restrict : 'E', + replace : true + }; + + } + + angular + .module('moon') + .controller('moonRulesEditController', moonRulesEditController); + + moonRulesEditController.$inject = ['$scope', 'rulesService', 'alertService', '$translate', + 'formService', 'policyService', 'utilService', 'metaRuleService', 'metaDataService', 'modelService', 'dataService', 'DATA_CST']; + + function moonRulesEditController($scope, rulesService, alertService, $translate, + formService, policyService, utilService, metaRuleService, metaDataService, modelService, dataService, DATA_CST) { + + var edit = this; + + edit.policy = $scope.edit.policy; + edit.editMode = true; + + edit.fromList = false; + + edit.loading = false; + + edit.form = {}; + edit.showDetailselectedMetaRules = false; + + edit.list = []; + edit.policyList = []; + + edit.categories = { + subject : [], + loadingSubjects: true, + object : [], + loadingObjects: true, + action : [], + loadingActions : true + }; + + edit.data = {}; // this object is filled in declareDataObject(): + + edit.create = createRules; + edit.addDataToRules = addDataToRules; + edit.removeSelectedDataFromRules = removeSelectedDataFromRules; + edit.isNumberSelectedDataAtMaximum = isNumberSelectedDataAtMaximum; + + //this variable is related to checks on Instruction field which is in JSON + edit.instructionsValid = true; + edit.numberOfSelectedSubjectValid = true; + edit.numberOfSelectedObjecttValid = true; + edit.numberOfSelectedActionsValid = true; + + activate(); + + /* + * + */ + function activate(){ + + edit.rules = {meta_rule_id: null, rule: [], policy_id: null, instructions: '[{"decision": "grant"}]', enabled: true}; + declareDataObject(); + loadAllPolicies(); + clearSelectedMetaRules(); + + } + + function loadAllPolicies() { + + edit.policyList = []; + + policyService.findAllWithCallback( function(data) { + + _.each(data, function(element){ + + if(element.id === edit.policy.id){ + edit.selectedPolicy = element; + } + + }); + + edit.policyList = data; + + }); + } + + $scope.$watch('edit.selectedPolicy', function(newValue){ + + clearSelectedMetaRules(); + + if(!_.isUndefined(newValue)){ + + loadRelatedMetaRules(); + + } + + }); + + $scope.$watch('edit.selectedMetaRules', function(newValue){ + + clearSelectedData(); + + edit.categories = { + subject : [], + loadingSubjects: true, + object : [], + loadingObjects: true, + action : [], + loadingActions : true + }; + + declareDataObject(); + + if(!_.isUndefined(newValue)){ + + loadRelatedCategoriesAndData(newValue.subject_categories, newValue.object_categories, newValue.action_categories); + + } + + }); + + /** + * To get the related MetaRules, it is required to : + * - Get the model related to the policy + * - Get the metaRules associated to the model + * - Get the MetaData associated to the metaRules + */ + function loadRelatedMetaRules() { + + edit.selectedPolicy.meta_rules_values = undefined; + + modelService.findOneWithCallback(edit.selectedPolicy.model_id, function(model){ + + metaRuleService.findSomeWithCallback(model.meta_rules, function(metaRules){ + + edit.selectedPolicy.meta_rules_values = metaRules; + + }); + + }); + + } + + /** + * Load categories from arrays of id in args + * @param subjectsCategories, list of subject id related to the metaRule + * @param objectCategories, list of object id related to the metaRule + * @param actionsCategories, list of action id related to the metaRule + */ + function loadRelatedCategoriesAndData(subjectsCategories, objectCategories, actionsCategories){ + + metaDataService.subject.findSomeWithCallback(subjectsCategories, function(list){ + + edit.categories.subject = list; + edit.categories.loadingSubjects = false; + + _.each(edit.categories.subject, function(aSubject){ + + dataService.subject.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, aSubject.id, function(subjects){ + + edit.data.subject = subjects; + edit.data.loadingSubjects = false; + edit.data.subjectsToBeSelected = angular.copy(edit.data.subject); + + }); + + }); + + }); + + metaDataService.object.findSomeWithCallback(objectCategories, function(list){ + + edit.categories.object = list; + edit.categories.loadingObjects = false; + + _.each(edit.categories.object, function(aObject){ + + dataService.object.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, aObject.id, function(objects){ + + edit.data.object = objects; + edit.data.loadingObjects = false; + edit.data.objectsToBeSelected = angular.copy(edit.data.object); + + }); + + }); + + }); + + metaDataService.action.findSomeWithCallback(actionsCategories, function(list){ + + edit.categories.action = list; + edit.categories.loadingActions = false; + + _.each(edit.categories.action, function(aAction){ + + dataService.action.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, aAction.id, function(actions){ + + edit.data.action = actions; + edit.data.loadingActions = false; + edit.data.actionsToBeSelected = angular.copy(edit.data.action); + + }); + + }); + + }); + + } + + /** + * createRules, create Rules depending of what has been filled in the view + */ + function createRules() { + + edit.instructionsValid = true; + edit.numberOfSelectedSubjectValid = true; + edit.numberOfSelectedObjecttValid = true; + edit.numberOfSelectedActionsValid = true; + + manageInstructionContent(); + // bellow function is called here in order to display errors into the view + manageNumberOfSelectedData(); + + if(formService.isInvalid(edit.form)) { + + formService.checkFieldsValidity(edit.form); + + //manageNumberOfSelectedData is call again in order to check if errors have been display into the view + }else if(edit.instructionsValid && manageNumberOfSelectedData()){ + + startLoading(); + buildRulesArray(); + + edit.rules.meta_rule_id = edit.selectedMetaRules.id; + edit.rules.policy_id = edit.selectedPolicy.id; + + var rulesToSend = angular.copy(edit.rules); + rulesToSend.instructions = JSON.parse(edit.rules.instructions); + + rulesService.add(rulesToSend, edit.policy.id, createSuccess, createError); + } + + + function createSuccess(data) { + + var created = utilService.transformOne(data, 'rules'); + + $translate('moon.policy.rules.edit.action.add.create.success').then(function (translatedValue) { + alertService.alertSuccess(translatedValue); + }); + + $scope.$emit('event:createRulesFromDataRulesSuccess', created); + + activate(); + + stopLoading(); + + } + + function createError(reason) { + + $translate('moon.policy.rules.edit.action.add.create.error').then(function (translatedValue) { + alertService.alertError(translatedValue); + }); + + stopLoading(); + + } + + } + + /** + * if instructions attribute is not good then edit.instructionsValid is set to false + * it will allow the view to display an error + */ + function manageInstructionContent(){ + + if (!isInstructionValid(edit.rules.instructions)){ + + edit.instructionsValid = false; + + }else{ + + edit.instructionsValid = true; + + } + } + + /** + * return true if the user has selected the number required of Selected Data (subject, object or action) + * if one is missing then return false + * it will also set numberOfSelected(Subject/Object/Action)Valid to true or false in order to display errors form in the view + * @returns {boolean} + */ + function manageNumberOfSelectedData(){ + + isNumberSelectedDataAtMaximum(DATA_CST.TYPE.SUBJECT) ? + edit.numberOfSelectedSubjectValid = true: edit.numberOfSelectedSubjectValid = false; + isNumberSelectedDataAtMaximum(DATA_CST.TYPE.OBJECT) ? + edit.numberOfSelectedObjecttValid = true: edit.numberOfSelectedObjecttValid = false; + isNumberSelectedDataAtMaximum(DATA_CST.TYPE.ACTION) ? + edit.numberOfSelectedActionsValid = true: edit.numberOfSelectedActionsValid = false; + + return edit.numberOfSelectedSubjectValid && edit.numberOfSelectedObjecttValid && edit.numberOfSelectedActionsValid; + } + + /** + * Check if the variables in param is not undefined and if it is a JSON + * It is used for instructions attribute of a Rules object + * @param str + * @returns {boolean|*} + */ + function isInstructionValid(str){ + + return !_.isUndefined(str) && isJsonString(str); + + } + + function isJsonString(str) { + + var item = null; + + try { + item = JSON.parse(str); + } catch (e) { + + return false; + } + + if (typeof item === 'object' && item !== null) { + + return true; + } + + return false; + } + + function startLoading(){ + + edit.loading = true; + + } + + function stopLoading(){ + + edit.loading = false; + + } + + /** + * allow to clear selected values in the form + */ + function clearSelectedMetaRules(){ + + edit.selectedMetaRules = undefined; + + clearSelectedData(); + + } + + function clearSelectedData(){ + + edit.selectedSubject = undefined; + edit.selectedObject = undefined; + edit.selectedAction = undefined; + + } + + /** + * check if the number of Selected Data is equal to the number of categories associated to the metaRule + * @param typeCST : 'SUBJECT', 'OBJECT', 'ACTION' + * @returns {boolean} + */ + function isNumberSelectedDataAtMaximum(typeCST){ + + if(!edit.selectedMetaRules){ + return false; + } + + switch (typeCST) { + + case DATA_CST.TYPE.SUBJECT: + + return edit.data.selectedSubjectsList.length === edit.selectedMetaRules.subject_categories.length; + + case DATA_CST.TYPE.OBJECT: + + return edit.data.selectedObjectsList.length === edit.selectedMetaRules.object_categories.length; + + case DATA_CST.TYPE.ACTION: + + return edit.data.selectedActionsList.length === edit.selectedMetaRules.action_categories.length; + } + } + + /** + * Add a data to an array of selected value (SUBJECT/OBJECT/ACTION) + * those arrays will used in the create function in order to filled the rule attribute of a rules object + * it will remove the selected value from the possible value to be selected once the data is added + * @param typeCST + */ + function addDataToRules(typeCST){ + + switch (typeCST) { + case DATA_CST.TYPE.SUBJECT: + + if (!edit.selectedSubject || isNumberSelectedDataAtMaximum(typeCST) + || _.contains(edit.data.selectedSubjectsList, edit.selectedSubject)) { + return; + } + + edit.data.selectedSubjectsList.push(edit.selectedSubject); + edit.data.subjectsToBeSelected = _.without(edit.data.subjectsToBeSelected, edit.selectedSubject); + + break; + case DATA_CST.TYPE.OBJECT: + + if (!edit.selectedObject || isNumberSelectedDataAtMaximum(typeCST) + || _.contains(edit.data.selectedObjectsList, edit.selectedObject)) { + return; + } + + edit.data.selectedObjectsList.push(edit.selectedObject); + edit.data.objectsToBeSelected = _.without(edit.data.objectsToBeSelected, edit.selectedObject); + + break; + + case DATA_CST.TYPE.ACTION: + if (!edit.selectedAction || isNumberSelectedDataAtMaximum(typeCST) + || _.contains(edit.data.selectedActionsList, edit.selectedAction)) { + return; + } + + edit.data.selectedActionsList.push(edit.selectedAction); + edit.data.actionsToBeSelected = _.without(edit.data.actionsToBeSelected, edit.selectedAction); + + break; + } + + } + + /** + * Remove a selected value, + * refresh the list of possible value to be selected with the removed selected value + * @param data + * @param typeCST + */ + function removeSelectedDataFromRules(data, typeCST) { + + switch (typeCST) { + + case DATA_CST.TYPE.SUBJECT: + + edit.data.subjectsToBeSelected.push(data); + edit.data.selectedSubjectsList = _.without(edit.data.selectedSubjectsList, data); + break; + + case DATA_CST.TYPE.OBJECT: + + edit.data.objectsToBeSelected.push(data); + edit.data.selectedObjectsList = _.without(edit.data.selectedObjectsList, data); + break; + + case DATA_CST.TYPE.ACTION: + + edit.data.actionsToBeSelected.push(data); + edit.data.selectedActionsList = _.without(edit.data.selectedActionsList, data); + break; + } + + } + + /** + * fill edit.rules.rule array with the selected data + * it will first add subject list, object list and then action list + */ + function buildRulesArray(){ + + _.each(edit.data.selectedSubjectsList, pushInRulesTab); + _.each(edit.data.selectedObjectsList, pushInRulesTab); + _.each(edit.data.selectedActionsList, pushInRulesTab); + + function pushInRulesTab(elem){ + edit.rules.rule.push(elem.id); + } + } + + /** + * Declare the data object which contains attributes related to data, + * values to be selected, values selected, loader... + */ + function declareDataObject(){ + + edit.data = { + subject : [], // List of subjects related to the policy + loadingSubjects: true, // allow to know if a call to the API is in progress + subjectsToBeSelected : [], // List of subjects the user can select + selectedSubjectsList: [], // List of subjects selected by the user from subjectsToBeSelected + subjectCST : DATA_CST.TYPE.SUBJECT, + object : [], + loadingObjects: true, + objectsToBeSelected: [], + selectedObjectsList: [], + objectCST : DATA_CST.TYPE.OBJECT, + action : [], + loadingActions : true, + actionsToBeSelected : [], + selectedActionsList: [], + actionCST : DATA_CST.TYPE.ACTION + } + + } + + } + +})();
\ No newline at end of file diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.list.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.list.dir.js index 5c3e7457..5c3e7457 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.list.dir.js +++ b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.list.dir.js diff --git a/moonv4/moon_gui/static/app/policy/edit/policy-edit-basic.tpl.html b/moonv4/moon_gui/static/app/policy/edit/policy-edit-basic.tpl.html index f55c1d05..f55c1d05 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/policy-edit-basic.tpl.html +++ b/moonv4/moon_gui/static/app/policy/edit/policy-edit-basic.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/edit/policy-edit.tpl.html b/moonv4/moon_gui/static/app/policy/edit/policy-edit.tpl.html index a1a6a54a..a1a6a54a 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/policy-edit.tpl.html +++ b/moonv4/moon_gui/static/app/policy/edit/policy-edit.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/edit/policy.controller.edit.js b/moonv4/moon_gui/static/app/policy/edit/policy.controller.edit.js index 123ee58b..123ee58b 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/policy.controller.edit.js +++ b/moonv4/moon_gui/static/app/policy/edit/policy.controller.edit.js diff --git a/moonv4/moon_gui/static/app/policy/edit/policy.edit.basic.dir.js b/moonv4/moon_gui/static/app/policy/edit/policy.edit.basic.dir.js index c32d9e69..c32d9e69 100644..100755 --- a/moonv4/moon_gui/static/app/policy/edit/policy.edit.basic.dir.js +++ b/moonv4/moon_gui/static/app/policy/edit/policy.edit.basic.dir.js diff --git a/moonv4/moon_gui/static/app/policy/policy-list.tpl.html b/moonv4/moon_gui/static/app/policy/policy-list.tpl.html index aeb90f0b..aeb90f0b 100644..100755 --- a/moonv4/moon_gui/static/app/policy/policy-list.tpl.html +++ b/moonv4/moon_gui/static/app/policy/policy-list.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/policy-mapped-list.tpl.html b/moonv4/moon_gui/static/app/policy/policy-mapped-list.tpl.html index 127dae3b..127dae3b 100644..100755 --- a/moonv4/moon_gui/static/app/policy/policy-mapped-list.tpl.html +++ b/moonv4/moon_gui/static/app/policy/policy-mapped-list.tpl.html diff --git a/moonv4/moon_gui/static/app/policy/policy.controller.list.js b/moonv4/moon_gui/static/app/policy/policy.controller.list.js index fc2c6503..fc2c6503 100644..100755 --- a/moonv4/moon_gui/static/app/policy/policy.controller.list.js +++ b/moonv4/moon_gui/static/app/policy/policy.controller.list.js diff --git a/moonv4/moon_gui/static/app/policy/policy.mapped.list.dir.js b/moonv4/moon_gui/static/app/policy/policy.mapped.list.dir.js index 78bb3b8d..78bb3b8d 100644..100755 --- a/moonv4/moon_gui/static/app/policy/policy.mapped.list.dir.js +++ b/moonv4/moon_gui/static/app/policy/policy.mapped.list.dir.js diff --git a/moonv4/moon_gui/static/app/project/action/mapping/project-map.tpl.html b/moonv4/moon_gui/static/app/project/action/mapping/project-map.tpl.html index 5ffd98e2..5ffd98e2 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/mapping/project-map.tpl.html +++ b/moonv4/moon_gui/static/app/project/action/mapping/project-map.tpl.html diff --git a/moonv4/moon_gui/static/app/project/action/mapping/project-unmap.tpl.html b/moonv4/moon_gui/static/app/project/action/mapping/project-unmap.tpl.html index 5cc5c6dd..5cc5c6dd 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/mapping/project-unmap.tpl.html +++ b/moonv4/moon_gui/static/app/project/action/mapping/project-unmap.tpl.html diff --git a/moonv4/moon_gui/static/app/project/action/mapping/project.controller.map.js b/moonv4/moon_gui/static/app/project/action/mapping/project.controller.map.js index afa2bfc0..afa2bfc0 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/mapping/project.controller.map.js +++ b/moonv4/moon_gui/static/app/project/action/mapping/project.controller.map.js diff --git a/moonv4/moon_gui/static/app/project/action/mapping/project.controller.unmap.js b/moonv4/moon_gui/static/app/project/action/mapping/project.controller.unmap.js index 911b30ff..911b30ff 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/mapping/project.controller.unmap.js +++ b/moonv4/moon_gui/static/app/project/action/mapping/project.controller.unmap.js diff --git a/moonv4/moon_gui/static/app/project/action/project-add.tpl.html b/moonv4/moon_gui/static/app/project/action/project-add.tpl.html index a90dcfa1..a90dcfa1 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/project-add.tpl.html +++ b/moonv4/moon_gui/static/app/project/action/project-add.tpl.html diff --git a/moonv4/moon_gui/static/app/project/action/project-delete.tpl.html b/moonv4/moon_gui/static/app/project/action/project-delete.tpl.html index 96b4f2e3..96b4f2e3 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/project-delete.tpl.html +++ b/moonv4/moon_gui/static/app/project/action/project-delete.tpl.html diff --git a/moonv4/moon_gui/static/app/project/action/project-view.tpl.html b/moonv4/moon_gui/static/app/project/action/project-view.tpl.html index 3228c915..3228c915 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/project-view.tpl.html +++ b/moonv4/moon_gui/static/app/project/action/project-view.tpl.html diff --git a/moonv4/moon_gui/static/app/project/action/project.controller.add.js b/moonv4/moon_gui/static/app/project/action/project.controller.add.js index 4d12b75d..4d12b75d 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/project.controller.add.js +++ b/moonv4/moon_gui/static/app/project/action/project.controller.add.js diff --git a/moonv4/moon_gui/static/app/project/action/project.controller.delete.js b/moonv4/moon_gui/static/app/project/action/project.controller.delete.js index 4f18f8e6..4f18f8e6 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/project.controller.delete.js +++ b/moonv4/moon_gui/static/app/project/action/project.controller.delete.js diff --git a/moonv4/moon_gui/static/app/project/action/project.controller.view.js b/moonv4/moon_gui/static/app/project/action/project.controller.view.js index fe98a507..fe98a507 100644..100755 --- a/moonv4/moon_gui/static/app/project/action/project.controller.view.js +++ b/moonv4/moon_gui/static/app/project/action/project.controller.view.js diff --git a/moonv4/moon_gui/static/app/project/project-list.tpl.html b/moonv4/moon_gui/static/app/project/project-list.tpl.html index 82a3745e..82a3745e 100644..100755 --- a/moonv4/moon_gui/static/app/project/project-list.tpl.html +++ b/moonv4/moon_gui/static/app/project/project-list.tpl.html diff --git a/moonv4/moon_gui/static/app/project/project.controller.list.js b/moonv4/moon_gui/static/app/project/project.controller.list.js index b1cb2056..b1cb2056 100644..100755 --- a/moonv4/moon_gui/static/app/project/project.controller.list.js +++ b/moonv4/moon_gui/static/app/project/project.controller.list.js diff --git a/moonv4/moon_gui/static/app/services/gui/alert.service.js b/moonv4/moon_gui/static/app/services/gui/alert.service.js index 8435eab1..8435eab1 100644..100755 --- a/moonv4/moon_gui/static/app/services/gui/alert.service.js +++ b/moonv4/moon_gui/static/app/services/gui/alert.service.js diff --git a/moonv4/moon_gui/static/app/services/gui/browser.service.js b/moonv4/moon_gui/static/app/services/gui/browser.service.js index 88c693a8..88c693a8 100644..100755 --- a/moonv4/moon_gui/static/app/services/gui/browser.service.js +++ b/moonv4/moon_gui/static/app/services/gui/browser.service.js diff --git a/moonv4/moon_gui/static/app/services/gui/form.service.js b/moonv4/moon_gui/static/app/services/gui/form.service.js index e436593c..e436593c 100644..100755 --- a/moonv4/moon_gui/static/app/services/gui/form.service.js +++ b/moonv4/moon_gui/static/app/services/gui/form.service.js diff --git a/moonv4/moon_gui/static/app/services/gui/menu.service.js b/moonv4/moon_gui/static/app/services/gui/menu.service.js index fd90a2fa..fd90a2fa 100644..100755 --- a/moonv4/moon_gui/static/app/services/gui/menu.service.js +++ b/moonv4/moon_gui/static/app/services/gui/menu.service.js diff --git a/moonv4/moon_gui/static/app/services/gui/security.pipeline.service.js b/moonv4/moon_gui/static/app/services/gui/security.pipeline.service.js index 3831e487..3831e487 100644..100755 --- a/moonv4/moon_gui/static/app/services/gui/security.pipeline.service.js +++ b/moonv4/moon_gui/static/app/services/gui/security.pipeline.service.js diff --git a/moonv4/moon_gui/static/app/services/gui/util.service.js b/moonv4/moon_gui/static/app/services/gui/util.service.js index 7274244a..7274244a 100644..100755 --- a/moonv4/moon_gui/static/app/services/gui/util.service.js +++ b/moonv4/moon_gui/static/app/services/gui/util.service.js diff --git a/moonv4/moon_gui/static/app/services/gui/version.service.js b/moonv4/moon_gui/static/app/services/gui/version.service.js index 5f9f2786..5f9f2786 100644..100755 --- a/moonv4/moon_gui/static/app/services/gui/version.service.js +++ b/moonv4/moon_gui/static/app/services/gui/version.service.js diff --git a/moonv4/moon_gui/static/app/services/moon/model/model.service.js b/moonv4/moon_gui/static/app/services/moon/model/model.service.js index a676fc1a..a676fc1a 100644..100755 --- a/moonv4/moon_gui/static/app/services/moon/model/model.service.js +++ b/moonv4/moon_gui/static/app/services/moon/model/model.service.js diff --git a/moonv4/moon_gui/static/app/services/moon/pdp.service.js b/moonv4/moon_gui/static/app/services/moon/pdp.service.js index 822f7414..822f7414 100644..100755 --- a/moonv4/moon_gui/static/app/services/moon/pdp.service.js +++ b/moonv4/moon_gui/static/app/services/moon/pdp.service.js diff --git a/moonv4/moon_gui/static/app/services/moon/policy/parameters/assignements.service.js b/moonv4/moon_gui/static/app/services/moon/policy/parameters/assignements.service.js index ca138b45..ca138b45 100644..100755 --- a/moonv4/moon_gui/static/app/services/moon/policy/parameters/assignements.service.js +++ b/moonv4/moon_gui/static/app/services/moon/policy/parameters/assignements.service.js diff --git a/moonv4/moon_gui/static/app/services/moon/policy/parameters/data.service.js b/moonv4/moon_gui/static/app/services/moon/policy/parameters/data.service.js index 1bbd3b24..1bbd3b24 100644..100755 --- a/moonv4/moon_gui/static/app/services/moon/policy/parameters/data.service.js +++ b/moonv4/moon_gui/static/app/services/moon/policy/parameters/data.service.js diff --git a/moonv4/moon_gui/static/app/services/moon/policy/parameters/perimeter.service.js b/moonv4/moon_gui/static/app/services/moon/policy/parameters/perimeter.service.js index 42e7288a..42e7288a 100644..100755 --- a/moonv4/moon_gui/static/app/services/moon/policy/parameters/perimeter.service.js +++ b/moonv4/moon_gui/static/app/services/moon/policy/parameters/perimeter.service.js diff --git a/moonv4/moon_gui/static/app/services/moon/policy/parameters/rules.service.js b/moonv4/moon_gui/static/app/services/moon/policy/parameters/rules.service.js new file mode 100755 index 00000000..76b24011 --- /dev/null +++ b/moonv4/moon_gui/static/app/services/moon/policy/parameters/rules.service.js @@ -0,0 +1,56 @@ +/** + * @author Samy Abdallah + */ + +(function() { + + 'use strict'; + + angular + .module('moon') + .factory('rulesService', rulesService); + + rulesService.$inject = ['$resource', 'REST_URI', 'utilService']; + + function rulesService($resource, REST_URI, utilService) { + + return { + + data: { + + policy: $resource(REST_URI.POLICIES + ':policy_id/rules/:rule_id', {}, { + get: {method: 'GET'}, + create: {method: 'POST'}, + remove: {method: 'DELETE'} + }) + + }, + + add: function (rules, policyId, callbackSuccess, callbackError ) { + + this.data.policy.create({policy_id: policyId}, rules, callbackSuccess, callbackError); + + }, + + delete: function (ruleId, policyId, callbackSuccess, callbackError ) { + + this.data.policy.remove({policy_id: policyId, rule_id: ruleId}, {}, callbackSuccess, callbackError); + + }, + + findAllFromPolicyWithCallback: function(policyId, callback){ + + this.data.policy.get({policy_id: policyId}).$promise.then(function(data) { + + callback(data.rules.rules); + //callback(utilService.transform(data['rules'], 'rules')); + + }); + + } + + + } + + } +})();
\ No newline at end of file diff --git a/moonv4/moon_gui/static/app/services/moon/policy/policy.service.js b/moonv4/moon_gui/static/app/services/moon/policy/policy.service.js index 5ad31421..5ad31421 100644..100755 --- a/moonv4/moon_gui/static/app/services/moon/policy/policy.service.js +++ b/moonv4/moon_gui/static/app/services/moon/policy/policy.service.js diff --git a/moonv4/moon_gui/static/app/services/moon/rule/metadata.service.js b/moonv4/moon_gui/static/app/services/moon/rule/metadata.service.js index 8c68b2ef..8c68b2ef 100644..100755 --- a/moonv4/moon_gui/static/app/services/moon/rule/metadata.service.js +++ b/moonv4/moon_gui/static/app/services/moon/rule/metadata.service.js diff --git a/moonv4/moon_gui/static/app/services/moon/rule/metarule.service.js b/moonv4/moon_gui/static/app/services/moon/rule/metarule.service.js index 2679fc5b..2679fc5b 100644..100755 --- a/moonv4/moon_gui/static/app/services/moon/rule/metarule.service.js +++ b/moonv4/moon_gui/static/app/services/moon/rule/metarule.service.js diff --git a/moonv4/moon_gui/static/app/services/partner/authentication.service.js b/moonv4/moon_gui/static/app/services/partner/authentication.service.js index b6d3f36d..b6d3f36d 100644..100755 --- a/moonv4/moon_gui/static/app/services/partner/authentication.service.js +++ b/moonv4/moon_gui/static/app/services/partner/authentication.service.js diff --git a/moonv4/moon_gui/static/app/services/partner/nova.service.js b/moonv4/moon_gui/static/app/services/partner/nova.service.js index 38e2a0fc..38e2a0fc 100644..100755 --- a/moonv4/moon_gui/static/app/services/partner/nova.service.js +++ b/moonv4/moon_gui/static/app/services/partner/nova.service.js diff --git a/moonv4/moon_gui/static/app/services/partner/project.service.js b/moonv4/moon_gui/static/app/services/partner/project.service.js index 4ec27f2e..4ec27f2e 100644..100755 --- a/moonv4/moon_gui/static/app/services/partner/project.service.js +++ b/moonv4/moon_gui/static/app/services/partner/project.service.js diff --git a/moonv4/moon_interface/Dockerfile b/moonv4/moon_interface/Dockerfile index de5447b6..268aba48 100644 --- a/moonv4/moon_interface/Dockerfile +++ b/moonv4/moon_interface/Dockerfile @@ -6,6 +6,7 @@ RUN pip3 install moon_utilities moon_db pip --upgrade ADD . /root WORKDIR /root/ RUN pip3 install -r requirements.txt --upgrade +#RUN pip3 install /root/dist/* --upgrade RUN pip3 install . CMD ["python3", "-m", "moon_interface"]
\ No newline at end of file diff --git a/moonv4/moon_interface/LICENSE b/moonv4/moon_interface/LICENSE index 4143aac2..d6456956 100644 --- a/moonv4/moon_interface/LICENSE +++ b/moonv4/moon_interface/LICENSE @@ -174,31 +174,29 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/moonv4/moon_interface/moon_interface/__main__.py b/moonv4/moon_interface/moon_interface/__main__.py index 2dac7b1d..517fdd60 100644 --- a/moonv4/moon_interface/moon_interface/__main__.py +++ b/moonv4/moon_interface/moon_interface/__main__.py @@ -1,3 +1,4 @@ from moon_interface.server import main -main() +server = main() +server.run() diff --git a/moonv4/moon_interface/moon_interface/api/assignments.py b/moonv4/moon_interface/moon_interface/api/assignments.py deleted file mode 100644 index 855a9049..00000000 --- a/moonv4/moon_interface/moon_interface/api/assignments.py +++ /dev/null @@ -1,264 +0,0 @@ -# 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'. -""" -Assignments allow to connect data with elements of perimeter - -""" - -from flask import request -from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call -from moon_utilities.security_functions import check_auth - -__version__ = "0.2.0" - -LOG = logging.getLogger("moon.interface.api." + __name__) - - -class SubjectAssignments(Resource): - """ - Endpoint for subject assignment requests - """ - - __urls__ = ( - "/policies/<string:uuid>/subject_assignments", - "/policies/<string:uuid>/subject_assignments/", - "/policies/<string:uuid>/subject_assignments/<string:perimeter_id>", - "/policies/<string:uuid>/subject_assignments/<string:perimeter_id>/<string:category_id>", - "/policies/<string:uuid>/subject_assignments/<string:perimeter_id>/<string:category_id>/<string:data_id>", - ) - - @check_auth - def get(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): - """Retrieve all subject assignments or a specific one for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the subject - :param category_id: uuid of the subject category - :param data_id: uuid of the subject scope - :param user_id: user ID who do the request - :return: { - "subject_data_id": { - "policy_id": "ID of the policy", - "subject_id": "ID of the subject", - "category_id": "ID of the category", - "assignments": "Assignments list (list of data_id)", - } - } - :internal_api: get_subject_assignments - """ - return call(ctx={"id": uuid, "method": "get_subject_assignments", "perimeter_id": perimeter_id, "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - @check_auth - def post(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): - """Create a subject assignment. - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the subject (not used here) - :param category_id: uuid of the subject category (not used here) - :param data_id: uuid of the subject scope (not used here) - :param user_id: user ID who do the request - :request body: { - "id": "UUID of the subject", - "category_id": "UUID of the category" - "data_id": "UUID of the scope" - } - :return: { - "subject_data_id": { - "policy_id": "ID of the policy", - "subject_id": "ID of the subject", - "category_id": "ID of the category", - "assignments": "Assignments list (list of data_id)", - } - } - :internal_api: update_subject_assignment - """ - return call("security_router", - ctx={"id": uuid, "method": "update_subject_assignment", "user_id": user_id}, args=request.json) - - @check_auth - def delete(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): - """Delete a subject assignment for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the subject - :param category_id: uuid of the subject category - :param data_id: uuid of the subject scope - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_subject_assignment - """ - return call("security_router", - ctx={"id": uuid, "method": "delete_subject_assignment", "perimeter_id": perimeter_id, "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - -class ObjectAssignments(Resource): - """ - Endpoint for object assignment requests - """ - - __urls__ = ( - "/policies/<string:uuid>/object_assignments", - "/policies/<string:uuid>/object_assignments/", - "/policies/<string:uuid>/object_assignments/<string:perimeter_id>", - "/policies/<string:uuid>/object_assignments/<string:perimeter_id>/<string:category_id>", - "/policies/<string:uuid>/object_assignments/<string:perimeter_id>/<string:category_id>/<string:data_id>", - ) - - @check_auth - def get(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): - """Retrieve all object assignment or a specific one for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the object - :param category_id: uuid of the object category - :param data_id: uuid of the object scope - :param user_id: user ID who do the request - :return: { - "object_data_id": { - "policy_id": "ID of the policy", - "object_id": "ID of the object", - "category_id": "ID of the category", - "assignments": "Assignments list (list of data_id)", - } - } - :internal_api: get_object_assignments - """ - return call("security_router", - ctx={"id": uuid, "method": "get_object_assignments", "perimeter_id": perimeter_id, "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - @check_auth - def post(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): - """Create an object assignment. - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the object (not used here) - :param category_id: uuid of the object category (not used here) - :param data_id: uuid of the object scope (not used here) - :param user_id: user ID who do the request - :request body: { - "id": "UUID of the action", - "category_id": "UUID of the category" - "data_id": "UUID of the scope" - } - :return: { - "object_data_id": { - "policy_id": "ID of the policy", - "object_id": "ID of the object", - "category_id": "ID of the category", - "assignments": "Assignments list (list of data_id)", - } - } - :internal_api: update_object_assignment - """ - return call("security_router", - ctx={"id": uuid, "method": "update_object_assignment", "user_id": user_id}, args=request.json) - - @check_auth - def delete(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): - """Delete a object assignment for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the object - :param category_id: uuid of the object category - :param data_id: uuid of the object scope - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_object_assignment - """ - return call("security_router", - ctx={"id": uuid, "method": "delete_object_assignment", "perimeter_id": perimeter_id, "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - -class ActionAssignments(Resource): - """ - Endpoint for action assignment requests - """ - - __urls__ = ( - "/policies/<string:uuid>/action_assignments", - "/policies/<string:uuid>/action_assignments/", - "/policies/<string:uuid>/action_assignments/<string:perimeter_id>", - "/policies/<string:uuid>/action_assignments/<string:perimeter_id>/<string:category_id>", - "/policies/<string:uuid>/action_assignments/<string:perimeter_id>/<string:category_id>/<string:data_id>", - ) - - @check_auth - def get(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): - """Retrieve all action assignment or a specific one for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the action - :param category_id: uuid of the action category - :param data_id: uuid of the action scope - :param user_id: user ID who do the request - :return: { - "action_data_id": { - "policy_id": "ID of the policy", - "object_id": "ID of the action", - "category_id": "ID of the category", - "assignments": "Assignments list (list of data_id)", - } - } - :internal_api: get_action_assignments - """ - return call("security_router", ctx={"id": uuid, "method": "get_action_assignments", "perimeter_id": perimeter_id, "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - @check_auth - def post(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): - """Create an action assignment. - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the action (not used here) - :param category_id: uuid of the action category (not used here) - :param data_id: uuid of the action scope (not used here) - :param user_id: user ID who do the request - :request body: { - "id": "UUID of the action", - "category_id": "UUID of the category", - "data_id": "UUID of the scope" - } - :return: { - "action_data_id": { - "policy_id": "ID of the policy", - "object_id": "ID of the action", - "category_id": "ID of the category", - "assignments": "Assignments list (list of data_id)", - } - } - :internal_api: update_action_assignment - """ - return call("security_router", ctx={"id": uuid, "method": "update_action_assignment", "user_id": user_id}, - args=request.json) - - @check_auth - def delete(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): - """Delete a action assignment for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the action - :param category_id: uuid of the action category - :param data_id: uuid of the action scope - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_action_assignment - """ - return call("security_router", ctx={"id": uuid, "method": "delete_action_assignment", "perimeter_id": perimeter_id, "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) diff --git a/moonv4/moon_interface/moon_interface/api/authz.py b/moonv4/moon_interface/moon_interface/api/authz.py index 69de0f80..c9f4697f 100644 --- a/moonv4/moon_interface/moon_interface/api/authz.py +++ b/moonv4/moon_interface/moon_interface/api/authz.py @@ -6,23 +6,120 @@ Authz is the endpoint to get authorization response """ -from uuid import uuid4 -import time +from flask import request from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call +import logging +import pickle +import requests +import time +from uuid import uuid4 + +from moon_interface.authz_requests import AuthzRequest __version__ = "0.1.0" LOG = logging.getLogger("moon.interface.api." + __name__) +def pdp_in_cache(cache, uuid): + """Check if a PDP exist with this Keystone Project ID in the cache of this component + + :param cache: Cache to use + :param uuid: Keystone Project ID + :return: True or False + """ + for item_uuid, item_value in cache.pdp.items(): + if uuid == item_value['keystone_project_id']: + return item_uuid, item_value + return None, None + + +def pdp_in_manager(cache, uuid): + """Check if a PDP exist with this Keystone Project ID in the Manager component + + :param cache: Cache to use + :param uuid: Keystone Project ID + :return: True or False + """ + cache.update() + return pdp_in_cache(cache, uuid) + + +def container_exist(cache, uuid): + """Check if a PDP exist with this Keystone Project ID in the Manager component + + :param cache: Cache to use + :param uuid: Keystone Project ID + :return: True or False + """ + for key, value in cache.containers.items(): + if "keystone_project_id" not in value: + continue + if value["keystone_project_id"] == uuid: + try: + req = requests.head("http://{}:{}/".format( + value.get("hostname"), + value.get("port")[0].get("PublicPort"))) + LOG.info("container_exist {}".format(req.status_code)) + if req.status_code in (200, 201): + return value + return + except requests.exceptions.ConnectionError: + pass + # maybe hostname is not working so trying with IP address + try: + req = requests.head("http://{}:{}/".format( + value.get("ip"), + value.get("port")[0].get("PublicPort"))) + if req.status_code in (200, 201): + return value + return + except requests.exceptions.ConnectionError: + return + + +def create_authz_request(cache, interface_name, manager_url, uuid, subject_name, object_name, action_name): + """Create the authorization request and make the first call to the Authz function + + :param cache: Cache to use + :param interface_name: hostname of the interface + :param manager_url: URL of the manager + :param uuid: Keystone Project ID + :param subject_name: name of the subject + :param object_name: name of the object + :param action_name: name of the action + :return: Authorisation request + """ + req_id = uuid4().hex + ctx = { + "project_id": uuid, + "subject_name": subject_name, + "object_name": object_name, + "action_name": action_name, + "request_id": req_id, + "interface_name": interface_name, + "manager_url": manager_url, + "cookie": uuid4().hex + } + cache.authz_requests[req_id] = AuthzRequest(ctx) + return cache.authz_requests[req_id] + + class Authz(Resource): """ Endpoint for authz requests """ - __urls__ = ("/authz/<string:uuid>/<string:subject_name>/<string:object_name>/<string:action_name>", ) + __urls__ = ( + "/authz/<string:uuid>", + "/authz/<string:uuid>/<string:subject_name>/<string:object_name>/<string:action_name>", + ) + + def __init__(self, **kwargs): + self.CACHE = kwargs.get("cache") + self.INTERFACE_NAME = kwargs.get("interface_name", "interface") + self.MANAGER_URL = kwargs.get("manager_url", "http://manager:8080") + self.TIMEOUT = 5 def get(self, uuid=None, subject_name=None, object_name=None, action_name=None): """Get a response on an authorization request @@ -51,17 +148,46 @@ class Authz(Resource): } :internal_api: authz """ - # Note (asteroide): user_id default to admin to be able to read the database - # it would be better to have a read-only user. - start_time = time.time() - result = call("security_router", ctx={"id": uuid, - "call_master": False, - "method": "authz", - "subject_name": subject_name, - "object_name": object_name, - "action_name": action_name, - "user_id": "admin", - "request_id": uuid4().hex}, args={}) - end_time = time.time() - result['time'] = {"start": start_time, "end": end_time} - return result + pdp_id, pdp_value = pdp_in_cache(self.CACHE, uuid) + if not pdp_id: + pdp_id, pdp_value = pdp_in_manager(self.CACHE, uuid) + if not pdp_id: + return { + "result": False, + "message": "Unknown Project ID or " + "Project ID is not bind to a PDP."}, 403 + authz_request = create_authz_request( + cache=self.CACHE, + uuid=uuid, + interface_name=self.INTERFACE_NAME, + manager_url=self.MANAGER_URL, + subject_name=subject_name, + object_name=object_name, + action_name=action_name) + cpt = 0 + while True: + if cpt > self.TIMEOUT*10: + return {"result": False, + "message": "Authz request had timed out."}, 500 + if authz_request.is_authz(): + if authz_request.final_result == "Grant": + return {"result": True, "message": ""}, 200 + return {"result": False, "message": ""}, 401 + cpt += 1 + time.sleep(0.1) + + def patch(self, uuid=None, subject_name=None, object_name=None, action_name=None): + """Get a response on an authorization request + + :param uuid: uuid of the authorization request + :param subject_name: not used + :param object_name: not used + :param action_name: not used + :request body: a Context object + :return: {} + :internal_api: authz + """ + if uuid in self.CACHE.authz_requests: + self.CACHE.authz_requests[uuid].set_result(pickle.loads(request.data)) + return "", 201 + return {"result": False, "message": "The request ID is unknown"}, 500 diff --git a/moonv4/moon_interface/moon_interface/api/data.py b/moonv4/moon_interface/moon_interface/api/data.py deleted file mode 100644 index 6d959095..00000000 --- a/moonv4/moon_interface/moon_interface/api/data.py +++ /dev/null @@ -1,259 +0,0 @@ -# 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'. -""" -Data are elements used to create rules - -""" - -from flask import request -from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call -from moon_utilities.security_functions import check_auth - -__version__ = "0.2.0" - -LOG = logging.getLogger("moon.interface.api." + __name__) - - -class SubjectData(Resource): - """ - Endpoint for subject data requests - """ - - __urls__ = ( - "/policies/<string:uuid>/subject_data", - "/policies/<string:uuid>/subject_data/", - "/policies/<string:uuid>/subject_data/<string:category_id>", - "/policies/<string:uuid>/subject_data/<string:category_id>/<string:data_id>", - ) - - @check_auth - def get(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Retrieve all subject categories or a specific one if sid is given for a given policy - - :param uuid: uuid of the policy - :param category_id: uuid of the subject category - :param data_id: uuid of the subject data - :param user_id: user ID who do the request - :return: [{ - "policy_id": "policy_id1", - "category_id": "category_id1", - "data": { - "subject_data_id": { - "name": "name of the data", - "description": "description of the data" - } - } - }] - :internal_api: get_subject_data - """ - return call("security_router", ctx={"id": uuid, "method": "get_subject_data", "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - @check_auth - def post(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Create or update a subject. - - :param uuid: uuid of the policy - :param category_id: uuid of the subject category - :param data_id: uuid of the subject data - :param user_id: user ID who do the request - :request body: { - "name": "name of the data", - "description": "description of the data" - } - :return: { - "policy_id": "policy_id1", - "category_id": "category_id1", - "data": { - "subject_data_id": { - "name": "name of the data", - "description": "description of the data" - } - } - } - :internal_api: add_subject_data - """ - return call("security_router", ctx={"id": uuid, "method": "add_subject_data", "category_id": category_id, "user_id": user_id}, - args=request.json) - - @check_auth - def delete(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Delete a subject for a given policy - - :param uuid: uuid of the policy - :param category_id: uuid of the subject category - :param data_id: uuid of the subject data - :param user_id: user ID who do the request - :return: [{ - "result": "True or False", - "message": "optional message" - }] - :internal_api: delete_subject_data - """ - return call("security_router", ctx={"id": uuid, "method": "delete_subject_data", "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - -class ObjectData(Resource): - """ - Endpoint for object data requests - """ - - __urls__ = ( - "/policies/<string:uuid>/object_data", - "/policies/<string:uuid>/object_data/", - "/policies/<string:uuid>/object_data/<string:category_id>", - "/policies/<string:uuid>/object_data/<string:category_id>/<string:data_id>", - ) - - @check_auth - def get(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Retrieve all object categories or a specific one if sid is given for a given policy - - :param uuid: uuid of the policy - :param category_id: uuid of the object category - :param data_id: uuid of the object data - :param user_id: user ID who do the request - :return: [{ - "policy_id": "policy_id1", - "category_id": "category_id1", - "data": { - "object_data_id": { - "name": "name of the data", - "description": "description of the data" - } - } - }] - :internal_api: get_object_data - """ - return call("security_router", ctx={"id": uuid, "method": "get_object_data", "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - @check_auth - def post(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Create or update a object. - - :param uuid: uuid of the policy - :param category_id: uuid of the object category - :param data_id: uuid of the object data - :param user_id: user ID who do the request - :request body: { - "name": "name of the data", - "description": "description of the data" - } - :return: { - "policy_id": "policy_id1", - "category_id": "category_id1", - "data": { - "object_data_id": { - "name": "name of the data", - "description": "description of the data" - } - } - } - :internal_api: add_object_data - """ - return call("security_router", ctx={"id": uuid, "method": "add_object_data", "category_id": category_id, "user_id": user_id}, args=request.json) - - @check_auth - def delete(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Delete a object for a given policy - - :param uuid: uuid of the policy - :param category_id: uuid of the object category - :param data_id: uuid of the object data - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_object_data - """ - return call("security_router", ctx={"id": uuid, "method": "delete_object_data", "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - -class ActionData(Resource): - """ - Endpoint for action data requests - """ - - __urls__ = ( - "/policies/<string:uuid>/action_data", - "/policies/<string:uuid>/action_data/", - "/policies/<string:uuid>/action_data/<string:category_id>", - "/policies/<string:uuid>/action_data/<string:category_id>/<string:data_id>", - ) - - @check_auth - def get(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Retrieve all action categories or a specific one if sid is given for a given policy - - :param uuid: uuid of the policy - :param category_id: uuid of the action category - :param data_id: uuid of the action data - :param user_id: user ID who do the request - :return: [{ - "policy_id": "policy_id1", - "category_id": "category_id1", - "data": { - "action_data_id": { - "name": "name of the data", - "description": "description of the data" - } - } - }] - :internal_api: get_action_data - """ - return call("security_router", ctx={"id": uuid, "method": "get_action_data", "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - @check_auth - def post(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Create or update a action. - - :param uuid: uuid of the policy - :param category_id: uuid of the action category - :param data_id: uuid of the action data - :param user_id: user ID who do the request - :request body: { - "name": "name of the data", - "description": "description of the data" - } - :return: { - "policy_id": "policy_id1", - "category_id": "category_id1", - "data": { - "action_data_id": { - "name": "name of the data", - "description": "description of the data" - } - } - } - :internal_api: add_action_data - """ - return call("security_router", ctx={"id": uuid, "method": "add_action_data", "category_id": category_id, "user_id": user_id}, - args=request.json) - - @check_auth - def delete(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Delete a action for a given policy - - :param uuid: uuid of the policy - :param category_id: uuid of the action category - :param data_id: uuid of the action data - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_action_data - """ - return call("security_router", ctx={"id": uuid, "method": "delete_action_data", "category_id": category_id, "user_id": user_id}, - args={"data_id": data_id}) - - diff --git a/moonv4/moon_interface/moon_interface/api/generic.py b/moonv4/moon_interface/moon_interface/api/generic.py index 80e8abff..702f33cf 100644 --- a/moonv4/moon_interface/moon_interface/api/generic.py +++ b/moonv4/moon_interface/moon_interface/api/generic.py @@ -7,8 +7,7 @@ Those API are helping API used to manage the Moon platform. """ from flask_restful import Resource, request -from oslo_log import log as logging -from moon_utilities.security_functions import call +import logging import moon_interface.api from moon_utilities.security_functions import check_auth @@ -36,7 +35,7 @@ class Status(Resource): } } """ - return call("security_router", method="get_status", ctx={"component_id": component_id}) + raise NotImplemented class Logs(Resource): @@ -71,7 +70,7 @@ class Logs(Resource): args["to"] = to_str args["event_number"] = event_number - return call("security_router", method="get_logs", ctx={"component_id": component_id}, args=args) + raise NotImplemented class API(Resource): @@ -130,22 +129,3 @@ class API(Resource): return {"error": "Unknown endpoint_id {}".format(endpoint_id)} return {group_id: api_desc[group_id]} return api_desc - - -class InternalAPI(Resource): - """ - Endpoint for status requests - """ - - __urls__ = ("/internal_api", "/internal_api/", "/internal_api/<string:component_id>") - - def get(self, component_id=None, user_id=""): - api_list = ("orchestrator", "security_router") - if not component_id: - return {"api": api_list} - if component_id in api_list: - api_desc = dict() - api_desc["name"] = component_id - api_desc["endpoints"] = call("security_router", component_id, {}, "list_api") - return api_desc - diff --git a/moonv4/moon_interface/moon_interface/api/meta_data.py b/moonv4/moon_interface/moon_interface/api/meta_data.py deleted file mode 100644 index 3c933759..00000000 --- a/moonv4/moon_interface/moon_interface/api/meta_data.py +++ /dev/null @@ -1,204 +0,0 @@ -# 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'. -""" -Meta Data are elements used to create Meta data (skeleton of security policies) - -""" - -from flask import request -from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call -from moon_utilities.security_functions import check_auth - -__version__ = "0.2.0" - -LOG = logging.getLogger("moon.interface.api." + __name__) - - -class SubjectCategories(Resource): - """ - Endpoint for subject categories requests - """ - - __urls__ = ( - "/subject_categories", - "/subject_categories/", - "/subject_categories/<string:category_id>", - ) - - @check_auth - def get(self, category_id=None, user_id=None): - """Retrieve all subject categories or a specific one - - :param category_id: uuid of the subject category - :param user_id: user ID who do the request - :return: { - "subject_category_id": { - "name": "name of the category", - "description": "description of the category" - } - } - :internal_api: get_subject_categories - """ - return call("security_router", ctx={"method": "get_subject_categories", "user_id": user_id}, args={"category_id": category_id}) - - @check_auth - def post(self, category_id=None, user_id=None): - """Create or update a subject category. - - :param category_id: must not be used here - :param user_id: user ID who do the request - :request body: { - "name": "name of the category", - "description": "description of the category" - } - :return: { - "subject_category_id": { - "name": "name of the category", - "description": "description of the category" - } - } - :internal_api: add_subject_category - """ - return call("security_router", ctx={"method": "set_subject_category", "user_id": user_id}, args=request.json) - - @check_auth - def delete(self, category_id=None, user_id=None): - """Delete a subject category - - :param category_id: uuid of the subject category to delete - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_subject_category - """ - return call("security_router", ctx={"method": "delete_subject_category", "user_id": user_id}, args={"category_id": category_id}) - - -class ObjectCategories(Resource): - """ - Endpoint for object categories requests - """ - - __urls__ = ( - "/object_categories", - "/object_categories/", - "/object_categories/<string:category_id>", - ) - - @check_auth - def get(self, category_id=None, user_id=None): - """Retrieve all object categories or a specific one - - :param category_id: uuid of the object category - :param user_id: user ID who do the request - :return: { - "object_category_id": { - "name": "name of the category", - "description": "description of the category" - } - } - :internal_api: get_object_categories - """ - return call("security_router", ctx={"method": "get_object_categories", "user_id": user_id}, args={"category_id": category_id}) - - @check_auth - def post(self, category_id=None, user_id=None): - """Create or update a object category. - - :param category_id: must not be used here - :param user_id: user ID who do the request - :request body: { - "name": "name of the category", - "description": "description of the category" - } - :return: { - "object_category_id": { - "name": "name of the category", - "description": "description of the category" - } - } - :internal_api: add_object_category - """ - return call("security_router", ctx={"method": "set_object_category", "user_id": user_id}, args=request.json) - - @check_auth - def delete(self, category_id=None, user_id=None): - """Delete an object category - - :param category_id: uuid of the object category to delete - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_object_category - """ - return call("security_router", ctx={"method": "delete_object_category", "user_id": user_id}, args={"category_id": category_id}) - - -class ActionCategories(Resource): - """ - Endpoint for action categories requests - """ - - __urls__ = ( - "/action_categories", - "/action_categories/", - "/action_categories/<string:category_id>", - ) - - @check_auth - def get(self, category_id=None, user_id=None): - """Retrieve all action categories or a specific one - - :param category_id: uuid of the action category - :param user_id: user ID who do the request - :return: { - "action_category_id": { - "name": "name of the category", - "description": "description of the category" - } - } - :internal_api: get_action_categories - """ - return call("security_router", ctx={"method": "get_action_categories", "user_id": user_id}, args={"category_id": category_id}) - - @check_auth - def post(self, category_id=None, user_id=None): - """Create or update an action category. - - :param category_id: must not be used here - :param user_id: user ID who do the request - :request body: { - "name": "name of the category", - "description": "description of the category" - } - :return: { - "action_category_id": { - "name": "name of the category", - "description": "description of the category" - } - } - :internal_api: add_action_category - """ - return call("security_router", ctx={"method": "set_action_category", "user_id": user_id}, args=request.json) - - @check_auth - def delete(self, category_id=None, user_id=None): - """Delete an action - - :param category_id: uuid of the action category to delete - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_action_category - """ - return call("security_router", ctx={"method": "delete_action_category", "user_id": user_id}, args={"category_id": category_id}) diff --git a/moonv4/moon_interface/moon_interface/api/meta_rules.py b/moonv4/moon_interface/moon_interface/api/meta_rules.py deleted file mode 100644 index 85072243..00000000 --- a/moonv4/moon_interface/moon_interface/api/meta_rules.py +++ /dev/null @@ -1,138 +0,0 @@ -# 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'. -""" -Meta rules are skeleton for security policies - -""" - -from flask import request -from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call -from moon_utilities.security_functions import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger("moon.interface.api." + __name__) - - -class MetaRules(Resource): - """ - Endpoint for meta rules requests - """ - - __urls__ = ("/meta_rules", - "/meta_rules/", - "/meta_rules/<string:meta_rule_id>", - "/meta_rules/<string:meta_rule_id>/") - - @check_auth - def get(self, meta_rule_id=None, user_id=None): - """Retrieve all sub meta rules - - :param meta_rule_id: Meta rule algorithm ID - :param user_id: user ID who do the request - :return: { - "meta_rules": { - "meta_rule_id1": { - "name": "name of the meta rule", - "algorithm": "name of the meta rule algorithm", - "subject_categories": ["subject_category_id1", "subject_category_id2"], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - }, - } - } - :internal_api: get_meta_rules - """ - return call("security_router", ctx={"method": "get_meta_rules", - "user_id": user_id, - "meta_rule_id": meta_rule_id}, args={}) - - @check_auth - def post(self, meta_rule_id=None, user_id=None): - """Add a meta rule - - :param meta_rule_id: Meta rule ID - :param user_id: user ID who do the request - :request body: post = { - "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - } - :return: { - "meta_rules": { - "meta_rule_id1": { - "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - }, - } - } - :internal_api: add_meta_rules - """ - return call("security_router", ctx={"method": "add_meta_rules", - "user_id": user_id, - "meta_rule_id": meta_rule_id}, args=request.json) - - @check_auth - def patch(self, meta_rule_id=None, user_id=None): - """Update a meta rule - - :param meta_rule_id: Meta rule ID - :param user_id: user ID who do the request - :request body: patch = { - "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - } - :return: { - "meta_rules": { - "meta_rule_id1": { - "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - }, - } - } - :internal_api: set_meta_rules - """ - return call("security_router", ctx={"method": "set_meta_rules", - "user_id": user_id, - "meta_rule_id": meta_rule_id}, args=request.json) - - @check_auth - def delete(self, meta_rule_id=None, user_id=None): - """Delete a meta rule - - :param meta_rule_id: Meta rule ID - :param user_id: user ID who do the request - :request body: delete = { - "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - } - :return: { - "meta_rules": { - "meta_rule_id1": { - "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - }, - } - } - :internal_api: delete_meta_rules - """ - return call("security_router", ctx={"method": "delete_meta_rules", - "user_id": user_id, - "meta_rule_id": meta_rule_id}, args=request.json) - - diff --git a/moonv4/moon_interface/moon_interface/api/models.py b/moonv4/moon_interface/moon_interface/api/models.py deleted file mode 100644 index f905db63..00000000 --- a/moonv4/moon_interface/moon_interface/api/models.py +++ /dev/null @@ -1,101 +0,0 @@ -# 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'. -""" -Models aggregate multiple meta rules -""" - -from flask import request -from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call -from moon_utilities.security_functions import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger("moon.interface.api." + __name__) - - -class Models(Resource): - """ - Endpoint for model requests - """ - - __urls__ = ( - "/models", - "/models/", - "/models/<string:uuid>", - "/models/<string:uuid>/", - ) - - @check_auth - def get(self, uuid=None, user_id=None): - """Retrieve all models - - :param uuid: uuid of the model - :param user_id: user ID who do the request - :return: { - "model_id1": { - "name": "...", - "description": "...", - "meta_rules": ["meta_rule_id1", ] - } - } - :internal_api: get_models - """ - return call("security_router", ctx={"id": uuid, "method": "get_models", "user_id": user_id}, args={}) - - @check_auth - def post(self, uuid=None, user_id=None): - """Create model. - - :param uuid: uuid of the model (not used here) - :param user_id: user ID who do the request - :request body: { - "name": "...", - "description": "...", - "meta_rules": ["meta_rule_id1", ] - } - :return: { - "model_id1": { - "name": "...", - "description": "...", - "meta_rules": ["meta_rule_id1", ] - } - } - :internal_api: add_model - """ - return call("security_router", ctx={"id": uuid, "method": "add_model", "user_id": user_id}, args=request.json) - - @check_auth - def delete(self, uuid=None, user_id=None): - """Delete a model - - :param uuid: uuid of the model to delete - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_model - """ - return call("security_router", ctx={"id": uuid, "method": "delete_model", "user_id": user_id}, args={}) - - @check_auth - def patch(self, uuid=None, user_id=None): - """Update a model - - :param uuid: uuid of the model to update - :param user_id: user ID who do the request - :return: { - "model_id1": { - "name": "...", - "description": "...", - "meta_rules": ["meta_rule_id1", ] - } - } - :internal_api: update_model - """ - return call("security_router", ctx={"id": uuid, "method": "update_model", "user_id": user_id}, args=request.json) - diff --git a/moonv4/moon_interface/moon_interface/api/pdp.py b/moonv4/moon_interface/moon_interface/api/pdp.py deleted file mode 100644 index 5316227b..00000000 --- a/moonv4/moon_interface/moon_interface/api/pdp.py +++ /dev/null @@ -1,106 +0,0 @@ -# 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'. -""" -PDP are Policy Decision Point. - -""" - -from flask import request -from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call -from moon_utilities.security_functions import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger("moon.interface.api." + __name__) - - -class PDP(Resource): - """ - Endpoint for pdp requests - """ - - __urls__ = ( - "/pdp", - "/pdp/", - "/pdp/<string:uuid>", - "/pdp/<string:uuid>/", - ) - - @check_auth - def get(self, uuid=None, user_id=None): - """Retrieve all pdp - - :param uuid: uuid of the pdp - :param user_id: user ID who do the request - :return: { - "pdp_id1": { - "name": "...", - "security_pipeline": [...], - "keystone_project_id": "keystone_project_id1", - "description": "...", - } - } - :internal_api: get_pdp - """ - return call("security_router", ctx={"id": uuid, "method": "get_pdp", "user_id": user_id}, args={}) - - @check_auth - def post(self, uuid=None, user_id=None): - """Create pdp. - - :param uuid: uuid of the pdp (not used here) - :param user_id: user ID who do the request - :request body: { - "name": "...", - "security_pipeline": [...], - "keystone_project_id": "keystone_project_id1", - "description": "...", - } - :return: { - "pdp_id1": { - "name": "...", - "security_pipeline": [...], - "keystone_project_id": "keystone_project_id1", - "description": "...", - } - } - :internal_api: add_pdp - """ - return call("security_router", ctx={"id": uuid, "method": "add_pdp", "user_id": user_id}, args=request.json) - - @check_auth - def delete(self, uuid=None, user_id=None): - """Delete a pdp - - :param uuid: uuid of the pdp to delete - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_pdp - """ - return call("security_router", ctx={"id": uuid, "method": "delete_pdp", "user_id": user_id}, args={}) - - @check_auth - def patch(self, uuid=None, user_id=None): - """Update a pdp - - :param uuid: uuid of the pdp to update - :param user_id: user ID who do the request - :return: { - "pdp_id1": { - "name": "...", - "security_pipeline": [...], - "keystone_project_id": "keystone_project_id1", - "description": "...", - } - } - :internal_api: update_pdp - """ - return call("security_router", ctx={"id": uuid, "method": "update_pdp", "user_id": user_id}, args=request.json) - diff --git a/moonv4/moon_interface/moon_interface/api/perimeter.py b/moonv4/moon_interface/moon_interface/api/perimeter.py deleted file mode 100644 index 177161f6..00000000 --- a/moonv4/moon_interface/moon_interface/api/perimeter.py +++ /dev/null @@ -1,312 +0,0 @@ -# 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'. -""" -* Subjects are the source of an action on an object (examples : users, virtual machines) -* Objects are the destination of an action (examples virtual machines, virtual Routers) -* Actions are what subject wants to do on an object -""" - -from flask import request -from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call -from moon_utilities.security_functions import check_auth - -__version__ = "0.2.0" - -LOG = logging.getLogger("moon.interface.api." + __name__) - - -class Subjects(Resource): - """ - Endpoint for subjects requests - """ - - __urls__ = ( - "/subjects", - "/subjects/", - "/subjects/<string:perimeter_id>", - "/policies/<string:uuid>/subjects", - "/policies/<string:uuid>/subjects/", - "/policies/<string:uuid>/subjects/<string:perimeter_id>", - ) - - @check_auth - def get(self, uuid=None, perimeter_id=None, user_id=None): - """Retrieve all subjects or a specific one if perimeter_id is given for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the subject - :param user_id: user ID who do the request - :return: { - "subject_id": { - "name": "name of the subject", - "keystone_id": "keystone id of the subject", - "description": "a description" - } - } - :internal_api: get_subjects - """ - return call("security_router", ctx={"id": uuid, "method": "get_subjects", "user_id": user_id}, args={"perimeter_id": perimeter_id}) - - @check_auth - def post(self, uuid=None, perimeter_id=None, user_id=None): - """Create or update a subject. - - :param uuid: uuid of the policy - :param perimeter_id: must not be used here - :param user_id: user ID who do the request - :request body: { - "name": "name of the subject", - "description": "description of the subject", - "password": "password for the subject", - "email": "email address of the subject" - } - :return: { - "subject_id": { - "name": "name of the subject", - "keystone_id": "keystone id of the subject", - "description": "description of the subject", - "password": "password for the subject", - "email": "email address of the subject" - } - } - :internal_api: set_subject - """ - return call("security_router", ctx={"id": uuid, "method": "set_subject", "user_id": user_id, "perimeter_id": None}, - args=request.json) - - @check_auth - def patch(self, uuid=None, perimeter_id=None, user_id=None): - """Create or update a subject. - - :param uuid: uuid of the policy - :param perimeter_id: must not be used here - :param user_id: user ID who do the request - :request body: { - "name": "name of the subject", - "description": "description of the subject", - "password": "password for the subject", - "email": "email address of the subject" - } - :return: { - "subject_id": { - "name": "name of the subject", - "keystone_id": "keystone id of the subject", - "description": "description of the subject", - "password": "password for the subject", - "email": "email address of the subject" - } - } - :internal_api: set_subject - """ - return call("security_router", ctx={"id": uuid, "method": "set_subject", "user_id": user_id, "perimeter_id": perimeter_id}, - args=request.json) - - @check_auth - def delete(self, uuid=None, perimeter_id=None, user_id=None): - """Delete a subject for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the subject - :param user_id: user ID who do the request - :return: { - "subject_id": { - "name": "name of the subject", - "keystone_id": "keystone id of the subject", - "description": "description of the subject", - "password": "password for the subject", - "email": "email address of the subject" - } - } - :internal_api: delete_subject - """ - return call("security_router", ctx={"id": uuid, "method": "delete_subject", "user_id": user_id}, args={"perimeter_id": perimeter_id}) - - -class Objects(Resource): - """ - Endpoint for objects requests - """ - - __urls__ = ( - "/objects", - "/objects/", - "/objects/<string:perimeter_id>", - "/policies/<string:uuid>/objects", - "/policies/<string:uuid>/objects/", - "/policies/<string:uuid>/objects/<string:perimeter_id>", - ) - - @check_auth - def get(self, uuid=None, perimeter_id=None, user_id=None): - """Retrieve all objects or a specific one if perimeter_id is given for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the object - :param user_id: user ID who do the request - :return: { - "object_id": { - "name": "name of the object", - "description": "description of the object" - } - } - :internal_api: get_objects - """ - return call("security_router", ctx={"id": uuid, "method": "get_objects", "user_id": user_id}, args={"perimeter_id": perimeter_id}) - - @check_auth - def post(self, uuid=None, perimeter_id=None, user_id=None): - """Create or update a object. - - :param uuid: uuid of the policy - :param perimeter_id: must not be used here - :param user_id: user ID who do the request - :request body: { - "object_name": "name of the object", - "object_description": "description of the object" - } - :return: { - "object_id": { - "name": "name of the object", - "description": "description of the object" - } - } - :internal_api: set_object - """ - return call("security_router", ctx={"id": uuid, "method": "set_object", "user_id": user_id, "perimeter_id": None}, - args=request.json) - - @check_auth - def patch(self, uuid=None, perimeter_id=None, user_id=None): - """Create or update a object. - - :param uuid: uuid of the policy - :param perimeter_id: must not be used here - :param user_id: user ID who do the request - :request body: { - "object_name": "name of the object", - "object_description": "description of the object" - } - :return: { - "object_id": { - "name": "name of the object", - "description": "description of the object" - } - } - :internal_api: set_object - """ - return call("security_router", ctx={"id": uuid, "method": "set_object", "user_id": user_id, "perimeter_id": perimeter_id}, - args=request.json) - - @check_auth - def delete(self, uuid=None, perimeter_id=None, user_id=None): - """Delete a object for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the object - :param user_id: user ID who do the request - :return: { - "object_id": { - "name": "name of the object", - "description": "description of the object" - } - } - :internal_api: delete_object - """ - return call("security_router", ctx={"id": uuid, "method": "delete_object", "user_id": user_id}, args={"perimeter_id": perimeter_id}) - - -class Actions(Resource): - """ - Endpoint for actions requests - """ - - __urls__ = ( - "/actions", - "/actions/", - "/actions/<string:perimeter_id>", - "/policies/<string:uuid>/actions", - "/policies/<string:uuid>/actions/", - "/policies/<string:uuid>/actions/<string:perimeter_id>", - ) - - @check_auth - def get(self, uuid=None, perimeter_id=None, user_id=None): - """Retrieve all actions or a specific one if perimeter_id is given for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the action - :param user_id: user ID who do the request - :return: { - "action_id": { - "name": "name of the action", - "description": "description of the action" - } - } - :internal_api: get_actions - """ - return call("security_router", ctx={"id": uuid, "method": "get_actions", "user_id": user_id}, args={"perimeter_id": perimeter_id}) - - @check_auth - def post(self, uuid=None, perimeter_id=None, user_id=None): - """Create or update a action. - - :param uuid: uuid of the policy - :param perimeter_id: must not be used here - :param user_id: user ID who do the request - :request body: { - "name": "name of the action", - "description": "description of the action" - } - :return: { - "action_id": { - "name": "name of the action", - "description": "description of the action" - } - } - :internal_api: set_action - """ - return call("security_router", ctx={"id": uuid, "method": "set_action", "user_id": user_id, "perimeter_id": None}, - args=request.json) - - @check_auth - def patch(self, uuid=None, perimeter_id=None, user_id=None): - """Create or update a action. - - :param uuid: uuid of the policy - :param perimeter_id: must not be used here - :param user_id: user ID who do the request - :request body: { - "name": "name of the action", - "description": "description of the action" - } - :return: { - "action_id": { - "name": "name of the action", - "description": "description of the action" - } - } - :internal_api: set_action - """ - return call("security_router", ctx={"id": uuid, "method": "set_action", "user_id": user_id, "perimeter_id": perimeter_id}, - args=request.json) - - @check_auth - def delete(self, uuid=None, perimeter_id=None, user_id=None): - """Delete a action for a given policy - - :param uuid: uuid of the policy - :param perimeter_id: uuid of the action - :param user_id: user ID who do the request - :return: { - "action_id": { - "name": "name of the action", - "description": "description of the action" - } - } - :internal_api: delete_action - """ - return call("security_router", ctx={"id": uuid, "method": "delete_action", "user_id": user_id}, args={"perimeter_id": perimeter_id}) diff --git a/moonv4/moon_interface/moon_interface/api/policies.py b/moonv4/moon_interface/moon_interface/api/policies.py deleted file mode 100644 index 5a84b612..00000000 --- a/moonv4/moon_interface/moon_interface/api/policies.py +++ /dev/null @@ -1,106 +0,0 @@ -# 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'. -""" -Policies are instances of security models and implement security policies - -""" - -from flask import request -from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call -from moon_utilities.security_functions import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger("moon.interface.api." + __name__) - - -class Policies(Resource): - """ - Endpoint for policy requests - """ - - __urls__ = ( - "/policies", - "/policies/", - "/policies/<string:uuid>", - "/policies/<string:uuid>/", - ) - - @check_auth - def get(self, uuid=None, user_id=None): - """Retrieve all policies - - :param uuid: uuid of the policy - :param user_id: user ID who do the request - :return: { - "policy_id1": { - "name": "...", - "model_id": "...", - "genre": "...", - "description": "...", - } - } - :internal_api: get_policies - """ - return call("security_router", ctx={"id": uuid, "method": "get_policies", "user_id": user_id}, args={}) - - @check_auth - def post(self, uuid=None, user_id=None): - """Create policy. - - :param uuid: uuid of the policy (not used here) - :param user_id: user ID who do the request - :request body: { - "name": "...", - "model_id": "...", - "genre": "...", - "description": "...", - } - :return: { - "policy_id1": { - "name": "...", - "model_id": "...", - "genre": "...", - "description": "...", - } - } - :internal_api: add_policy - """ - return call("security_router", ctx={"id": uuid, "method": "add_policy", "user_id": user_id}, args=request.json) - - @check_auth - def delete(self, uuid=None, user_id=None): - """Delete a policy - - :param uuid: uuid of the policy to delete - :param user_id: user ID who do the request - :return: { - "result": "True or False", - "message": "optional message" - } - :internal_api: delete_policy - """ - return call("security_router", ctx={"id": uuid, "method": "delete_policy", "user_id": user_id}, args={}) - - @check_auth - def patch(self, uuid=None, user_id=None): - """Update a policy - - :param uuid: uuid of the policy to update - :param user_id: user ID who do the request - :return: { - "policy_id1": { - "name": "...", - "model_id": "...", - "genre": "...", - "description": "...", - } - } - :internal_api: update_policy - """ - return call("security_router", ctx={"id": uuid, "method": "update_policy", "user_id": user_id}, args=request.json) - diff --git a/moonv4/moon_interface/moon_interface/api/rules.py b/moonv4/moon_interface/moon_interface/api/rules.py deleted file mode 100644 index 1111729c..00000000 --- a/moonv4/moon_interface/moon_interface/api/rules.py +++ /dev/null @@ -1,114 +0,0 @@ -# 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'. -""" -Rules (TODO) -""" - -from flask import request -from flask_restful import Resource -from oslo_log import log as logging -from moon_utilities.security_functions import call -from moon_utilities.security_functions import check_auth - -__version__ = "0.1.0" - -LOG = logging.getLogger("moon.interface.api." + __name__) - - -class Rules(Resource): - """ - Endpoint for rules requests - """ - - __urls__ = ("/policies/<string:uuid>/rules", - "/policies/<string:uuid>/rules/", - "/policies/<string:uuid>/rules/<string:rule_id>", - "/policies/<string:uuid>/rules/<string:rule_id>/", - ) - - @check_auth - def get(self, uuid=None, rule_id=None, user_id=None): - """Retrieve all rules or a specific one - - :param uuid: policy ID - :param rule_id: rule ID - :param user_id: user ID who do the request - :return: { - "rules": [ - "policy_id": "policy_id1", - "meta_rule_id": "meta_rule_id1", - "rule_id1": ["subject_data_id1", "object_data_id1", "action_data_id1"], - "rule_id2": ["subject_data_id2", "object_data_id2", "action_data_id2"], - ] - } - :internal_api: get_rules - """ - return call("security_router", ctx={"id": uuid, - "method": "get_rules", - "user_id": user_id, - "rule_id": rule_id}, args={}) - - @check_auth - def post(self, uuid=None, rule_id=None, user_id=None): - """Add a rule to a meta rule - - :param uuid: policy ID - :param rule_id: rule ID - :param user_id: user ID who do the request - :request body: post = { - "meta_rule_id": "meta_rule_id1", - "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], - "instructions": ( - {"decision": "grant"}, - ) - "enabled": True - } - :return: { - "rules": [ - "meta_rule_id": "meta_rule_id1", - "rule_id1": { - "rule": ["subject_data_id1", "object_data_id1", "action_data_id1"], - "instructions": ( - {"decision": "grant"}, # "grant" to immediately exit, - # "continue" to wait for the result of next policy - # "deny" to deny the request - ) - } - "rule_id2": { - "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], - "instructions": ( - { - "update": { - "operation": "add", # operations may be "add" or "delete" - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the policy named rbac - ) - } - ] - } - :internal_api: add_rule - """ - return call("security_router", ctx={"id": uuid, - "method": "add_rule", - "user_id": user_id, - "rule_id": rule_id}, args=request.json) - - @check_auth - def delete(self, uuid=None, rule_id=None, user_id=None): - """Delete one rule linked to a specific sub meta rule - - :param uuid: policy ID - :param rule_id: rule ID - :param user_id: user ID who do the request - :return: { "result": true } - :internal_api: delete_rule - """ - return call("security_router", ctx={"id": uuid, - "method": "delete_rule", - "user_id": user_id, - "rule_id": rule_id}, args={}) - diff --git a/moonv4/moon_interface/moon_interface/authz_requests.py b/moonv4/moon_interface/moon_interface/authz_requests.py new file mode 100644 index 00000000..c09ee957 --- /dev/null +++ b/moonv4/moon_interface/moon_interface/authz_requests.py @@ -0,0 +1,159 @@ +# 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'. + +import logging +import itertools +import pickle +import requests +from moon_utilities import configuration, exceptions +from moon_utilities.security_functions import Context +from moon_utilities.cache import Cache + +LOG = logging.getLogger("moon.interface.authz_requests") + + +CACHE = Cache() +CACHE.update() + + +class AuthzRequest: + + result = None + final_result = "Deny" + req_max_delay = 2 + + def __init__(self, ctx, args=None): + self.context = Context(ctx, CACHE) + self.args = args + self.request_id = ctx["request_id"] + if ctx['project_id'] not in CACHE.container_chaining: + raise exceptions.KeystoneProjectError("Unknown Project ID {}".format(ctx['project_id'])) + self.container_chaining = CACHE.container_chaining[ctx['project_id']] + if len(self.container_chaining) == 0: + raise exceptions.MoonError('Void container chaining') + self.pdp_container = self.container_chaining[0]["container_id"] + self.run() + + def run(self): + self.context.delete_cache() + req = None + try: + req = requests.post("http://{}:{}/authz".format( + self.container_chaining[0]["hostip"], + self.container_chaining[0]["port"], + ), data=pickle.dumps(self.context)) + if req.status_code != 200: + raise exceptions.AuthzException( + "Receive bad response from Authz function " + "(with IP address - {})".format( + req.status_code + )) + except requests.exceptions.ConnectionError: + LOG.error("Cannot connect to {}".format( + "http://{}:{}/authz".format( + self.container_chaining[0]["hostip"], + self.container_chaining[0]["port"] + ))) + except ValueError: + try: + req = requests.post("http://{}:{}/authz".format( + self.container_chaining[0]["hostname"], + self.container_chaining[0]["port"], + ), data=pickle.dumps(self.context)) + if req.status_code != 200: + raise exceptions.AuthzException( + "Receive bad response from Authz function " + "(with hostname - {})".format( + req.status_code + )) + except requests.exceptions.ConnectionError: + LOG.error("Cannot connect to {}".format( + "http://{}:{}/authz".format( + self.container_chaining[0]["hostname"], + self.container_chaining[0]["port"] + ))) + raise exceptions.AuthzException( + "Cannot connect to Authz function") + self.context.set_cache(CACHE) + if req and len(self.container_chaining) == 1: + self.result = pickle.loads(req.content) + + # def __exec_next_state(self, rule_found): + # index = self.context.index + # current_meta_rule = self.context.headers[index] + # current_container = self.__get_container_from_meta_rule(current_meta_rule) + # current_container_genre = current_container["genre"] + # try: + # next_meta_rule = self.context.headers[index + 1] + # except IndexError: + # next_meta_rule = None + # if current_container_genre == "authz": + # if rule_found: + # return True + # pass + # if next_meta_rule: + # # next will be session if current is deny and session is unset + # if self.payload["authz_context"]['pdp_set'][next_meta_rule]['effect'] == "unset": + # return notify( + # request_id=self.payload["authz_context"]["request_id"], + # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], + # payload=self.payload) + # # next will be delegation if current is deny and session is passed or deny and delegation is unset + # else: + # LOG.error("Delegation is not developed!") + # + # else: + # # else next will be None and the request is sent to router + # return self.__return_to_router() + # elif current_container_genre == "session": + # pass + # # next will be next container in headers if current is passed + # if self.payload["authz_context"]['pdp_set'][current_meta_rule]['effect'] == "passed": + # return notify( + # request_id=self.payload["authz_context"]["request_id"], + # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], + # payload=self.payload) + # # next will be None if current is grant and the request is sent to router + # else: + # return self.__return_to_router() + # elif current_container_genre == "delegation": + # LOG.error("Delegation is not developed!") + # # next will be authz if current is deny + # # next will be None if current is grant and the request is sent to router + + def set_result(self, result): + self.result = result + + def is_authz(self): + if not self.result: + return False + authz_results = [] + for key in self.result.pdp_set: + if "effect" in self.result.pdp_set[key]: + if self.result.pdp_set[key]["effect"] == "grant": + # the pdp is a authorization PDP and grant the request + authz_results.append(True) + elif self.result.pdp_set[key]["effect"] == "passed": + # the pdp is not a authorization PDP (session or delegation) and had run normally + authz_results.append(True) + elif self.result.pdp_set[key]["effect"] == "unset": + # the pdp is not a authorization PDP (session or delegation) and had not yep run + authz_results.append(True) + else: + # the pdp is (or not) a authorization PDP and had run badly + authz_results.append(False) + if list(itertools.accumulate(authz_results, lambda x, y: x & y))[-1]: + self.result.pdp_set["effect"] = "grant" + if self.result: + if self.result.pdp_set["effect"] == "grant": + self.final_result = "Grant" + return True + self.final_result = "Deny" + return True + + # def notify(self, request_id, container_id, payload): + # LOG.info("notify {} {} {}".format(request_id, container_id, payload)) + # # TODO: send the notification and wait for the result + # # req = requests.get() diff --git a/moonv4/moon_interface/moon_interface/containers.py b/moonv4/moon_interface/moon_interface/containers.py new file mode 100644 index 00000000..1ca76a2d --- /dev/null +++ b/moonv4/moon_interface/moon_interface/containers.py @@ -0,0 +1,102 @@ +# Copyright 2017 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'. + +import docker +import logging +import re +import requests +import time +from moon_utilities import configuration, exceptions + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.interface.container") + + +class DockerManager: + + def __init__(self): + docker_conf = configuration.get_configuration("docker")['docker'] + self.docker = docker.DockerClient(base_url=docker_conf['url']) + + def create_container(self, data): + """Create the container through the docker client + + :param data: { + "name": "authz", + "hostname": "authz123456789", + "port": { + "PrivatePort": 8090, + "Type": "tcp", + "IP": "0.0.0.0", + "PublicPort": 8090 + }, + "keystone_project_id": "keystone_project_id1", + "pdp_id": "123456789", + "container_name": "wukongsun/moon_authz:v4.1" + } + :return: container output + """ + output = self.docker.containers.run( + image=data.get("container_name"), + hostname=data.get("hostname", data.get("name"))[:63], + name=data.get("name"), + network='moon', + ports={'{}/{}'.format( + data.get("port").get("PrivatePort"), + data.get("port").get("Type") + ): int(data.get("port").get("PrivatePort"))}, + environment={ + "UUID": data.get("hostname"), + "BIND": data.get("port").get("IP"), + "TYPE": data.get("plugin_name"), + "PORT": data.get("port").get("PrivatePort"), + "PDP_ID": data.get("pdp_id"), + "META_RULE_ID": data.get("meta_rule_id"), + "KEYSTONE_PROJECT_ID": data.get("keystone_project_id"), + }, + detach=True + ) + try: + req = requests.head("http://{}:{}/".format(data.get("hostname"), data.get("port").get("PublicPort"))) + except requests.exceptions.ConnectionError: + pass + else: + if req.status_code != 200: + raise exceptions.DockerError("Container {} is not running!".format(data.get("hostname"))) + output.ip = "0.0.0.0" + return output + + # Note: host is not reachable through hostname so trying to find th IP address + res = output.exec_run("ip addr") + find = re.findall("inet (\d+\.\d+\.\d+\.\d+)", res.decode("utf-8")) + ip = "127.0.0.1" + for ip in find: + if ip.startswith("127"): + continue + break + cpt = 0 + while True: + try: + req = requests.head("http://{}:{}/".format(ip, data.get("port").get("PublicPort"))) + except requests.exceptions.ConnectionError: + pass + else: + if req.status_code not in (200, 201): + LOG.error("url={}".format("http://{}:{}/".format(ip, data.get("port").get("PublicPort")))) + LOG.error("req={}".format(req)) + raise exceptions.DockerError("Container {} is not running!".format(data.get("hostname"))) + output.ip = ip + return output + finally: + cpt += 1 + time.sleep(0.1) + if cpt > 20: + break + output.ip = ip + return output + + def delete_container(self, uuid): + raise NotImplementedError diff --git a/moonv4/moon_interface/moon_interface/http_server.py b/moonv4/moon_interface/moon_interface/http_server.py index 046337a2..387699f8 100644 --- a/moonv4/moon_interface/moon_interface/http_server.py +++ b/moonv4/moon_interface/moon_interface/http_server.py @@ -3,23 +3,15 @@ # 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 Flask +from flask import Flask, jsonify from flask_cors import CORS, cross_origin from flask_restful import Resource, Api import logging from moon_interface import __version__ from moon_interface.api.generic import Status, Logs, API -from moon_interface.api.models import Models -from moon_interface.api.policies import Policies -from moon_interface.api.pdp import PDP -from moon_interface.api.meta_rules import MetaRules -from moon_interface.api.meta_data import SubjectCategories, ObjectCategories, ActionCategories -from moon_interface.api.perimeter import Subjects, Objects, Actions -from moon_interface.api.data import SubjectData, ObjectData, ActionData -from moon_interface.api.assignments import SubjectAssignments, ObjectAssignments, ActionAssignments -from moon_interface.api.rules import Rules from moon_interface.api.authz import Authz -from moon_utilities import exceptions +from moon_interface.authz_requests import CACHE +from moon_utilities import configuration, exceptions logger = logging.getLogger("moon.interface.http") @@ -68,13 +60,7 @@ class Server: raise NotImplementedError() __API__ = ( - Status, Logs, API, - MetaRules, SubjectCategories, ObjectCategories, ActionCategories, - Subjects, Objects, Actions, - SubjectAssignments, ObjectAssignments, ActionAssignments, - SubjectData, ObjectData, ActionData, - Rules, Authz, - Models, Policies, PDP + Status, Logs, API ) @@ -106,24 +92,28 @@ class HTTPServer(Server): def __init__(self, host="localhost", port=80, **kwargs): super(HTTPServer, self).__init__(host=host, port=port, **kwargs) self.app = Flask(__name__) + self.port = port + conf = configuration.get_configuration("components/manager") + self.manager_hostname = conf["components/manager"].get("hostname", "manager") + self.manager_port = conf["components/manager"].get("port", 80) #Todo : specify only few urls instead of * CORS(self.app) self.api = Api(self.app) self.__set_route() - # self.__hook_errors() + self.__hook_errors() - @self.app.errorhandler(exceptions.AuthException) - def _auth_exception(error): - return {"error": "Unauthorized"}, 401 + # @self.app.errorhandler(exceptions.AuthException) + # def _auth_exception(error): + # return {"error": "Unauthorized"}, 401 def __hook_errors(self): - # FIXME (dthom): it doesn't work + def get_404_json(e): - return {"error": "Error", "code": 404, "description": e} + return jsonify({"result": False, "code": 404, "description": str(e)}), 404 self.app.register_error_handler(404, get_404_json) def get_400_json(e): - return {"error": "Error", "code": 400, "description": e} + return jsonify({"result": False, "code": 400, "description": str(e)}), 400 self.app.register_error_handler(400, lambda e: get_400_json) self.app.register_error_handler(403, exceptions.AuthException) @@ -132,7 +122,15 @@ class HTTPServer(Server): for api in __API__: self.api.add_resource(api, *api.__urls__) + self.api.add_resource(Authz, *Authz.__urls__, + resource_class_kwargs={ + "cache": CACHE, + "interface_name": self.host, + "manager_url": "http://{}:{}".format(self.manager_hostname, self.manager_port), + } + ) def run(self): - self.app.run(debug=True, host=self._host, port=self._port) # nosec + self.app.run(host=self._host, port=self._port) # nosec + # self.app.run(debug=True, host=self._host, port=self._port) # nosec diff --git a/moonv4/moon_interface/moon_interface/server.py b/moonv4/moon_interface/moon_interface/server.py index 711aa00a..7043e2f9 100644 --- a/moonv4/moon_interface/moon_interface/server.py +++ b/moonv4/moon_interface/moon_interface/server.py @@ -14,7 +14,6 @@ def main(): configuration.init_logging() try: conf = configuration.get_configuration("components/interface") - LOG.debug("interface.conf={}".format(conf)) hostname = conf["components/interface"].get("hostname", "interface") port = conf["components/interface"].get("port", 80) bind = conf["components/interface"].get("bind", "127.0.0.1") @@ -25,8 +24,11 @@ def main(): configuration.add_component(uuid="interface", name=hostname, port=port, bind=bind) LOG.info("Starting server with IP {} on port {} bind to {}".format(hostname, port, bind)) server = HTTPServer(host=bind, port=port) - server.run() + # LOG.info("Starting server") + # server = HTTPServer(host="0.0.0.0", port=8081) + return server if __name__ == '__main__': - main() + server = main() + server.run() diff --git a/moonv4/moon_interface/requirements.txt b/moonv4/moon_interface/requirements.txt index ee4b455e..36332aa4 100644 --- a/moonv4/moon_interface/requirements.txt +++ b/moonv4/moon_interface/requirements.txt @@ -1,9 +1,4 @@ -kombu !=4.0.1,!=4.0.0 -oslo.messaging -oslo.config -vine flask flask_restful flask_cors -babel moon_utilities
\ No newline at end of file diff --git a/moonv4/moon_interface/tests/apitests/README.md b/moonv4/moon_interface/tests/apitests/README.md deleted file mode 100644 index ef74a1e3..00000000 --- a/moonv4/moon_interface/tests/apitests/README.md +++ /dev/null @@ -1,33 +0,0 @@ -Test directory -============== - -API tests ---------- -To test all interfaces, you can use : - -```bash -$ cd moonv4/moon_interface/tests/apitests -$ pytest -============================================================================= test session starts ============================================================================== -platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.33, pluggy-0.4.0 -rootdir: /home/vdsq3226/projets/opnfv/moonv4/moon_interface, inifile: -collected 15 items - -test_models.py ..... -test_pdp.py . -test_policies.py ......... - -``` - -Populate default variables for a particular demonstration ---------------------------------------------------------- - -```bash -$ cd moonv4/moon_interface/tests/apitests -$ python3 populate_default_values.py scenario/rbac.py -v -Loading: scenario/rbac.py -2017-03-31 09:57:17,243 WARNING Creating model RBAC -2017-03-31 09:57:17,507 WARNING Creating policy Multi policy example -2017-03-31 09:57:18,690 WARNING Creating PDP pdp1 - -```
\ No newline at end of file diff --git a/moonv4/moon_interface/tests/apitests/plot_json.py b/moonv4/moon_interface/tests/apitests/plot_json.py deleted file mode 100644 index f67f1d27..00000000 --- a/moonv4/moon_interface/tests/apitests/plot_json.py +++ /dev/null @@ -1,852 +0,0 @@ -import os -import argparse -import logging -import json -import glob -import time -import datetime -import itertools -import plotly -from plotly.graph_objs import Scatter, Layout, Bar -import plotly.figure_factory as ff - - -logger = None - - -def init(): - global logger - commands = { - "graph": write_graph, - "digraph": write_distgraph, - "average": write_average_graph, - "latency": write_latency, - "request_average": write_request_average, - "throughput": write_throughput, - "global_throughput": write_global_throughput, - "parallel_throughput": write_parallel_throughput, - } - parser = argparse.ArgumentParser() - parser.add_argument("command", - help="Command to throw ({})".format(", ".join(commands.keys()))) - parser.add_argument("input", nargs="+", help="files to use with the form \"file1.json,file2.json,...\"") - parser.add_argument("--verbose", "-v", action='store_true', help="verbose mode") - parser.add_argument("--debug", "-d", action='store_true', help="debug mode") - parser.add_argument("--write", "-w", help="Write test data to a JSON file", default="/tmp/data.json") - parser.add_argument("--legend", "-l", help="Set the legend (by default get from the file names)") - parser.add_argument("--titles", "-t", - help="Set the general title, x title and y title (ex: Title 1,Title X,Title Y)") - # parser.add_argument("--request-per-second", help="Number of requests per seconds", - # type=int, dest="request_second", default=1) - # parser.add_argument("--limit", help="Limit request to LIMIT", type=int) - parser.add_argument("--write-image", help="Write the graph to file IMAGE", dest="write_image") - parser.add_argument("--write-html", help="Write the graph to HTML file HTML", dest="write_html", default="data.html") - parser.add_argument("--plot-result", - help="Use specific data like Grant or Deny responses " - "('*' for all or 'Grant,Deny' to separate granted and denied responses)", - dest="plot_result", - default="*") - args = parser.parse_args() - - FORMAT = '%(levelname)s %(message)s' - - if args.verbose: - logging.basicConfig( - format=FORMAT, - level=logging.INFO) - elif args.debug: - logging.basicConfig( - format=FORMAT, - level=logging.DEBUG) - else: - logging.basicConfig( - format=FORMAT, - level=logging.WARNING) - - logger = logging.getLogger(__name__) - - # args.input = args.input[0] - result_input = [] - for _input in args.input: - if "*" in _input: - filenames = glob.glob(_input) - filenames.sort() - result_input.append(",".join(filenames)) - else: - result_input.append(_input) - args.input = result_input - - if not args.legend: - _legends = [] - for data in args.input: - for filename in data.split(","): - _legends.append(os.path.basename(filename).replace(".json", "")) - args.legend = ",".join(_legends) - - return args, commands - - -def __get_legends(legend_str, default_length=10): - if "|" in legend_str: - secondary_legend = legend_str.split("|")[1].split(",") - else: - secondary_legend = ["average"] * default_length - _legends = legend_str.split("|")[0].split(",") - return _legends, secondary_legend - - -def get_delta_v1(time_data, result=None): - time_delta = list() - x_data = list() - time_delta_sum1 = 0 - cpt = 0 - for key in time_data: - if not result or 'result' not in time_data[key] or time_data[key]['result'].lower() == result.lower() or result == "*": - time_delta.append(time_data[key]['delta']) - time_delta_sum1 += time_data[key]['delta'] - if 'index' in time_data[key]: - print("in index {}".format(time_data[key]['index'])) - x_data.append(time_data[key]['index']) - else: - x_data.append(cpt) - cpt += 1 - time_delta_average1 = time_delta_sum1 / len(time_data.keys()) - return time_delta, time_delta_average1, x_data - - -def get_delta_v2(time_data, result=None): - time_delta = list() - x_data = list() - time_delta_sum1 = 0 - cpt = 0 - for item in time_data: - if not result or 'result' not in item or item['result'].lower() == result.lower() or result == "*": - time_delta.append(item['delta']) - time_delta_sum1 += item['delta'] - x_data.append(cpt) - cpt += 1 - time_delta_average1 = time_delta_sum1 / len(time_data) - return time_delta, time_delta_average1, x_data - - -def get_delta(time_data, result=None): - if type(time_data) is dict: - return get_delta_v1(time_data, result=result) - if type(time_data) is list: - return get_delta_v2(time_data, result=result) - raise Exception("Time data has not a correct profile") - - -def get_latency_v1(time_data, result=None): - time_delta = list() - time_delta_sum1 = 0 - for key in time_data: - if not result or 'result' not in time_data[key] or time_data[key]['result'].lower() == result.lower() or result == "*": - time_delta.append(1/time_data[key]['delta']) - time_delta_sum1 += time_data[key]['delta'] - logger.debug("Adding {} {}".format(1/time_data[key]['delta'], time_data[key]['delta'])) - time_delta_average1 = time_delta_sum1 / len(time_data.keys()) - return time_delta, 1/time_delta_average1 - - -def get_latency_v2(time_data, result=None): - time_delta = list() - time_delta_sum1 = 0 - time_list = list() - for item in time_data: - if not result or 'result' not in item or item['result'].lower() == result.lower() or result == "*": - time_delta.append(1/item['delta']) - time_delta_sum1 += item['delta'] - time_list.append(item['end']) - time_delta_average1 = time_delta_sum1 / len(time_data) - return time_delta, 1/time_delta_average1, time_list - - -def get_latency(time_data, result=None): - if type(time_data) is dict: - return get_latency_v1(time_data, result=result) - if type(time_data) is list: - return get_latency_v2(time_data, result=result) - raise Exception("Time data has not a correct profile") - - -def get_request_per_second_v1(time_data): - result = {} - _min = None - _max = 0 - for key in time_data: - start = str(time_data[key]['start']).split(".")[0] - end = str(time_data[key]['end']).split(".")[0] - middle = str(int((int(end) + int(start)) / 2)) - middle = end - if not _min: - _min = int(middle) - if int(middle) < _min: - _min = int(middle) - if int(middle) > _max: - _max = int(middle) - if middle not in result: - result[middle] = 1 - else: - result[middle] += 1 - for cpt in range(_min+1, _max): - if str(cpt) not in result: - result[str(cpt)] = 0 - # result[str(cpt)] = (result[str(cpt - 1)] + result[str(cpt)]) / 2 - # result[str(cpt - 1)] = result[str(cpt)] - return result - - -def get_request_per_second_v2(time_data): - result = {} - _min = None - _max = 0 - for item in time_data: - start = str(item['start']).split(".")[0] - end = str(item['end']).split(".")[0] - middle = str(int((int(end) + int(start)) / 2)) - middle = end - if not _min: - _min = int(middle) - if int(middle) < _min: - _min = int(middle) - if int(middle) > _max: - _max = int(middle) - if middle not in result: - result[middle] = 1 - else: - result[middle] += 1 - for cpt in range(_min+1, _max): - if str(cpt) not in result: - result[str(cpt)] = 0 - # result[str(cpt)] = (result[str(cpt - 1)] + result[str(cpt)]) / 2 - # result[str(cpt - 1)] = result[str(cpt)] - return result - - -def get_request_per_second(time_data): - if type(time_data) is dict: - return get_request_per_second_v1(time_data) - if type(time_data) is list: - return get_request_per_second_v2(time_data) - raise Exception("Time data has not a correct profile") - - -def write_graph(legend=None, input=None, image_file=None, html_file=None, plot_result="", title=None): - logger.info("Writing graph") - cpt_max = 0 - logger.debug("legend={}".format(legend)) - for data in input: - cpt_max += len(data.split(",")) - legends, secondary_legend = __get_legends(legend, cpt_max) - logger.debug("legends={}".format(legends)) - result_data = [] - cpt_input = 0 - for data in input: - for _input in data.split(","): - try: - current_legend = legends.pop(0) - except IndexError: - current_legend = "" - time_data = json.load(open(_input)) - time_delta, time_delta_average2, x_data = get_delta(time_data) - for item in time_data: - if type(time_data) is dict: - time_delta.append(time_data[item]['delta']) - else: - time_delta.append(item['delta']) - data = Scatter( - x=x_data, - y=time_delta, - name=current_legend, - line=dict( - color="rgb({},{},{})".format(0, cpt_input * 255 / cpt_max, cpt_input * 255 / cpt_max), - # shape='spline' - ) - ) - result_data.append(data) - data_a = Scatter( - x=list(range(len(time_data))), - y=[time_delta_average2 for x in range(len(time_data))], - name=current_legend + " average", - line=dict( - color="rgb({},{},{})".format(255, cpt_input * 255 / cpt_max, cpt_input * 255 / cpt_max), - # shape='spline' - ) - ) - result_data.append(data_a) - cpt_input += 1 - - if image_file: - plotly.offline.plot( - { - "data": result_data, - "layout": Layout( - title="Request times delta", - xaxis=dict(title='Requests'), - yaxis=dict(title='Request duration'), - ) - }, - filename=html_file, - image="svg", - image_filename=image_file, - image_height=1000, - image_width=1200 - ) - else: - plotly.offline.plot( - { - "data": result_data, - "layout": Layout( - title="Request times delta", - xaxis=dict(title='Requests'), - yaxis=dict(title='Request duration'), - ) - }, - filename=html_file, - ) - return 0 - - -def write_distgraph(legend=None, input=None, image_file=None, html_file=None, plot_result="", title=None): - - logger.info("Writing graph") - _legends, secondary_legend = __get_legends(legend, len(input)) - result_data = [] - legends = [] - - # FIXME: deals with multiple input - input = input[0] - for _input in input.split(","): - logger.info("Analysing input {}".format(_input)) - current_legend = _legends.pop(0) - for result in plot_result.split(","): - time_data2 = json.load(open(_input)) - time_delta2, time_delta_average2, x_data = get_delta(time_data2, result=result) - result_data.append(time_delta2) - if result == "*": - legends.append(current_legend) - else: - legends.append("{} ({})".format(current_legend, result)) - - # Create distplot with custom bin_size - if len(legends) < len(result_data): - for _cpt in range(len(result_data)-len(legends)): - legends.append("NC") - fig = ff.create_distplot(result_data, legends, show_hist=False) - - # Plot! - plotly.offline.plot( - fig, - # image="svg", - # image_filename=image_file, - # image_height=1000, - # image_width=1200, - filename=html_file - ) - return 0 - - -def write_average_graph(legend=None, input=None, image_file=None, html_file=None, plot_result="", title=None): - - logger.info("Writing average graph") - _legends, secondary_legend = __get_legends(legend, len(input)) - all_data = [] - legends = [] - legend_done = False - html_file = "latency_" + html_file - - cpt_input = 0 - cpt_max = len(input) - for data in input: - result_data = [] - for _input in data.split(","): - logger.info("Analysing input {}".format(_input)) - if not legend_done: - current_legend = _legends.pop(0) - for result in plot_result.split(","): - time_data2 = json.load(open(_input)) - time_delta2, time_delta_average2 = get_delta(time_data2, result=result) - result_data.append(time_delta_average2) - if not legend_done and result == "*": - legends.append(current_legend) - elif not legend_done: - legends.append("{} ({})".format(current_legend, result)) - - if not legend_done: - if len(legends) < len(result_data): - for _cpt in range(len(result_data)-len(legends)): - legends.append("NC") - - data = Scatter( - x=legends, - y=result_data, - name=secondary_legend.pop(0), - line=dict( - color="rgb({},{},{})".format(158, cpt_input * 255 / cpt_max, cpt_input * 255 / cpt_max) - ) - ) - all_data.append(data) - legend_done = True - cpt_input += 1 - if image_file: - plotly.offline.plot( - { - "data": all_data, - "layout": Layout( - title="Latency", - xaxis=dict(title='Request per second'), - yaxis=dict(title='Request latency'), - ) - }, - filename=html_file, - image="svg", - image_filename=image_file, - image_height=1000, - image_width=1200 - ) - else: - plotly.offline.plot( - { - "data": all_data, - "layout": Layout( - title="Latency", - xaxis=dict(title='Requests'), - yaxis=dict(title='Request latency'), - ) - }, - filename=html_file, - ) - return 0 - - -def __get_titles(title): - if title: - titles = title.split(",") - try: - title_generic = titles[0] - except IndexError: - title_generic = "" - try: - title_x = titles[1] - except IndexError: - title_x = "" - try: - title_y = titles[2] - except IndexError: - title_y = "" - else: - title_generic = "" - title_x = "" - title_y = "" - return title_generic, title_x, title_y - - -def __get_time_axis(data): - result_data = [] - start_time = None - for item in data: - if not start_time: - start_time = item - item = item - start_time - millis = int(str(item).split('.')[-1][:6]) - t = time.gmtime(int(item)) - result_data.append( - datetime.datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, millis) - ) - return result_data - - -def write_latency(legend=None, input=None, image_file=None, html_file=None, plot_result="", title=None): - - logger.info("Writing latency graph") - _legends, secondary_legend = __get_legends(legend, len(input)) - all_data = [] - legends = [] - legend_done = False - html_file = "latency_" + html_file - title_generic, title_x, title_y = __get_titles(title) - cpt_input = 0 - cpt_max = len(input) - for data in input: - result_data = [] - for _input in data.split(","): - logger.info("Analysing input {}".format(_input)) - if not legend_done: - current_legend = _legends.pop(0) - for result in plot_result.split(","): - time_data2 = json.load(open(_input)) - time_delta2, time_delta_average2, x_data = get_latency(time_data2, result=result) - result_data.append(time_delta_average2) - if not legend_done and result == "*": - legends.append(current_legend) - elif not legend_done: - legends.append("{} ({})".format(current_legend, result)) - - if not legend_done: - if len(legends) < len(result_data): - for _cpt in range(len(result_data)-len(legends)): - legends.append("NC") - - data = Scatter( - x=legends, - y=result_data, - name=secondary_legend.pop(0), - line=dict( - color="rgb({},{},{})".format(158, cpt_input * 255 / cpt_max, cpt_input * 255 / cpt_max) - ) - ) - all_data.append(data) - legend_done = True - cpt_input += 1 - if image_file: - plotly.offline.plot( - { - "data": all_data, - "layout": Layout( - title=title_generic, - xaxis=dict(title=title_x), - yaxis=dict(title=title_y), - ) - }, - filename=html_file, - image="svg", - image_filename=image_file, - image_height=1000, - image_width=1200 - ) - else: - plotly.offline.plot( - { - "data": all_data, - "layout": Layout( - title=title_generic, - xaxis=dict(title=title_x), - yaxis=dict(title=title_y), - font=dict( - size=25 - ) - ) - }, - filename=html_file, - ) - return 0 - - -def write_request_average(legend=None, input=None, image_file=None, html_file=None, plot_result="", title=None): - logger.info("Writing average graph") - _legends, secondary_legend = __get_legends(legend, len(input)) - result_data = [] - html_file = "request_average_" + html_file - - # FIXME: deals with multiple input - input = input[0] - for _input in input.split(","): - logger.info("Analysing input {}".format(_input)) - current_legend = _legends.pop(0) - time_data = json.load(open(_input)) - result = get_request_per_second(time_data) - time_keys = list(result.keys()) - time_keys.sort() - time_value = list(map(lambda x: result[x], time_keys)) - datetime_keys = list() - for _time in time_keys: - t = time.gmtime(int(_time)) - datetime_keys.append(datetime.datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec)) - data = Bar( - x=datetime_keys, - y=time_value, - name=current_legend, - ) - result_data.append(data) - plotly.offline.plot( - { - "data": result_data, - "layout": Layout( - title="Request per second", - xaxis=dict(title='Time'), - yaxis=dict(title='Request number'), - ) - }, - filename=html_file, - ) - - -def write_throughput(legend=None, input=None, image_file=None, html_file=None, plot_result="", title=None): - logger.info("Writing throughput graph") - _legends, secondary_legend = __get_legends(legend, len(input)) - result_data = [] - html_file = "request_throughput_" + html_file - title_generic, title_x, title_y = __get_titles(title) - - cpt_input = 0 - cpt_request = 0 - cpt_max = 0 - average_data_x = [] - average_data_y = [] - for _i in input: - cpt_max += len(_i.split(",")) - - for data in input: - for _input in data.split(","): - logger.info("Analysing input {}".format(_input)) - current_legend = _legends.pop(0) - time_data = json.load(open(_input)) - result = get_request_per_second(time_data) - time_keys = list(result.keys()) - time_keys.sort() - time_value = list(map(lambda x: result[x], time_keys)) - index_list = list(map(lambda x: cpt_request + x, range(len(time_keys)))) - cpt_request += len(index_list) - import itertools - average_data_y.extend( - [list(itertools.accumulate(result.values()))[-1]/len(result.values())]*len(result.values()) - ) - average_data_x.extend(index_list) - data = Scatter( - x=index_list, - y=time_value, - name=current_legend, - line=dict( - color="rgb({},{},{})".format(0, cpt_input*255/cpt_max, cpt_input*255/cpt_max) - ), - mode="lines+markers" - ) - result_data.append(data) - cpt_input += 1 - data = Scatter( - x=average_data_x, - y=average_data_y, - name="Average", - line=dict( - color="rgb({},{},{})".format(255, 0, 0) - ), - mode="lines" - ) - logger.debug(average_data_x) - logger.debug(average_data_y) - result_data.append(data) - plotly.offline.plot( - { - "data": result_data, - "layout": Layout( - title=title_generic, - xaxis=dict(title=title_x), - yaxis=dict(title=title_y), - font=dict( - size=15 - ) - ) - }, - filename=html_file, - ) - - -def write_global_throughput(legend=None, input=None, image_file=None, html_file=None, plot_result="", title=None): - logger.info("Writing global throughput graph") - _legends, secondary_legend = __get_legends(legend, len(input)) - result_data = [] - # html_file = "request_throughput_" + html_file - title_generic, title_x, title_y = __get_titles(title) - - cpt_input = 0 - cpt_global = 0 - cpt_max = 0 - average_data_x = [] - final_time_data = None - average_data_y = [] - continuous_data_x = [] - continuous_data_y = [] - for _i in input: - cpt_max += len(_i.split(",")) - - for data in input: - for _input in data.split(","): - logger.info("Analysing input {}".format(_input)) - # current_legend = _legends.pop(0) - _time_data = json.load(open(_input)) - result, average, time_data = get_latency(_time_data, plot_result) - if not final_time_data: - final_time_data = time_data - continuous_data_y.extend(result) - cpt_global += len(result) - _cpt = 0 - for item in result: - if len(average_data_y) <= _cpt: - average_data_y.append([item, ]) - average_data_x.append(_cpt) - else: - _list = average_data_y[_cpt] - _list.append(item) - average_data_y[_cpt] = _list - _cpt += 1 - # time_keys = list(map(lambda x: x['url'], result)) - # time_keys.sort() - # time_value = list(map(lambda x: result[x], time_keys)) - # index_list = list(map(lambda x: cpt_request + x, range(len(time_keys)))) - # cpt_request += len(index_list) - # average_data_y.extend( - # [list(itertools.accumulate(result.values()))[-1]/len(result.values())]*len(result.values()) - # ) - # average_data_x.extend(index_list) - cpt_input += 1 - data_continuous = Scatter( - x=list(range(len(continuous_data_y))), - y=continuous_data_y, - name="continuous_data_y", - line=dict( - color="rgb({},{},{})".format(0, 0, 255) - ), - mode="lines" - ) - for index, item in enumerate(average_data_y): - av = list(itertools.accumulate(item))[-1]/len(item) - average_data_y[index] = av - - average_data = [] - for cpt in range(len(time_data)): - average_data.append([average_data_y[cpt], time_data[cpt]]) - - sorted(average_data, key=lambda x: x[1]) - - average_data_x = [] - start_time = None - for item in map(lambda x: x[1], average_data): - if not start_time: - start_time = item - item = item - start_time - millis = int(str(item).split('.')[-1][:6]) - t = time.gmtime(int(item)) - average_data_x.append( - datetime.datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, millis) - ) - - data_average = Scatter( - x=average_data_x, - y=list(map(lambda x: x[0], average_data)), - name="Average", - line=dict( - color="rgb({},{},{})".format(0, 0, 255) - ), - mode="lines" - ) - plotly.offline.plot( - { - "data": [data_average, ], - "layout": Layout( - title=title_generic, - xaxis=dict(title=title_x), - yaxis=dict(title=title_y), - font=dict( - size=15 - ) - ) - }, - filename="average_throughput_" + html_file, - ) - plotly.offline.plot( - { - "data": [data_continuous, ], - "layout": Layout( - title=title_generic, - xaxis=dict(title=title_x), - yaxis=dict(title=title_y), - font=dict( - size=15 - ) - ) - }, - filename="continuous_throughput_" + html_file, - ) - - -def write_parallel_throughput(legend=None, input=None, image_file=None, html_file=None, plot_result="", title=None): - logger.info("Writing global throughput graph") - _legends, secondary_legend = __get_legends(legend, len(input)) - result_data = [] - title_generic, title_x, title_y = __get_titles(title) - - cpt_input = 0 - cpt_global = 0 - cpt_max = 0 - overhead_data = [] - MAX = 60 - for _i in input: - cpt_max += len(_i.split(",")) - for data in input: - for _input in data.split(","): - logger.info("Analysing input {}".format(_input)) - current_legend = _legends.pop(0) - _time_data = json.load(open(_input)) - result, average, time_data = get_latency(_time_data, plot_result) - result = result[:MAX] - cpt_global += len(result) - if not overhead_data: - for _data in result: - overhead_data.append(list()) - for _index, _data in enumerate(result): - _item = overhead_data[_index] - _item.append(_data) - overhead_data[_index] = _item - - data_continuous = Scatter( - x=__get_time_axis(time_data), - # x=list(range(len(result))), - y=result, - name=current_legend, - line=dict( - color="rgb({},{},{})".format(0, cpt_input * 255 / cpt_max, cpt_input * 255 / cpt_max) - ), - mode="lines" - ) - cpt_input += 1 - result_data.append(data_continuous) - - for _index, _data in enumerate(overhead_data): - if len(_data) == 2: - _item = overhead_data[_index] - overhead_data[_index] = 1-_item[1]/_item[0] - data_overhead = Scatter( - x=__get_time_axis(time_data), - # x=list(range(len(result))), - y=overhead_data, - name="Overhead", - line=dict( - color="rgb({},{},{})".format(255, 0, 0) - ), - mode="lines" - ) - # result_data.append(data_overhead) - plotly.offline.plot( - { - "data": result_data, - "layout": Layout( - title=title_generic, - xaxis=dict(title=title_x), - yaxis=dict(title=title_y), - font=dict( - size=20 - ) - ) - }, - filename="parallel_throughput_" + html_file, - ) - - -def main(): - args, commands = init() - if args.command in commands: - commands[args.command]( - legend=args.legend, - input=args.input, - image_file=args.write_image, - html_file=args.write_html, - plot_result=args.plot_result, - title=args.titles - ) - else: - logger.error("Unkwnon command: {}".format(args.command)) - - -if __name__ == "__main__": - main() diff --git a/moonv4/moon_interface/tests/apitests/scenario/delegation.py b/moonv4/moon_interface/tests/apitests/scenario/delegation.py deleted file mode 100644 index 839e74ce..00000000 --- a/moonv4/moon_interface/tests/apitests/scenario/delegation.py +++ /dev/null @@ -1,40 +0,0 @@ - -pdp_name = "pdp1" -policy_name = "Delegation policy example" -model_name = "Delegation" - -subjects = {"user0": "", } -objects = {"user1": "", } -actions = {"delegate": ""} - -subject_categories = {"subjectid": "", } -object_categories = {"delegated": "", } -action_categories = {"delegation-action": "", } - -subject_data = {"subjectid": {"user0": ""}} -object_data = {"delegated": {"user1": ""}} -action_data = {"delegation-action": {"delegate": ""}} - -subject_assignments = {"user0": {"subjectid": "user0"}} -object_assignments = {"user1": {"delegated": "user1"}} -action_assignments = {"delegate": {"delegation-action": "delegate"}} - -meta_rule = { - "session": {"id": "", "value": ("subjectid", "delegated", "delegation-action")}, -} - -rules = { - "session": ( - { - "rule": ("user0", "user1", "delegate"), - "instructions": ( - { - "update": {"request:subject": "user1"} # update the current user with "user1" - }, - {"chain": {"security_pipeline": "rbac"}} - ) - }, - ) -} - - diff --git a/moonv4/moon_interface/tests/apitests/scenario/rbac_large.py b/moonv4/moon_interface/tests/apitests/scenario/rbac_large.py deleted file mode 100644 index ef5dd9b2..00000000 --- a/moonv4/moon_interface/tests/apitests/scenario/rbac_large.py +++ /dev/null @@ -1,233 +0,0 @@ - -pdp_name = "pdp1" -policy_name = "RBAC policy example" -model_name = "RBAC" -policy_genre = "authz" - -subjects = { - "user0": "", - "user1": "", - "user2": "", - "user3": "", - "user4": "", - "user5": "", - "user6": "", - "user7": "", - "user8": "", - "user9": "", -} -objects = { - "vm0": "", - "vm1": "", - "vm2": "", - "vm3": "", - "vm4": "", - "vm5": "", - "vm6": "", - "vm7": "", - "vm8": "", - "vm9": "", -} -actions = { - "start": "", - "stop": "", - "pause": "", - "unpause": "", - "destroy": "", -} - -subject_categories = {"role": "", } -object_categories = {"id": "", } -action_categories = {"action-type": "", } - -subject_data = {"role": { - "admin": "", - "employee": "", - "dev1": "", - "dev2": "", - "*": "" -}} -object_data = {"id": { - "vm0": "", - "vm1": "", - "vm2": "", - "vm3": "", - "vm4": "", - "vm5": "", - "vm6": "", - "vm7": "", - "vm8": "", - "vm9": "", - "*": "" -}} -action_data = {"action-type": { - "vm-read": "", - "vm-write": "", - "*": "" -}} - -subject_assignments = { - "user0": ({"role": "employee"}, {"role": "*"}), - "user1": ({"role": "employee"}, {"role": "*"}), - "user2": ({"role": "dev1"}, {"role": "*"}), - "user3": ({"role": "dev1"}, {"role": "*"}), - "user4": ({"role": "dev1"}, {"role": "*"}), - "user5": ({"role": "dev1"}, {"role": "*"}), - "user6": ({"role": "dev2"}, {"role": "*"}), - "user7": ({"role": "dev2"}, {"role": "*"}), - "user8": ({"role": "dev2"}, {"role": "*"}), - "user9": ({"role": "dev2"}, {"role": "*"}), -} -object_assignments = { - "vm0": ({"id": "vm0"}, {"id": "*"}), - "vm1": ({"id": "vm1"}, {"id": "*"}), - "vm2": ({"id": "vm2"}, {"id": "*"}), - "vm3": ({"id": "vm3"}, {"id": "*"}), - "vm4": ({"id": "vm4"}, {"id": "*"}), - "vm5": ({"id": "vm5"}, {"id": "*"}), - "vm6": ({"id": "vm6"}, {"id": "*"}), - "vm7": ({"id": "vm7"}, {"id": "*"}), - "vm8": ({"id": "vm8"}, {"id": "*"}), - "vm9": ({"id": "vm9"}, {"id": "*"}), -} -action_assignments = { - "start": ({"action-type": "vm-write"}, {"action-type": "*"}), - "stop": ({"action-type": "vm-write"}, {"action-type": "*"}), - "pause": ({"action-type": "vm-read"}, {"action-type": "*"}), - "unpause": ({"action-type": "vm-read"}, {"action-type": "*"}), - "destroy": ({"action-type": "vm-write"}, {"action-type": "*"}), -} - -meta_rule = { - "rbac": {"id": "", "value": ("role", "id", "action-type")}, -} - -rules = { - "rbac": ( - { - "rule": ("admin", "vm0", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("admin", "vm0", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - # Rules for grant all employee to do read actions to all VM except vm0 - { - "rule": ("employee", "vm1", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("employee", "vm2", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("employee", "vm3", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("employee", "vm4", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("employee", "vm5", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("employee", "vm6", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("employee", "vm7", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("employee", "vm8", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("employee", "vm9", "vm-read"), - "instructions": ( - {"decision": "grant"}, - ) - }, - # Rules for grant all dev1 to do read actions to some VM - { - "rule": ("dev1", "vm1", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("dev1", "vm2", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("dev1", "vm3", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("dev1", "vm4", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - # Rules for grant all dev2 to do read actions to some VM - { - "rule": ("dev2", "vm5", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("dev2", "vm6", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("dev2", "vm7", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("dev2", "vm8", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - { - "rule": ("dev2", "vm9", "vm-write"), - "instructions": ( - {"decision": "grant"}, - ) - }, - ) -} - - diff --git a/moonv4/moon_interface/tests/apitests/scenario/rbac_mls.py b/moonv4/moon_interface/tests/apitests/scenario/rbac_mls.py deleted file mode 100644 index 8a5362ea..00000000 --- a/moonv4/moon_interface/tests/apitests/scenario/rbac_mls.py +++ /dev/null @@ -1,50 +0,0 @@ - -pdp_name = "pdp1" -policy_name = "Multi policy example" -model_name = "RBAC" - -subjects = {"user0": "", "user1": "", "user2": "", } -objects = {"vm0": "", "vm1": "", } -actions = {"start": "", "stop": ""} - -subject_categories = {"role": "", "subject-security-level": "", } -object_categories = {"id": "", "object-security-level": "", } -action_categories = {"action-type": "", } - -subject_data = { - "role": {"admin": "", "employee": ""}, - "subject-security-level": {"low": "", "medium": "", "high": ""}, -} -object_data = { - "id": {"vm1": "", "vm2": ""}, - "object-security-level": {"low": "", "medium": "", "high": ""}, -} -action_data = {"action-type": {"vm-action": "", "storage-action": "", }} - -subject_assignments = { - "user0": {"role": "admin", "subject-security-level": "high"}, - "user1": {"role": "employee", "subject-security-level": "medium"}, -} -object_assignments = { - "vm0": {"id": "vm1", "object-security-level": "medium"}, - "vm1": {"id": "vm2", "object-security-level": "low"}, -} -action_assignments = { - "start": {"action-type": "vm-action"}, - "stop": {"action-type": "vm-action"} -} - -meta_rule = { - "rbac": {"id": "", "value": ("role", "id", "action-type")}, - "mls": {"id": "", "value": ("subject-security-level", "object-security-level", "action-type")}, -} - -rules = { - "rbac": ( - ("admin", "vm1", "vm-action"), - ), - "mls": ( - ("high", "medium", "vm-action"), - ("medium", "low", "vm-action"), - ) -} diff --git a/moonv4/moon_interface/tests/apitests/scenario/session.py b/moonv4/moon_interface/tests/apitests/scenario/session.py deleted file mode 100644 index 97d7aec3..00000000 --- a/moonv4/moon_interface/tests/apitests/scenario/session.py +++ /dev/null @@ -1,60 +0,0 @@ - -pdp_name = "pdp1" -policy_name = "Session policy example" -model_name = "Session" -policy_genre = "session" - -subjects = {"user0": "", "user1": "", } -objects = {"admin": "", "employee": "", } -actions = {"activate": "", "deactivate": ""} - -subject_categories = {"subjectid": "", } -object_categories = {"role": "", } -action_categories = {"session-action": "", } - -subject_data = {"subjectid": {"user0": "", "user1": ""}} -object_data = {"role": {"admin": "", "employee": "", "*": ""}} -action_data = {"session-action": {"activate": "", "deactivate": "", "*": ""}} - -subject_assignments = {"user0": ({"subjectid": "user0"}, ), "user1": ({"subjectid": "user1"}, ), } -object_assignments = {"admin": ({"role": "admin"}, {"role": "*"}), - "employee": ({"role": "employee"}, {"role": "employee"}) - } -action_assignments = {"activate": ({"session-action": "activate"}, {"session-action": "*"}, ), - "deactivate": ({"session-action": "deactivate"}, {"session-action": "*"}, ) - } - -meta_rule = { - "session": {"id": "", "value": ("subjectid", "role", "session-action")}, -} - -rules = { - "session": ( - { - "rule": ("user0", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user1", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "delete", - "target": "rbac:role:employee" # delete the role employee from the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - ) -} - - diff --git a/moonv4/moon_interface/tests/apitests/scenario/session_large.py b/moonv4/moon_interface/tests/apitests/scenario/session_large.py deleted file mode 100644 index 5b4a64b6..00000000 --- a/moonv4/moon_interface/tests/apitests/scenario/session_large.py +++ /dev/null @@ -1,389 +0,0 @@ - -pdp_name = "pdp1" -policy_name = "Session policy example" -model_name = "Session" -policy_genre = "session" - -subjects = { - "user0": "", - "user1": "", - "user2": "", - "user3": "", - "user4": "", - "user5": "", - "user6": "", - "user7": "", - "user8": "", - "user9": "", -} -objects = {"admin": "", "employee": "", "dev1": "", "dev2": "", } -actions = {"activate": "", "deactivate": ""} - -subject_categories = {"subjectid": "", } -object_categories = {"role": "", } -action_categories = {"session-action": "", } - -subject_data = {"subjectid": { - "user0": "", - "user1": "", - "user2": "", - "user3": "", - "user4": "", - "user5": "", - "user6": "", - "user7": "", - "user8": "", - "user9": "", -}} -object_data = {"role": { - "admin": "", - "employee": "", - "dev1": "", - "dev2": "", - "*": "" -}} -action_data = {"session-action": {"activate": "", "deactivate": "", "*": ""}} - -subject_assignments = { - "user0": ({"subjectid": "user0"}, ), - "user1": ({"subjectid": "user1"}, ), - "user2": ({"subjectid": "user2"}, ), - "user3": ({"subjectid": "user3"}, ), - "user4": ({"subjectid": "user4"}, ), - "user5": ({"subjectid": "user5"}, ), - "user6": ({"subjectid": "user6"}, ), - "user7": ({"subjectid": "user7"}, ), - "user8": ({"subjectid": "user8"}, ), - "user9": ({"subjectid": "user9"}, ), -} -object_assignments = {"admin": ({"role": "admin"}, {"role": "*"}), - "employee": ({"role": "employee"}, {"role": "*"}), - "dev1": ({"role": "employee"}, {"role": "dev1"}, {"role": "*"}), - "dev2": ({"role": "employee"}, {"role": "dev2"}, {"role": "*"}), - } -action_assignments = {"activate": ({"session-action": "activate"}, {"session-action": "*"}, ), - "deactivate": ({"session-action": "deactivate"}, {"session-action": "*"}, ) - } - -meta_rule = { - "session": {"id": "", "value": ("subjectid", "role", "session-action")}, -} - -rules = { - "session": ( - { - "rule": ("user0", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user1", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "delete", - "target": "rbac:role:employee" # delete the role employee from the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user2", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user2", "dev1", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user2", "dev2", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user3", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user3", "dev1", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user3", "dev2", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user4", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user4", "dev1", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user4", "dev2", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user5", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user5", "dev1", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user5", "dev2", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user6", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user6", "dev1", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user6", "dev2", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user7", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user7", "dev1", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user7", "dev2", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user8", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user8", "dev1", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user8", "dev2", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user9", "employee", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user9", "dev1", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - { - "rule": ("user9", "dev2", "*"), - "instructions": ( - { - "update": { - "operation": "add", - "target": "rbac:role:admin" # add the role admin to the current user - } - }, - {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac - ) - }, - ) -} - - diff --git a/moonv4/moon_interface/tests/apitests/set_authz.py b/moonv4/moon_interface/tests/apitests/set_authz.py deleted file mode 100644 index 270c9de2..00000000 --- a/moonv4/moon_interface/tests/apitests/set_authz.py +++ /dev/null @@ -1,388 +0,0 @@ -import sys -import argparse -import logging -import copy -import threading -from importlib.machinery import SourceFileLoader -import itertools -import requests -import time -import json -import random -import plotly -from plotly.graph_objs import Scatter, Layout -import plotly.figure_factory as ff -from uuid import uuid4 -from utils.pdp import check_pdp - - -logger = None -HOST = None -PORT = None -HOST_AUTHZ = None -PORT_AUTHZ = None - -lock = threading.Lock() - - -def init(): - global logger, HOST, PORT, HOST_AUTHZ, PORT_AUTHZ - parser = argparse.ArgumentParser() - parser.add_argument('filename', help='scenario filename', nargs=1) - parser.add_argument("--verbose", "-v", action='store_true', help="verbose mode") - parser.add_argument("--debug", action='store_true', help="debug mode") - parser.add_argument("--dry-run", "-n", action='store_true', help="Dry run", dest="dry_run") - parser.add_argument("--host", - help="Set the name of the host to test (default: 172.18.0.11).", - default="172.18.0.11") - parser.add_argument("--host-authz", - help="Set the name of the host to test authorization (default: 172.18.0.11).", - default="172.18.0.11", - dest="host_authz") - parser.add_argument("--port", "-p", - help="Set the port of the host to test (default: 38001).", - default="38001") - parser.add_argument("--port-authz", - help="Set the port of the host to test authorization (default: 38001).", - default="38001", - dest="port_authz") - parser.add_argument("--test-only", "-t", action='store_true', dest='testonly', help="Do not generate graphs") - parser.add_argument("--stress-test", "-s", action='store_true', dest='stress_test', - help="Execute stressing tests (warning delta measures will be false, implies -t)") - parser.add_argument("--write", "-w", help="Write test data to a JSON file", default="/tmp/data.json") - parser.add_argument("--pdp", help="Test on pdp PDP") - parser.add_argument("--input", "-i", help="Get data from a JSON input file") - parser.add_argument("--legend", "-l", help="Set the legend (default: 'rbac,rbac+session')", - default='rbac,rbac+session') - # parser.add_argument("--distgraph", "-d", - # help="Show a distribution graph instead of a linear graph", - # action='store_true') - parser.add_argument("--request-per-second", help="Number of requests per seconds", - type=int, dest="request_second", default=1) - parser.add_argument("--limit", help="Limit request to LIMIT", type=int) - parser.add_argument("--write-image", help="Write the graph to file IMAGE", dest="write_image") - parser.add_argument("--write-html", help="Write the graph to HTML file HTML", dest="write_html", default="data.html") - args = parser.parse_args() - - FORMAT = '%(asctime)-15s %(levelname)s %(message)s' - if args.debug: - logging.basicConfig( - format=FORMAT, - level=logging.DEBUG) - elif args.verbose: - logging.basicConfig( - format=FORMAT, - level=logging.INFO) - else: - logging.basicConfig( - format=FORMAT, - level=logging.WARNING) - - logger = logging.getLogger(__name__) - - requests_log = logging.getLogger("requests.packages.urllib3") - requests_log.setLevel(logging.WARNING) - requests_log.propagate = True - - if args.stress_test: - args.testonly = True - - if args.filename: - logger.info("Loading: {}".format(args.filename[0])) - - HOST = args.host - PORT = args.port - HOST_AUTHZ = args.host_authz - PORT_AUTHZ = args.port_authz - return args - - -def get_scenario(args): - m = SourceFileLoader("scenario", args.filename[0]) - return m.load_module() - - -def get_keystone_id(pdp_name): - keystone_project_id = None - logger.error("get_keystone_id url={}".format("http://{}:{}".format(HOST, PORT))) - for pdp_key, pdp_value in check_pdp(moon_url="http://{}:{}".format(HOST, PORT))["pdps"].items(): - logger.debug(pdp_value) - if pdp_name: - if pdp_name != pdp_value["name"]: - continue - if pdp_value['security_pipeline'] and pdp_value["keystone_project_id"]: - logger.debug("Found pdp with keystone_project_id={}".format(pdp_value["keystone_project_id"])) - keystone_project_id = pdp_value["keystone_project_id"] - - if not keystone_project_id: - logger.error("Cannot find PDP with keystone project ID") - sys.exit(1) - return keystone_project_id - - -def _send(url, stress_test=False): - current_request = dict() - current_request['url'] = url - try: - if stress_test: - current_request['start'] = time.time() - # with lock: - res = requests.get(url) - current_request['end'] = time.time() - current_request['delta'] = current_request["end"] - current_request["start"] - else: - with lock: - current_request['start'] = time.time() - res = requests.get(url) - current_request['end'] = time.time() - current_request['delta'] = current_request["end"] - current_request["start"] - except requests.exceptions.ConnectionError: - logger.warning("Unable to connect to server") - return {} - if res and not stress_test: - logger.debug(res.status_code) - logger.debug(res.text) - if res.status_code == 200: - # logger.warning("error code 200 for {}".format(self.url)) - logger.info("\033[1m{}\033[m {}".format(url, res.status_code)) - try: - j = res.json() - except Exception as e: - logger.debug(e) - logger.error(res.text) - else: - if j.get("authz"): - logger.warning("{} \033[32m{}\033[m".format(url, j.get("authz"))) - logger.debug("{}".format(j.get("error", ""))) - current_request['result'] = "Grant" - else: - logger.warning("{} \033[31m{}\033[m".format(url, j.get("authz"))) - logger.debug("{}".format(j.get("error", ""))) - current_request['result'] = "Deny" - return current_request - - -class AsyncGet(threading.Thread): - - def __init__(self, url, semaphore=None, *args, **kwargs): - threading.Thread.__init__(self) - self.url = url - self.kwargs = kwargs - self.sema = semaphore - self.result = dict() - self.uuid = uuid4().hex - self.index = kwargs.get("index", 0) - - def run(self): - self.result = _send(self.url, self.kwargs.get("stress_test", False)) - self.result['index'] = self.index - - -def send_requests(scenario, keystone_project_id, request_second=1, limit=500, - dry_run=None, stress_test=False): - # sema = threading.BoundedSemaphore(value=request_second) - backgrounds = [] - time_data = list() - start_timing = time.time() - request_cpt = 0 - indexes = [] - # rules = itertools.product(scenario.subjects.keys(), scenario.objects.keys(), scenario.actions.keys()) - SUBJECTS = tuple(scenario.subjects.keys()) - OBJECTS = tuple(scenario.objects.keys()) - ACTIONS = tuple(scenario.actions.keys()) - # for rule in rules: - while request_cpt <= limit: - rule = (random.choice(SUBJECTS), random.choice(OBJECTS), random.choice(ACTIONS)) - url = "http://{}:{}/authz/{}/{}".format(HOST_AUTHZ, PORT_AUTHZ, keystone_project_id, "/".join(rule)) - indexes.append(url) - if dry_run: - logger.info(url) - continue - request_cpt += 1 - if stress_test: - time_data.append(copy.deepcopy(_send(url, stress_test=stress_test))) - else: - background = AsyncGet(url, stress_test=stress_test, index=request_cpt) - backgrounds.append(background) - background.start() - # if limit and limit < request_cpt: - # break - if request_cpt % request_second == 0: - if time.time()-start_timing < 1: - while True: - if time.time()-start_timing > 1: - break - start_timing = time.time() - if not stress_test: - for background in backgrounds: - background.join() - if background.result: - time_data.append(copy.deepcopy(background.result)) - return time_data - - -def save_data(filename, time_data): - json.dump(time_data, open(filename, "w")) - - -def get_delta(time_data): - time_delta = list() - time_delta_sum1 = 0 - for item in time_data: - time_delta.append(item['delta']) - time_delta_sum1 += item['delta'] - time_delta_average1 = time_delta_sum1 / len(time_data) - return time_delta, time_delta_average1 - - -def write_graph(time_data, legend=None, input=None, image_file=None, html_file=None): - logger.info("Writing graph") - legends = legend.split(",") - result_data = [] - time_delta, time_delta_average1 = get_delta(time_data) - time_delta_average2 = None - # if input: - # for _input in input.split(","): - # current_legend = legends.pop(0) - # time_data2 = json.load(open(_input)) - # time_delta2, time_delta_average2 = get_delta(time_data2) - # for item in time_data: - # if key in time_data2: - # time_delta2.append(time_data2[key]['delta']) - # else: - # time_delta2.append(None) - # data2 = Scatter( - # x=list(range(len(time_data))), - # y=time_delta2, - # name=current_legend, - # line=dict( - # color='rgb(255, 192, 118)', - # shape='spline') - # ) - # result_data.append(data2) - # data2_a = Scatter( - # x=list(range(len(time_data))), - # y=[time_delta_average2 for x in range(len(time_data))], - # name=current_legend + " average", - # line=dict( - # color='rgb(255, 152, 33)', - # shape='spline') - # ) - # result_data.append(data2_a) - current_legend = legends.pop(0) - data1 = Scatter( - x=list(range(len(time_data))), - y=time_delta, - name=current_legend, - line=dict( - color='rgb(123, 118, 255)') - ) - result_data.append(data1) - data1_a = Scatter( - x=list(range(len(time_data))), - y=[time_delta_average1 for x in range(len(time_data))], - name=current_legend + " average", - line=dict( - color='rgb(28, 20, 255)') - ) - result_data.append(data1_a) - - if image_file: - plotly.offline.plot( - { - "data": result_data, - "layout": Layout( - title="Request times delta", - xaxis=dict(title='Requests'), - yaxis=dict(title='Request duration'), - ) - }, - filename=html_file, - image="svg", - image_filename=image_file, - image_height=1000, - image_width=1200 - ) - else: - plotly.offline.plot( - { - "data": result_data, - "layout": Layout( - title="Request times delta", - xaxis=dict(title='Requests'), - yaxis=dict(title='Request duration'), - ) - }, - filename=html_file, - ) - if time_delta_average2: - logger.info("Average: {} and {}".format(time_delta_average1, time_delta_average2)) - return 1-time_delta_average2/time_delta_average1 - return 0 - - -# def write_distgraph(time_data, legend=None, input=None, image_file=None, html_file=None): -# -# logger.info("Writing graph") -# legends = legend.split(",") -# result_data = [] -# -# time_delta_average2 = None -# -# if input: -# for _input in input.split(","): -# logger.info("Analysing input {}".format(_input)) -# time_data2 = json.load(open(_input)) -# time_delta2, time_delta_average2 = get_delta(time_data2) -# result_data.append(time_delta2) -# -# time_delta, time_delta_average1 = get_delta(time_data) -# result_data.append(time_delta) -# -# # Create distplot with custom bin_size -# if len(legends) < len(result_data): -# for _cpt in range(len(result_data)-len(legends)): -# legends.append("NC") -# fig = ff.create_distplot(result_data, legends, bin_size=.2) -# -# # Plot! -# plotly.offline.plot( -# fig, -# image="svg", -# image_filename=image_file, -# image_height=1000, -# image_width=1200, -# filename=html_file -# ) -# if time_delta_average2: -# logger.info("Average: {} and {}".format(time_delta_average1, time_delta_average2)) -# return 1-time_delta_average2/time_delta_average1 -# return 0 - - -def main(): - args = init() - scenario = get_scenario(args) - keystone_project_id = get_keystone_id(args.pdp) - time_data = send_requests( - scenario, - keystone_project_id, - request_second=args.request_second, - limit=args.limit, - dry_run=args.dry_run, - stress_test=args.stress_test - ) - if not args.dry_run: - save_data(args.write, time_data) - if not args.testonly: - # if args.distgraph: - # overhead = write_distgraph(time_data, legend=args.legend, input=args.input, image_file=args.write_image, - # html_file=args.write_html) - # else: - overhead = write_graph(time_data, legend=args.legend, input=args.input, image_file=args.write_image, - html_file=args.write_html) - logger.info("Overhead: {:.2%}".format(overhead)) - - -if __name__ == "__main__": - main() diff --git a/moonv4/moon_interface/tests/apitests/test_models.py b/moonv4/moon_interface/tests/apitests/test_models.py deleted file mode 100644 index 0da40ce5..00000000 --- a/moonv4/moon_interface/tests/apitests/test_models.py +++ /dev/null @@ -1,37 +0,0 @@ -from utils.models import * - - -def test_models(): - check_model() - model_id = add_model() - check_model(model_id) - delete_model(model_id) - - -def test_meta_data_subject(): - category_id = add_subject_category() - check_subject_category(category_id) - # TODO (asteroide): must implement the deletion of linked data - # delete_subject_category(category_id) - - -def test_meta_data_object(): - category_id = add_object_category() - check_object_category(category_id) - # TODO (asteroide): must implement the deletion of linked data - # delete_object_category(category_id) - - -def test_meta_data_action(): - category_id = add_action_category() - check_action_category(category_id) - # TODO (asteroide): must implement the deletion of linked data - # delete_action_category(category_id) - - -def test_meta_rule(): - meta_rule_id, scat_id, ocat_id, acat_id = add_categories_and_meta_rule() - check_meta_rule(meta_rule_id, scat_id, ocat_id, acat_id) - delete_meta_rule(meta_rule_id) - - diff --git a/moonv4/moon_interface/tests/apitests/test_pdp.py b/moonv4/moon_interface/tests/apitests/test_pdp.py deleted file mode 100644 index 6cd5365b..00000000 --- a/moonv4/moon_interface/tests/apitests/test_pdp.py +++ /dev/null @@ -1,16 +0,0 @@ -from utils.pdp import * - - -def test_pdp(): - projects = get_keystone_projects() - admin_project_id = None - for _project in projects['projects']: - if _project['name'] == "admin": - admin_project_id = _project['id'] - assert admin_project_id - check_pdp() - pdp_id = add_pdp() - check_pdp(pdp_id) - map_to_keystone(pdp_id=pdp_id, keystone_project_id=admin_project_id) - check_pdp(pdp_id=pdp_id, keystone_project_id=admin_project_id) - delete_pdp(pdp_id) diff --git a/moonv4/moon_interface/tests/apitests/test_policies.py b/moonv4/moon_interface/tests/apitests/test_policies.py deleted file mode 100644 index 8f26d72d..00000000 --- a/moonv4/moon_interface/tests/apitests/test_policies.py +++ /dev/null @@ -1,157 +0,0 @@ -from utils.policies import * -from utils.models import * - - -def test_policies(): - check_policy() - policy_id = add_policy() - check_policy(policy_id) - delete_policy(policy_id) - - -def test_subjects(): - policy_id = add_policy() - subject_id = add_subject() - - update_subject(subject_id=subject_id, policy_id=policy_id) - - check_subject(subject_id=subject_id, policy_id=policy_id) - - delete_subject(subject_id, policy_id=policy_id) - delete_subject(subject_id) - - -def test_objects(): - policy_id = add_policy() - object_id = add_object() - - update_object(object_id=object_id, policy_id=policy_id) - check_object(object_id=object_id, policy_id=policy_id) - - delete_object(object_id=object_id, policy_id=policy_id) - delete_object(object_id=object_id) - - -def test_actions(): - policy_id = add_policy() - action_id = add_action() - - update_action(action_id=action_id, policy_id=policy_id) - check_action(action_id=action_id, policy_id=policy_id) - - delete_action(action_id=action_id, policy_id=policy_id) - delete_action(action_id=action_id) - - -def test_subject_data(): - policy_id = add_policy() - - model_id = add_model() - - update_policy(policy_id, model_id) - - meta_rule_id, subject_cat_id, object_cat_id, action_cat_id = add_categories_and_meta_rule() - add_meta_rule_to_model(model_id, meta_rule_id) - - subject_data_id = add_subject_data(policy_id=policy_id, category_id=subject_cat_id) - check_subject_data(policy_id=policy_id, data_id=subject_data_id, category_id=subject_cat_id) - delete_subject_data(policy_id=policy_id, data_id=subject_data_id, category_id=subject_cat_id) - - -def test_object_data(): - policy_id = add_policy() - - model_id = add_model() - - update_policy(policy_id, model_id) - - meta_rule_id, object_cat_id, object_cat_id, action_cat_id = add_categories_and_meta_rule() - add_meta_rule_to_model(model_id, meta_rule_id) - - object_data_id = add_object_data(policy_id=policy_id, category_id=object_cat_id) - check_object_data(policy_id=policy_id, data_id=object_data_id, category_id=object_cat_id) - delete_object_data(policy_id=policy_id, data_id=object_data_id, category_id=object_cat_id) - - -def test_action_data(): - policy_id = add_policy() - - model_id = add_model() - - update_policy(policy_id, model_id) - - meta_rule_id, action_cat_id, action_cat_id, action_cat_id = add_categories_and_meta_rule() - add_meta_rule_to_model(model_id, meta_rule_id) - - action_data_id = add_action_data(policy_id=policy_id, category_id=action_cat_id) - check_action_data(policy_id=policy_id, data_id=action_data_id, category_id=action_cat_id) - delete_action_data(policy_id=policy_id, data_id=action_data_id, category_id=action_cat_id) - - -def test_assignments(): - policy_id = add_policy() - - model_id = add_model() - - update_policy(policy_id, model_id) - - meta_rule_id, subject_cat_id, object_cat_id, action_cat_id = add_categories_and_meta_rule() - add_meta_rule_to_model(model_id, meta_rule_id) - - subject_data_id = add_subject_data(policy_id=policy_id, category_id=subject_cat_id) - subject_data_id_bis = add_subject_data(policy_id=policy_id, category_id=subject_cat_id) - object_data_id = add_object_data(policy_id=policy_id, category_id=object_cat_id) - object_data_id_bis = add_object_data(policy_id=policy_id, category_id=object_cat_id) - action_data_id = add_action_data(policy_id=policy_id, category_id=action_cat_id) - action_data_id_bis = add_action_data(policy_id=policy_id, category_id=action_cat_id) - - subject_id = add_subject(policy_id) - object_id = add_object(policy_id) - action_id = add_action(policy_id) - - add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) - add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id_bis) - add_object_assignments(policy_id, object_id, object_cat_id, object_data_id) - add_object_assignments(policy_id, object_id, object_cat_id, object_data_id_bis) - add_action_assignments(policy_id, action_id, action_cat_id, action_data_id) - add_action_assignments(policy_id, action_id, action_cat_id, action_data_id_bis) - - check_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) - check_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id_bis) - check_object_assignments(policy_id, object_id, object_cat_id, object_data_id) - check_object_assignments(policy_id, object_id, object_cat_id, object_data_id_bis) - check_action_assignments(policy_id, action_id, action_cat_id, action_data_id) - check_action_assignments(policy_id, action_id, action_cat_id, action_data_id_bis) - - delete_subject_assignment(policy_id, subject_id, subject_cat_id, subject_data_id) - delete_object_assignment(policy_id, object_id, object_cat_id, object_data_id) - delete_action_assignment(policy_id, action_id, action_cat_id, action_data_id) - - -def test_rule(): - policy_id = add_policy() - - model_id = add_model() - - update_policy(policy_id, model_id) - - meta_rule_id, subject_cat_id, object_cat_id, action_cat_id = add_categories_and_meta_rule() - add_meta_rule_to_model(model_id, meta_rule_id) - - subject_data_id = add_subject_data(policy_id=policy_id, category_id=subject_cat_id) - object_data_id = add_object_data(policy_id=policy_id, category_id=object_cat_id) - action_data_id = add_action_data(policy_id=policy_id, category_id=action_cat_id) - - subject_id = add_subject(policy_id) - object_id = add_object(policy_id) - action_id = add_action(policy_id) - - add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) - add_object_assignments(policy_id, object_id, object_cat_id, object_data_id) - add_action_assignments(policy_id, action_id, action_cat_id, action_data_id) - - rule_id = add_rule(policy_id, meta_rule_id, [subject_data_id, object_data_id, action_data_id]) - check_rule(policy_id, meta_rule_id, rule_id, [subject_data_id, object_data_id, action_data_id]) - - delete_rule(policy_id, rule_id) - diff --git a/moonv4/moon_consul/moon_consul/api/__init__.py b/moonv4/moon_interface/tests/unit_python/api/__init__.py index e69de29b..e69de29b 100644 --- a/moonv4/moon_consul/moon_consul/api/__init__.py +++ b/moonv4/moon_interface/tests/unit_python/api/__init__.py diff --git a/moonv4/moon_interface/tests/unit_python/api/test_authz.py b/moonv4/moon_interface/tests/unit_python/api/test_authz.py new file mode 100644 index 00000000..a63948f8 --- /dev/null +++ b/moonv4/moon_interface/tests/unit_python/api/test_authz.py @@ -0,0 +1,23 @@ +import json + + +def get_json(data): + return json.loads(data.decode("utf-8")) + + +def test_authz_true(context): + import moon_interface.server + server = moon_interface.server.main() + client = server.app.test_client() + req = client.get("/authz/{p_id}/{s_id}/{o_id}/{a_id}".format( + p_id=context["project_id"], + s_id=context["subject_name"], + o_id=context["object_name"], + a_id=context["action_name"], + )) + assert req.status_code == 200 + data = get_json(req.data) + assert data + assert "result" in data + assert data['result'] == True + diff --git a/moonv4/moon_interface/tests/unit_python/conftest.py b/moonv4/moon_interface/tests/unit_python/conftest.py new file mode 100644 index 00000000..7edcd32d --- /dev/null +++ b/moonv4/moon_interface/tests/unit_python/conftest.py @@ -0,0 +1,678 @@ +import base64 +import json +import os +import pickle +import pytest +import requests_mock +from uuid import uuid4 +from requests.packages.urllib3.response import HTTPResponse + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "orchestrator" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", + "components/orchestrator", + "components/interface", +) + +CONTEXT = { + "project_id": "a64beb1cc224474fb4badd43173e7101", + "subject_name": "testuser", + "object_name": "vm1", + "action_name": "boot", + "request_id": uuid4().hex, + "interface_name": "interface", + "manager_url": "http://{}:{}".format( + CONF["components"]["manager"]["hostname"], + CONF["components"]["manager"]["port"] + ), + "cookie": uuid4().hex + } + + +def get_b64_conf(component=None): + if component == "components": + return base64.b64encode( + json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8') + elif component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif not component: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') + + +MOCK_URLS = [ + ('GET', 'http://consul:8500/v1/kv/components?recurse=true', + {'json': {"Key": key, "Value": get_b64_conf(key)} + for key in COMPONENTS} + ), + ('POST', 'http://keystone:5000/v3/auth/tokens', + {'headers': {'X-Subject-Token': "111111111"}}), + ('DELETE', 'http://keystone:5000/v3/auth/tokens', + {'headers': {'X-Subject-Token': "111111111"}}), + ('POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + {'json': {"users": {}}}), + ('GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + {'json': {"users": {}}}), + ('POST', 'http://keystone:5000/v3/users/', + {'json': {"users": [{ + "id": "1111111111111" + }]}}), +] + + +@pytest.fixture +def db(): + return CONF['database'] + + +@pytest.fixture +def context(): + return CONTEXT + + +def set_env_variables(): + os.environ['UUID'] = "1111111111" + os.environ['TYPE'] = "authz" + os.environ['PORT'] = "8081" + os.environ['PDP_ID'] = "b3d3e18abf3340e8b635fd49e6634ccd" + os.environ['META_RULE_ID'] = "f8f49a779ceb47b3ac810f01ef71b4e0" + os.environ['KEYSTONE_PROJECT_ID'] = CONTEXT['project_id'] + + +def get_pickled_context(): + from moon_utilities.security_functions import Context + from moon_utilities.cache import Cache + CACHE = Cache() + CACHE.update() + _context = Context(context(), CACHE) + _context.increment_index() + _context.pdp_set['effect'] = 'grant' + _context.pdp_set[os.environ['META_RULE_ID']]['effect'] = 'grant' + print(_context.pdp_set) + return pickle.dumps(_context) + + +@pytest.fixture(autouse=True) +def set_consul_and_db(monkeypatch): + """ Modify the response from Requests module + """ + set_env_variables() + with requests_mock.Mocker(real_http=True) as m: + for component in COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': get_b64_conf(component)}] + ) + # for _data in MOCK_URLS: + # m.register_uri(_data[0], _data[1], **_data[2]) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/components?recurse=true', + json=[ + {"Key": key, "Value": get_b64_conf(key)} for key in COMPONENTS + ], + ) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/plugins/authz', + json=[ + { + "LockIndex": 0, + "Key": "plugins/authz", + "Flags": 0, + "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=", + "CreateIndex": 14, + "ModifyIndex": 656 + } + ], + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'DELETE', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users/', + json={"users": [{ + "id": "1111111111111" + }]} + ) + m.register_uri( + 'GET', 'http://orchestrator:8083/pods', + json={ + "pods": { + "721760dd-de5f-11e7-8001-3863bbb766f3": [ + { + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", + "port": 8080, + "genre": "interface", + "name": "interface-paltry", + "keystone_project_id": "a64beb1cc224474fb4badd43173e7101", + "namespace": "moon", + "container": "wukongsun/moon_interface:v4.3" + }, + { + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", + "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "port": 8081, + "genre": "authz", + "name": "authz-economic", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "keystone_project_id": "a64beb1cc224474fb4badd43173e7101", + "namespace": "moon", + "container": "wukongsun/moon_authz:v4.3" + } + ], + "232399a4-de5f-11e7-8001-3863bbb766f3": [ + { + "port": 8080, + "namespace": "moon", + "name": "wrapper-paltry", + "container": "wukongsun/moon_wrapper:v4.3.1" + } + ] + } + } + ) + m.register_uri( + 'GET', 'http://orchestrator:8083/pods/authz-economic', + json={ + "pods": None + } + ) + m.register_uri( + 'GET', 'http://manager:8082/pdp', + json={ + "pdps": { + "b3d3e18abf3340e8b635fd49e6634ccd": { + "description": "test", + "security_pipeline": [ + "f8f49a779ceb47b3ac810f01ef71b4e0" + ], + "name": "pdp_rbac", + "keystone_project_id": "a64beb1cc224474fb4badd43173e7101" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies', + json={ + "policies": { + "f8f49a779ceb47b3ac810f01ef71b4e0": { + "name": "RBAC policy example", + "model_id": "cd923d8633ff4978ab0e99938f5153d6", + "description": "test", + "genre": "authz" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/models', + json={ + "models": { + "cd923d8633ff4978ab0e99938f5153d6": { + "name": "RBAC", + "meta_rules": [ + "f8f49a779ceb47b3ac810f01ef71b4e0" + ], + "description": "test" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/meta_rules', + json={ + "meta_rules": { + "f8f49a779ceb47b3ac810f01ef71b4e0": { + "subject_categories": [ + "14e6ae0ba34d458b876c791b73aa17bd" + ], + "action_categories": [ + "241a2a791554421a91c9f1bc564aa94d" + ], + "description": "", + "name": "rbac", + "object_categories": [ + "6d48500f639d4c2cab2b1f33ef93a1e8" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subjects', + json={ + "subjects": { + "89ba91c18dd54abfbfde7a66936c51a6": { + "description": "test", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ], + "name": "testuser", + "email": "mail", + "id": "89ba91c18dd54abfbfde7a66936c51a6", + "partner_id": "" + }, + "31fd15ad14784a9696fcc887dddbfaf9": { + "description": "test", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ], + "name": "adminuser", + "email": "mail", + "id": "31fd15ad14784a9696fcc887dddbfaf9", + "partner_id": "" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/objects', + json={ + "objects": { + "67b8008a3f8d4f8e847eb628f0f7ca0e": { + "name": "vm1", + "description": "test", + "id": "67b8008a3f8d4f8e847eb628f0f7ca0e", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + }, + "9089b3d2ce5b4e929ffc7e35b55eba1a": { + "name": "vm0", + "description": "test", + "id": "9089b3d2ce5b4e929ffc7e35b55eba1a", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/actions', + json={ + "actions": { + "cdb3df220dc05a6ea3334b994827b068": { + "name": "boot", + "description": "test", + "id": "cdb3df220dc04a6ea3334b994827b068", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + }, + "cdb3df220dc04a6ea3334b994827b068": { + "name": "stop", + "description": "test", + "id": "cdb3df220dc04a6ea3334b994827b068", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + }, + "9f5112afe9b34a6c894eb87246ccb7aa": { + "name": "start", + "description": "test", + "id": "9f5112afe9b34a6c894eb87246ccb7aa", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subject_assignments', + json={ + "subject_assignments": { + "826c1156d0284fc9b4b2ddb279f63c52": { + "category_id": "14e6ae0ba34d458b876c791b73aa17bd", + "assignments": [ + "24ea95256c5f4c888c1bb30a187788df", + "6b227b77184c48b6a5e2f3ed1de0c02a", + "31928b17ec90438ba5a2e50ae7650e63", + "4e60f554dd3147af87595fb6b37dcb13", + "7a5541b63a024fa88170a6b59f99ccd7", + "dd2af27812f742029d289df9687d6126" + ], + "id": "826c1156d0284fc9b4b2ddb279f63c52", + "subject_id": "89ba91c18dd54abfbfde7a66936c51a6", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + }, + "7407ffc1232944279b0cbcb0847c86f7": { + "category_id": "315072d40d774c43a89ff33937ed24eb", + "assignments": [ + "6b227b77184c48b6a5e2f3ed1de0c02a", + "31928b17ec90438ba5a2e50ae7650e63", + "7a5541b63a024fa88170a6b59f99ccd7", + "dd2af27812f742029d289df9687d6126" + ], + "id": "7407ffc1232944279b0cbcb0847c86f7", + "subject_id": "89ba91c18dd54abfbfde7a66936c51a6", + "policy_id": "3e65256389b448cb9897917ea235f0bb" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/object_assignments', + json={ + "object_assignments": { + "201ad05fd3f940948b769ab9214fe295": { + "object_id": "9089b3d2ce5b4e929ffc7e35b55eba1a", + "assignments": [ + "030fbb34002e4236a7b74eeb5fd71e35", + "06bcb8655b9d46a9b90e67ef7c825b50", + "34eb45d7f46d4fb6bc4965349b8e4b83", + "4b7793dbae434c31a77da9d92de9fa8c" + ], + "id": "201ad05fd3f940948b769ab9214fe295", + "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + }, + "90c5e86f8be34c0298fbd1973e4fb043": { + "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e", + "assignments": [ + "a098918e915b4b12bccb89f9a3f3b4e4", + "06bcb8655b9d46a9b90e67ef7c825b50", + "7dc76c6142af47c88b60cc2b0df650ba", + "4b7793dbae434c31a77da9d92de9fa8c" + ], + "id": "90c5e86f8be34c0298fbd1973e4fb043", + "category_id": "33aece52d45b4474a20dc48a76800daf", + "policy_id": "3e65256389b448cb9897917ea235f0bb" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/action_assignments', + json={ + "action_assignments": { + "2128e3ffbd1c4ef5be515d625745c2d4": { + "category_id": "241a2a791554421a91c9f1bc564aa94d", + "action_id": "cdb3df220dc05a6ea3334b994827b068", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "id": "2128e3ffbd1c4ef5be515d625745c2d4", + "assignments": [ + "570c036781e540dc9395b83098c40ba7", + "7fe17d7a2e3542719f8349c3f2273182", + "015ca6f40338422ba3f692260377d638", + "23d44c17bf88480f83e8d57d2aa1ea79" + ] + }, + "cffb98852f3a4110af7a0ddfc4e19201": { + "category_id": "4a2c5abaeaf644fcaf3ca8df64000d53", + "action_id": "cdb3df220dc04a6ea3334b994827b068", + "policy_id": "3e65256389b448cb9897917ea235f0bb", + "id": "cffb98852f3a4110af7a0ddfc4e19201", + "assignments": [ + "570c036781e540dc9395b83098c40ba7", + "7fe17d7a2e3542719f8349c3f2273182", + "015ca6f40338422ba3f692260377d638", + "23d44c17bf88480f83e8d57d2aa1ea79" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subject_assignments/89ba91c18dd54abfbfde7a66936c51a6', + json={ + "subject_assignments": { + "826c1156d0284fc9b4b2ddb279f63c52": { + "category_id": "14e6ae0ba34d458b876c791b73aa17bd", + "assignments": [ + "24ea95256c5f4c888c1bb30a187788df", + "6b227b77184c48b6a5e2f3ed1de0c02a", + "31928b17ec90438ba5a2e50ae7650e63", + "4e60f554dd3147af87595fb6b37dcb13", + "7a5541b63a024fa88170a6b59f99ccd7", + "dd2af27812f742029d289df9687d6126" + ], + "id": "826c1156d0284fc9b4b2ddb279f63c52", + "subject_id": "89ba91c18dd54abfbfde7a66936c51a6", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/object_assignments/67b8008a3f8d4f8e847eb628f0f7ca0e', + json={ + "object_assignments": { + "201ad05fd3f940948b769ab9214fe295": { + "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e", + "assignments": [ + "030fbb34002e4236a7b74eeb5fd71e35", + "06bcb8655b9d46a9b90e67ef7c825b50", + "34eb45d7f46d4fb6bc4965349b8e4b83", + "4b7793dbae434c31a77da9d92de9fa8c" + ], + "id": "201ad05fd3f940948b769ab9214fe295", + "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/action_assignments/cdb3df220dc05a6ea3334b994827b068', + json={ + "action_assignments": { + "2128e3ffbd1c4ef5be515d625745c2d4": { + "category_id": "241a2a791554421a91c9f1bc564aa94d", + "action_id": "cdb3df220dc05a6ea3334b994827b068", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "id": "2128e3ffbd1c4ef5be515d625745c2d4", + "assignments": [ + "570c036781e540dc9395b83098c40ba7", + "7fe17d7a2e3542719f8349c3f2273182", + "015ca6f40338422ba3f692260377d638", + "23d44c17bf88480f83e8d57d2aa1ea79" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/rules', + json={ + "rules": { + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "rules": [ + { + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "rule": [ + "24ea95256c5f4c888c1bb30a187788df", + "030fbb34002e4236a7b74eeb5fd71e35", + "570c036781e540dc9395b83098c40ba7" + ], + "enabled": True, + "id": "0201a2bcf56943c1904dbac016289b71", + "instructions": [ + { + "decision": "grant" + } + ], + "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + }, + { + "policy_id": "ecc2451c494e47b5bca7250cd324a360", + "rule": [ + "54f574cd2043468da5d65e4f6ed6e3c9", + "6559686961a3490a978f246ac9f85fbf", + "ac0d1f600bf447e8bd2f37b7cc47f2dc" + ], + "enabled": True, + "id": "a83fed666af8436192dfd8b3c83a6fde", + "instructions": [ + { + "decision": "grant" + } + ], + "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + } + ] + } + } + ) + m.register_uri( + 'POST', 'http://127.0.0.1:8081/authz', + content=get_pickled_context() + ) + # from moon_db.db_manager import init_engine, run + # engine = init_engine() + # run("upgrade", logging.getLogger("db_manager"), engine) + yield m + # os.unlink(CONF['database']['url'].replace("sqlite:///", "")) + + diff --git a/moonv4/moon_interface/tests/unit_python/requirements.txt b/moonv4/moon_interface/tests/unit_python/requirements.txt new file mode 100644 index 00000000..8bd8449f --- /dev/null +++ b/moonv4/moon_interface/tests/unit_python/requirements.txt @@ -0,0 +1,5 @@ +flask +flask_cors +flask_restful +moon_db +moon_utilities
\ No newline at end of file diff --git a/moonv4/moon_interface/tools/get_keystone_token.py b/moonv4/moon_interface/tools/get_keystone_token.py index 63b0d0b6..a153f4db 100644 --- a/moonv4/moon_interface/tools/get_keystone_token.py +++ b/moonv4/moon_interface/tools/get_keystone_token.py @@ -1,7 +1,6 @@ import requests from oslo_config import cfg from oslo_log import log as logging -from moon_utilities import options # noqa from moon_utilities import exceptions CONF = cfg.CONF diff --git a/moonv4/moon_manager/Dockerfile b/moonv4/moon_manager/Dockerfile index 3e1a65af..873e3aa2 100644 --- a/moonv4/moon_manager/Dockerfile +++ b/moonv4/moon_manager/Dockerfile @@ -6,6 +6,7 @@ RUN pip3 install pip --upgrade ADD . /root WORKDIR /root/ RUN pip3 install -r requirements.txt +#RUN pip3 install /root/dist/* --upgrade RUN pip3 install . CMD ["python3", "-m", "moon_manager"]
\ No newline at end of file diff --git a/moonv4/moon_manager/LICENSE b/moonv4/moon_manager/LICENSE index 4143aac2..d6456956 100644 --- a/moonv4/moon_manager/LICENSE +++ b/moonv4/moon_manager/LICENSE @@ -174,31 +174,29 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/moonv4/moon_manager/moon_manager/__main__.py b/moonv4/moon_manager/moon_manager/__main__.py index 0b264ce6..7d97f003 100644 --- a/moonv4/moon_manager/moon_manager/__main__.py +++ b/moonv4/moon_manager/moon_manager/__main__.py @@ -1,3 +1,4 @@ from moon_manager.server import main -main() +server = main() +server.run() diff --git a/moonv4/moon_manager/moon_manager/api/assignments.py b/moonv4/moon_manager/moon_manager/api/assignments.py index bc585304..3bb6ed29 100644 --- a/moonv4/moon_manager/moon_manager/api/assignments.py +++ b/moonv4/moon_manager/moon_manager/api/assignments.py @@ -60,7 +60,7 @@ class SubjectAssignments(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"subject_assignments": data} @check_auth @@ -97,7 +97,7 @@ class SubjectAssignments(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"subject_assignments": data} @check_auth @@ -122,7 +122,7 @@ class SubjectAssignments(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @@ -164,7 +164,7 @@ class ObjectAssignments(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"object_assignments": data} @check_auth @@ -201,7 +201,7 @@ class ObjectAssignments(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"object_assignments": data} @check_auth @@ -226,7 +226,7 @@ class ObjectAssignments(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @@ -268,7 +268,7 @@ class ActionAssignments(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"action_assignments": data} @check_auth @@ -305,7 +305,7 @@ class ActionAssignments(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"action_assignments": data} @check_auth @@ -330,5 +330,5 @@ class ActionAssignments(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} diff --git a/moonv4/moon_manager/moon_manager/api/containers.py b/moonv4/moon_manager/moon_manager/api/containers.py new file mode 100644 index 00000000..44e7baac --- /dev/null +++ b/moonv4/moon_manager/moon_manager/api/containers.py @@ -0,0 +1,179 @@ +# 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'. +""" +PDP are Policy Decision Point. + +""" + +import copy +from docker import Client +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from moon_utilities.security_functions import check_auth +from moon_db.core import PDPManager +from moon_utilities import configuration, exceptions + +docker_conf = configuration.get_configuration("docker")['docker'] +docker = Client(base_url=docker_conf['url']) + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class Container(Resource): + """ + Endpoint for container requests + """ + + __urls__ = ( + "/containers", + "/containers/", + "/containers/<string:uuid>", + "/containers/<string:uuid>/", + ) + + def __init__(self): + self.containers = {} + self.update() + + def update(self): + for _container in docker.containers(): + if _container['Id'] not in self.containers: + self.containers[_container['Id']] = { + "name": _container["Names"], + "port": _container["Ports"], + } + + @check_auth + def get(self, uuid=None, user_id=None): + """Retrieve all containers + + :param uuid: uuid of the container + :param user_id: user ID who do the request + :return: { + "containers": { + "da0fd80fc1dc146e1b...a2e07d240cde09f0a": { + "name": [ + "/wrapper" + ], + "port": [ + { + "PrivatePort": 8080, + "Type": "tcp", + "IP": "0.0.0.0", + "PublicPort": 8080 + } + ] + }, + } + } + :internal_api: get_containers + """ + # try: + # data = [{"name": item["Names"], "port": item["Ports"], } for item in docker.containers()] + # except Exception as e: + # LOG.error(e, exc_info=True) + # return {"result": False, + # "error": str(e)} + return {"containers": self.containers} + + @check_auth + def post(self, uuid=None, user_id=None): + """Add a new container. + + :param uuid: uuid of the pdp (not used here) + :param user_id: user ID who do the request + :request body: { + "id": "id of the new container", + "name": "name of the new container", + "hostname": "hostname of the new container", + "port": { + "PrivatePort": 8080, + "Type": "tcp", + "IP": "0.0.0.0", + "PublicPort": 8080 + }, + "keystone_project_id": "keystone_project_id1", + "pdp_id": "PDP UUID", + "container_name": "wukongsun/moon_authz:v4.1" + } + :return: { + "containers": { + "da0fd80fc1dc146e1b...a2e07d240cde09f0a": { + "name": [ + "/wrapper" + ], + "port": [ + { + "PrivatePort": 8080, + "Type": "tcp", + "IP": "0.0.0.0", + "PublicPort": 8080 + } + ] + }, + } + } + :internal_api: add_container + """ + try: + self.update() + self.containers[request.json.get('id')] = copy.deepcopy(request.json) + LOG.info("Added a new container {}".format(request.json.get('name'))) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"containers": self.containers} + + @check_auth + def delete(self, uuid=None, user_id=None): + """Delete a pdp + + :param uuid: uuid of the pdp to delete + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_pdp + """ + # try: + # data = PDPManager.delete_pdp(user_id=user_id, pdp_id=uuid) + # except Exception as e: + # LOG.error(e, exc_info=True) + # return {"result": False, + # "error": str(e)} + # return {"result": True} + raise NotImplementedError + + @check_auth + def patch(self, uuid=None, user_id=None): + """Update a pdp + + :param uuid: uuid of the pdp to update + :param user_id: user ID who do the request + :return: { + "pdp_id1": { + "name": "...", + "security_pipeline": [...], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } + } + :internal_api: update_pdp + """ + # try: + # data = PDPManager.update_pdp(user_id=user_id, pdp_id=uuid, value=request.json) + # add_container(uuid=uuid, pipeline=data[uuid]['security_pipeline']) + # except Exception as e: + # LOG.error(e, exc_info=True) + # return {"result": False, + # "error": str(e)} + # return {"pdps": data} + raise NotImplementedError + diff --git a/moonv4/moon_manager/moon_manager/api/data.py b/moonv4/moon_manager/moon_manager/api/data.py index fbf26fd9..85faf415 100644 --- a/moonv4/moon_manager/moon_manager/api/data.py +++ b/moonv4/moon_manager/moon_manager/api/data.py @@ -27,12 +27,14 @@ class SubjectData(Resource): "/policies/<string:uuid>/subject_data", "/policies/<string:uuid>/subject_data/", "/policies/<string:uuid>/subject_data/<string:category_id>", - "/policies/<string:uuid>/subject_data/<string:category_id>/<string:data_id>", + "/policies/<string:uuid>/subject_data/<string:category_id>/" + "<string:data_id>", ) @check_auth def get(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Retrieve all subject categories or a specific one if sid is given for a given policy + """Retrieve all subject categories or a specific one if sid is given + for a given policy :param uuid: uuid of the policy :param category_id: uuid of the subject category @@ -51,12 +53,14 @@ class SubjectData(Resource): :internal_api: get_subject_data """ try: - data = PolicyManager.get_subject_data(user_id=user_id, policy_id=uuid, - category_id=category_id, data_id=data_id) + data = PolicyManager.get_subject_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + data_id=data_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"subject_data": data} @check_auth @@ -84,12 +88,14 @@ class SubjectData(Resource): :internal_api: add_subject_data """ try: - data = PolicyManager.set_subject_data(user_id=user_id, policy_id=uuid, - category_id=category_id, value=request.json) + data = PolicyManager.set_subject_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"subject_data": data} @check_auth @@ -107,12 +113,13 @@ class SubjectData(Resource): :internal_api: delete_subject_data """ try: - data = PolicyManager.delete_subject_data(user_id=user_id, policy_id=uuid, + data = PolicyManager.delete_subject_data(user_id=user_id, + policy_id=uuid, data_id=data_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @@ -125,12 +132,14 @@ class ObjectData(Resource): "/policies/<string:uuid>/object_data", "/policies/<string:uuid>/object_data/", "/policies/<string:uuid>/object_data/<string:category_id>", - "/policies/<string:uuid>/object_data/<string:category_id>/<string:data_id>", + "/policies/<string:uuid>/object_data/<string:category_id>/" + "<string:data_id>", ) @check_auth def get(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Retrieve all object categories or a specific one if sid is given for a given policy + """Retrieve all object categories or a specific one if sid is given + for a given policy :param uuid: uuid of the policy :param category_id: uuid of the object category @@ -149,12 +158,14 @@ class ObjectData(Resource): :internal_api: get_object_data """ try: - data = PolicyManager.get_object_data(user_id=user_id, policy_id=uuid, - category_id=category_id, data_id=data_id) + data = PolicyManager.get_object_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + data_id=data_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"object_data": data} @check_auth @@ -182,12 +193,14 @@ class ObjectData(Resource): :internal_api: add_object_data """ try: - data = PolicyManager.add_object_data(user_id=user_id, policy_id=uuid, - category_id=category_id, value=request.json) + data = PolicyManager.add_object_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"object_data": data} @check_auth @@ -205,12 +218,13 @@ class ObjectData(Resource): :internal_api: delete_object_data """ try: - data = PolicyManager.delete_object_data(user_id=user_id, policy_id=uuid, - data_id=data_id) + data = PolicyManager.delete_object_data(user_id=user_id, + policy_id=uuid, + data_id=data_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @@ -223,12 +237,14 @@ class ActionData(Resource): "/policies/<string:uuid>/action_data", "/policies/<string:uuid>/action_data/", "/policies/<string:uuid>/action_data/<string:category_id>", - "/policies/<string:uuid>/action_data/<string:category_id>/<string:data_id>", + "/policies/<string:uuid>/action_data/<string:category_id>/" + "<string:data_id>", ) @check_auth def get(self, uuid=None, category_id=None, data_id=None, user_id=None): - """Retrieve all action categories or a specific one if sid is given for a given policy + """Retrieve all action categories or a specific one if sid is given + for a given policy :param uuid: uuid of the policy :param category_id: uuid of the action category @@ -247,12 +263,14 @@ class ActionData(Resource): :internal_api: get_action_data """ try: - data = PolicyManager.get_action_data(user_id=user_id, policy_id=uuid, - category_id=category_id, data_id=data_id) + data = PolicyManager.get_action_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + data_id=data_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"action_data": data} @check_auth @@ -280,12 +298,14 @@ class ActionData(Resource): :internal_api: add_action_data """ try: - data = PolicyManager.add_action_data(user_id=user_id, policy_id=uuid, - category_id=category_id, value=request.json) + data = PolicyManager.add_action_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"action_data": data} @check_auth @@ -303,12 +323,13 @@ class ActionData(Resource): :internal_api: delete_action_data """ try: - data = PolicyManager.delete_action_data(user_id=user_id, policy_id=uuid, + data = PolicyManager.delete_action_data(user_id=user_id, + policy_id=uuid, data_id=data_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} diff --git a/moonv4/moon_manager/moon_manager/api/generic.py b/moonv4/moon_manager/moon_manager/api/generic.py index ac4f8f1e..9ff285c8 100644 --- a/moonv4/moon_manager/moon_manager/api/generic.py +++ b/moonv4/moon_manager/moon_manager/api/generic.py @@ -107,18 +107,18 @@ class API(Resource): api_desc = dict() for api_name in api_list: api_desc[api_name] = {} - group_api_obj = eval("moon_interface.api.{}".format(api_name)) + group_api_obj = eval("moon_manager.api.{}".format(api_name)) api_desc[api_name]["description"] = group_api_obj.__doc__ if "__version__" in dir(group_api_obj): api_desc[api_name]["version"] = group_api_obj.__version__ object_list = list(filter(lambda x: "__" not in x, dir(group_api_obj))) - for obj in map(lambda x: eval("moon_interface.api.{}.{}".format(api_name, x)), object_list): + for obj in map(lambda x: eval("moon_manager.api.{}.{}".format(api_name, x)), object_list): if "__urls__" in dir(obj): api_desc[api_name][obj.__name__] = dict() api_desc[api_name][obj.__name__]["urls"] = obj.__urls__ api_desc[api_name][obj.__name__]["methods"] = dict() for _method in filter(lambda x: x in __methods, dir(obj)): - docstring = eval("moon_interface.api.{}.{}.{}.__doc__".format(api_name, obj.__name__, _method)) + docstring = eval("moon_manager.api.{}.{}.{}.__doc__".format(api_name, obj.__name__, _method)) api_desc[api_name][obj.__name__]["methods"][_method] = docstring api_desc[api_name][obj.__name__]["description"] = str(obj.__doc__) if group_id in api_desc: diff --git a/moonv4/moon_manager/moon_manager/api/meta_data.py b/moonv4/moon_manager/moon_manager/api/meta_data.py index 0f9078ed..95cd58cc 100644 --- a/moonv4/moon_manager/moon_manager/api/meta_data.py +++ b/moonv4/moon_manager/moon_manager/api/meta_data.py @@ -44,11 +44,12 @@ class SubjectCategories(Resource): :internal_api: get_subject_categories """ try: - data = ModelManager.get_subject_categories(user_id=user_id, category_id=category_id) + data = ModelManager.get_subject_categories( + user_id=user_id, category_id=category_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"subject_categories": data} @check_auth @@ -70,11 +71,12 @@ class SubjectCategories(Resource): :internal_api: add_subject_category """ try: - data = ModelManager.add_subject_category(user_id=user_id, value=request.json) + data = ModelManager.add_subject_category( + user_id=user_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"subject_categories": data} @check_auth @@ -90,11 +92,12 @@ class SubjectCategories(Resource): :internal_api: delete_subject_category """ try: - data = ModelManager.delete_subject_category(user_id=user_id, category_id=category_id) + data = ModelManager.delete_subject_category( + user_id=user_id, category_id=category_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @@ -124,11 +127,12 @@ class ObjectCategories(Resource): :internal_api: get_object_categories """ try: - data = ModelManager.get_object_categories(user_id=user_id, category_id=category_id) + data = ModelManager.get_object_categories( + user_id=user_id, category_id=category_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"object_categories": data} @check_auth @@ -150,11 +154,12 @@ class ObjectCategories(Resource): :internal_api: add_object_category """ try: - data = ModelManager.add_object_category(user_id=user_id, value=request.json) + data = ModelManager.add_object_category( + user_id=user_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"object_categories": data} @check_auth @@ -170,11 +175,12 @@ class ObjectCategories(Resource): :internal_api: delete_object_category """ try: - data = ModelManager.delete_object_category(user_id=user_id, category_id=category_id) + data = ModelManager.delete_object_category( + user_id=user_id, category_id=category_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @@ -204,11 +210,12 @@ class ActionCategories(Resource): :internal_api: get_action_categories """ try: - data = ModelManager.get_action_categories(user_id=user_id, category_id=category_id) + data = ModelManager.get_action_categories( + user_id=user_id, category_id=category_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"action_categories": data} @check_auth @@ -230,11 +237,12 @@ class ActionCategories(Resource): :internal_api: add_action_category """ try: - data = ModelManager.add_action_category(user_id=user_id, value=request.json) + data = ModelManager.add_action_category( + user_id=user_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"action_categories": data} @check_auth @@ -250,9 +258,10 @@ class ActionCategories(Resource): :internal_api: delete_action_category """ try: - data = ModelManager.delete_action_category(user_id=user_id, category_id=category_id) + data = ModelManager.delete_action_category( + user_id=user_id, category_id=category_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} diff --git a/moonv4/moon_manager/moon_manager/api/meta_rules.py b/moonv4/moon_manager/moon_manager/api/meta_rules.py index dc3ea0db..45e2b5ee 100644 --- a/moonv4/moon_manager/moon_manager/api/meta_rules.py +++ b/moonv4/moon_manager/moon_manager/api/meta_rules.py @@ -39,7 +39,8 @@ class MetaRules(Resource): "meta_rule_id1": { "name": "name of the meta rule", "algorithm": "name of the meta rule algorithm", - "subject_categories": ["subject_category_id1", "subject_category_id2"], + "subject_categories": ["subject_category_id1", + "subject_category_id2"], "object_categories": ["object_category_id1"], "action_categories": ["action_category_id1"] }, @@ -48,11 +49,12 @@ class MetaRules(Resource): :internal_api: get_meta_rules """ try: - data = ModelManager.get_meta_rules(user_id=user_id, meta_rule_id=meta_rule_id) + data = ModelManager.get_meta_rules( + user_id=user_id, meta_rule_id=meta_rule_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"meta_rules": data} @check_auth @@ -63,7 +65,8 @@ class MetaRules(Resource): :param user_id: user ID who do the request :request body: post = { "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], + "subject_categories": ["subject_category_id1", + "subject_category_id2"], "object_categories": ["object_category_id1"], "action_categories": ["action_category_id1"] } @@ -71,7 +74,8 @@ class MetaRules(Resource): "meta_rules": { "meta_rule_id1": { "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], + "subject_categories": ["subject_category_id1", + "subject_category_id2"], "object_categories": ["object_category_id1"], "action_categories": ["action_category_id1"] }, @@ -80,11 +84,12 @@ class MetaRules(Resource): :internal_api: add_meta_rules """ try: - data = ModelManager.add_meta_rule(user_id=user_id, meta_rule_id=None, value=request.json) + data = ModelManager.add_meta_rule( + user_id=user_id, meta_rule_id=None, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"meta_rules": data} @check_auth @@ -95,7 +100,8 @@ class MetaRules(Resource): :param user_id: user ID who do the request :request body: patch = { "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], + "subject_categories": ["subject_category_id1", + "subject_category_id2"], "object_categories": ["object_category_id1"], "action_categories": ["action_category_id1"] } @@ -103,7 +109,8 @@ class MetaRules(Resource): "meta_rules": { "meta_rule_id1": { "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], + "subject_categories": ["subject_category_id1", + "subject_category_id2"], "object_categories": ["object_category_id1"], "action_categories": ["action_category_id1"] }, @@ -112,11 +119,12 @@ class MetaRules(Resource): :internal_api: set_meta_rules """ try: - data = ModelManager.set_meta_rule(user_id=user_id, meta_rule_id=meta_rule_id, value=request.json) + data = ModelManager.set_meta_rule( + user_id=user_id, meta_rule_id=meta_rule_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"meta_rules": data} @check_auth @@ -127,7 +135,8 @@ class MetaRules(Resource): :param user_id: user ID who do the request :request body: delete = { "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], + "subject_categories": ["subject_category_id1", + "subject_category_id2"], "object_categories": ["object_category_id1"], "action_categories": ["action_category_id1"] } @@ -135,7 +144,8 @@ class MetaRules(Resource): "meta_rules": { "meta_rule_id1": { "name": "name of the meta rule", - "subject_categories": ["subject_category_id1", "subject_category_id2"], + "subject_categories": ["subject_category_id1", + "subject_category_id2"], "object_categories": ["object_category_id1"], "action_categories": ["action_category_id1"] }, @@ -144,10 +154,11 @@ class MetaRules(Resource): :internal_api: delete_meta_rules """ try: - data = ModelManager.delete_meta_rule(user_id=user_id, meta_rule_id=meta_rule_id) + data = ModelManager.delete_meta_rule( + user_id=user_id, meta_rule_id=meta_rule_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} diff --git a/moonv4/moon_manager/moon_manager/api/models.py b/moonv4/moon_manager/moon_manager/api/models.py index cec899f5..0a050c7f 100644 --- a/moonv4/moon_manager/moon_manager/api/models.py +++ b/moonv4/moon_manager/moon_manager/api/models.py @@ -49,7 +49,7 @@ class Models(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"models": data} @check_auth @@ -73,11 +73,12 @@ class Models(Resource): :internal_api: add_model """ try: - data = ModelManager.add_model(user_id=user_id, model_id=uuid, value=request.json) + data = ModelManager.add_model( + user_id=user_id, model_id=uuid, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"models": data} @check_auth @@ -97,7 +98,7 @@ class Models(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @check_auth @@ -116,10 +117,11 @@ class Models(Resource): :internal_api: update_model """ try: - data = ModelManager.update_model(user_id=user_id, model_id=uuid, value=request.json) + data = ModelManager.update_model( + user_id=user_id, model_id=uuid, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"models": data} diff --git a/moonv4/moon_manager/moon_manager/api/pdp.py b/moonv4/moon_manager/moon_manager/api/pdp.py index 15f4988f..465f4dba 100644 --- a/moonv4/moon_manager/moon_manager/api/pdp.py +++ b/moonv4/moon_manager/moon_manager/api/pdp.py @@ -9,20 +9,48 @@ PDP are Policy Decision Point. from flask import request from flask_restful import Resource -from oslo_log import log as logging +import logging +import requests +import time from moon_utilities.security_functions import check_auth from moon_db.core import PDPManager +from moon_db.core import PolicyManager +from moon_db.core import ModelManager +from moon_utilities import configuration __version__ = "0.1.0" LOG = logging.getLogger("moon.manager.api." + __name__) -def add_container(uuid, pipeline): - # TODO: to implement - LOG.warning("Add container not implemented!") - LOG.info(uuid) - LOG.info(pipeline) +def delete_pod(uuid): + raise NotImplementedError + + +def add_pod(uuid, data): + if not data.get("keystone_project_id"): + return + LOG.info("Add a new pod {}".format(data)) + if "pdp_id" not in data: + data["pdp_id"] = uuid + data['policies'] = PolicyManager.get_policies(user_id="admin") + data['models'] = ModelManager.get_models(user_id="admin") + conf = configuration.get_configuration("components/orchestrator") + hostname = conf["components/orchestrator"].get("hostname", "orchestrator") + port = conf["components/orchestrator"].get("port", 80) + proto = conf["components/orchestrator"].get("protocol", "http") + while True: + try: + req = requests.post( + "{}://{}:{}/pods".format(proto, hostname, port), + json=data, + headers={"content-type": "application/json"}) + except requests.exceptions.ConnectionError: + LOG.warning("Orchestrator is not ready, standby...") + time.sleep(1) + else: + break + LOG.info(req.text) class PDP(Resource): @@ -58,7 +86,7 @@ class PDP(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"pdps": data} @check_auth @@ -84,11 +112,19 @@ class PDP(Resource): :internal_api: add_pdp """ try: - data = PDPManager.add_pdp(user_id=user_id, pdp_id=None, value=request.json) + data = dict(request.json) + if not data.get("keystone_project_id"): + data["keystone_project_id"] = None + data = PDPManager.add_pdp( + user_id=user_id, pdp_id=None, value=request.json) + uuid = list(data.keys())[0] + LOG.info("data={}".format(data)) + LOG.info("uuid={}".format(uuid)) + add_pod(uuid=uuid, data=data[uuid]) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"pdps": data} @check_auth @@ -105,10 +141,11 @@ class PDP(Resource): """ try: data = PDPManager.delete_pdp(user_id=user_id, pdp_id=uuid) + delete_pod(uuid) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @check_auth @@ -128,11 +165,17 @@ class PDP(Resource): :internal_api: update_pdp """ try: - data = PDPManager.update_pdp(user_id=user_id, pdp_id=uuid, value=request.json) - add_container(uuid=uuid, pipeline=data[uuid]['security_pipeline']) + _data = dict(request.json) + if not _data.get("keystone_project_id"): + _data["keystone_project_id"] = None + data = PDPManager.update_pdp( + user_id=user_id, pdp_id=uuid, value=_data) + LOG.info("data={}".format(data)) + LOG.info("uuid={}".format(uuid)) + add_pod(uuid=uuid, data=data[uuid]) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"pdps": data} diff --git a/moonv4/moon_manager/moon_manager/api/perimeter.py b/moonv4/moon_manager/moon_manager/api/perimeter.py index cc2c0561..2eb80652 100644 --- a/moonv4/moon_manager/moon_manager/api/perimeter.py +++ b/moonv4/moon_manager/moon_manager/api/perimeter.py @@ -3,8 +3,10 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. """ -* Subjects are the source of an action on an object (examples : users, virtual machines) -* Objects are the destination of an action (examples virtual machines, virtual Routers) +* Subjects are the source of an action on an object + (examples : users, virtual machines) +* Objects are the destination of an action + (examples virtual machines, virtual Routers) * Actions are what subject wants to do on an object """ @@ -35,7 +37,8 @@ class Subjects(Resource): @check_auth def get(self, uuid=None, perimeter_id=None, user_id=None): - """Retrieve all subjects or a specific one if perimeter_id is given for a given policy + """Retrieve all subjects or a specific one if perimeter_id is + given for a given policy :param uuid: uuid of the policy :param perimeter_id: uuid of the subject @@ -58,7 +61,7 @@ class Subjects(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"subjects": data} @check_auth @@ -87,18 +90,20 @@ class Subjects(Resource): """ try: if not perimeter_id: - data = PolicyManager.get_subjects(user_id=user_id, policy_id=None) + data = PolicyManager.get_subjects(user_id=user_id, + policy_id=None) if 'name' in request.json: for data_id, data_value in data.items(): if data_value['name'] == request.json['name']: perimeter_id = data_id break - data = PolicyManager.add_subject(user_id=user_id, policy_id=uuid, - perimeter_id=perimeter_id, value=request.json) + data = PolicyManager.add_subject( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"subjects": data} @check_auth @@ -127,18 +132,20 @@ class Subjects(Resource): """ try: if not perimeter_id: - data = PolicyManager.get_subjects(user_id=user_id, policy_id=None) + data = PolicyManager.get_subjects(user_id=user_id, + policy_id=None) if 'name' in request.json: for data_id, data_value in data.items(): if data_value['name'] == request.json['name']: perimeter_id = data_id break - data = PolicyManager.add_subject(user_id=user_id, policy_id=uuid, - perimeter_id=perimeter_id, value=request.json) + data = PolicyManager.add_subject( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"subjects": data} @check_auth @@ -160,11 +167,12 @@ class Subjects(Resource): :internal_api: delete_subject """ try: - data = PolicyManager.delete_subject(user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + data = PolicyManager.delete_subject( + user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @@ -184,7 +192,8 @@ class Objects(Resource): @check_auth def get(self, uuid=None, perimeter_id=None, user_id=None): - """Retrieve all objects or a specific one if perimeter_id is given for a given policy + """Retrieve all objects or a specific one if perimeter_id is + given for a given policy :param uuid: uuid of the policy :param perimeter_id: uuid of the object @@ -206,7 +215,7 @@ class Objects(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"objects": data} @check_auth @@ -235,12 +244,13 @@ class Objects(Resource): if data_value['name'] == request.json['name']: perimeter_id = data_id break - data = PolicyManager.add_object(user_id=user_id, policy_id=uuid, - perimeter_id=perimeter_id, value=request.json) + data = PolicyManager.add_object( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"objects": data} @check_auth @@ -269,12 +279,13 @@ class Objects(Resource): if data_value['name'] == request.json['name']: perimeter_id = data_id break - data = PolicyManager.add_object(user_id=user_id, policy_id=uuid, - perimeter_id=perimeter_id, value=request.json) + data = PolicyManager.add_object( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"objects": data} @check_auth @@ -293,11 +304,12 @@ class Objects(Resource): :internal_api: delete_object """ try: - data = PolicyManager.delete_object(user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + data = PolicyManager.delete_object( + user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @@ -317,7 +329,8 @@ class Actions(Resource): @check_auth def get(self, uuid=None, perimeter_id=None, user_id=None): - """Retrieve all actions or a specific one if perimeter_id is given for a given policy + """Retrieve all actions or a specific one if perimeter_id + is given for a given policy :param uuid: uuid of the policy :param perimeter_id: uuid of the action @@ -331,11 +344,12 @@ class Actions(Resource): :internal_api: get_actions """ try: - data = PolicyManager.get_actions(user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + data = PolicyManager.get_actions( + user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"actions": data} @check_auth @@ -364,12 +378,13 @@ class Actions(Resource): if data_value['name'] == request.json['name']: perimeter_id = data_id break - data = PolicyManager.add_action(user_id=user_id, policy_id=uuid, - perimeter_id=perimeter_id, value=request.json) + data = PolicyManager.add_action( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"actions": data} @check_auth @@ -398,12 +413,13 @@ class Actions(Resource): if data_value['name'] == request.json['name']: perimeter_id = data_id break - data = PolicyManager.add_action(user_id=user_id, policy_id=uuid, - perimeter_id=perimeter_id, value=request.json) + data = PolicyManager.add_action( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"actions": data} @check_auth @@ -422,9 +438,10 @@ class Actions(Resource): :internal_api: delete_action """ try: - data = PolicyManager.delete_action(user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + data = PolicyManager.delete_action( + user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} diff --git a/moonv4/moon_manager/moon_manager/api/policies.py b/moonv4/moon_manager/moon_manager/api/policies.py index 737b988e..8ef11a0d 100644 --- a/moonv4/moon_manager/moon_manager/api/policies.py +++ b/moonv4/moon_manager/moon_manager/api/policies.py @@ -51,7 +51,7 @@ class Policies(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"policies": data} @check_auth @@ -77,11 +77,12 @@ class Policies(Resource): :internal_api: add_policy """ try: - data = PolicyManager.add_policy(user_id=user_id, policy_id=uuid, value=request.json) + data = PolicyManager.add_policy( + user_id=user_id, policy_id=uuid, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"policies": data} @check_auth @@ -101,7 +102,7 @@ class Policies(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} @check_auth @@ -121,10 +122,11 @@ class Policies(Resource): :internal_api: update_policy """ try: - data = PolicyManager.update_policy(user_id=user_id, policy_id=uuid, value=request.json) + data = PolicyManager.update_policy( + user_id=user_id, policy_id=uuid, value=request.json) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"policies": data} diff --git a/moonv4/moon_manager/moon_manager/api/rules.py b/moonv4/moon_manager/moon_manager/api/rules.py index 8b1cf635..f7771f1a 100644 --- a/moonv4/moon_manager/moon_manager/api/rules.py +++ b/moonv4/moon_manager/moon_manager/api/rules.py @@ -9,7 +9,6 @@ Rules (TODO) from flask import request from flask_restful import Resource from oslo_log import log as logging -from moon_utilities.security_functions import call from moon_utilities.security_functions import check_auth from moon_db.core import PolicyManager @@ -40,8 +39,10 @@ class Rules(Resource): "rules": [ "policy_id": "policy_id1", "meta_rule_id": "meta_rule_id1", - "rule_id1": ["subject_data_id1", "object_data_id1", "action_data_id1"], - "rule_id2": ["subject_data_id2", "object_data_id2", "action_data_id2"], + "rule_id1": + ["subject_data_id1", "object_data_id1", "action_data_id1"], + "rule_id2": + ["subject_data_id2", "object_data_id2", "action_data_id2"], ] } :internal_api: get_rules @@ -53,7 +54,7 @@ class Rules(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"rules": data} @check_auth @@ -75,23 +76,31 @@ class Rules(Resource): "rules": [ "meta_rule_id": "meta_rule_id1", "rule_id1": { - "rule": ["subject_data_id1", "object_data_id1", "action_data_id1"], + "rule": ["subject_data_id1", + "object_data_id1", + "action_data_id1"], "instructions": ( - {"decision": "grant"}, # "grant" to immediately exit, - # "continue" to wait for the result of next policy - # "deny" to deny the request + {"decision": "grant"}, + # "grant" to immediately exit, + # "continue" to wait for the result of next policy + # "deny" to deny the request ) } "rule_id2": { - "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], + "rule": ["subject_data_id2", + "object_data_id2", + "action_data_id2"], "instructions": ( { "update": { - "operation": "add", # operations may be "add" or "delete" - "target": "rbac:role:admin" # add the role admin to the current user + "operation": "add", + # operations may be "add" or "delete" + "target": "rbac:role:admin" + # add the role admin to the current user } }, - {"chain": {"name": "rbac"}} # chain with the policy named rbac + {"chain": {"name": "rbac"}} + # chain with the policy named rbac ) } ] @@ -107,7 +116,7 @@ class Rules(Resource): except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"rules": data} @check_auth @@ -121,10 +130,11 @@ class Rules(Resource): :internal_api: delete_rule """ try: - data = PolicyManager.delete_rule(user_id=user_id, policy_id=uuid, rule_id=rule_id) + data = PolicyManager.delete_rule( + user_id=user_id, policy_id=uuid, rule_id=rule_id) except Exception as e: LOG.error(e, exc_info=True) return {"result": False, - "error": str(e)} + "error": str(e)}, 500 return {"result": True} diff --git a/moonv4/moon_manager/moon_manager/http_server.py b/moonv4/moon_manager/moon_manager/http_server.py index bdd429e4..c671ed6f 100644 --- a/moonv4/moon_manager/moon_manager/http_server.py +++ b/moonv4/moon_manager/moon_manager/http_server.py @@ -7,6 +7,8 @@ from flask import Flask, jsonify from flask_cors import CORS, cross_origin from flask_restful import Resource, Api import logging +import sqlalchemy.exc +import time from moon_manager import __version__ from moon_manager.api.generic import Status, Logs, API from moon_manager.api.models import Models @@ -18,9 +20,12 @@ from moon_manager.api.perimeter import Subjects, Objects, Actions from moon_manager.api.data import SubjectData, ObjectData, ActionData from moon_manager.api.assignments import SubjectAssignments, ObjectAssignments, ActionAssignments from moon_manager.api.rules import Rules +# from moon_manager.api.containers import Container from moon_utilities import configuration, exceptions +from moon_db.core import PDPManager -logger = logging.getLogger("moon.manager.http") + +LOG = logging.getLogger("moon.manager.http") class Server: @@ -72,7 +77,7 @@ __API__ = ( Subjects, Objects, Actions, SubjectAssignments, ObjectAssignments, ActionAssignments, SubjectData, ObjectData, ActionData, - Rules, + Rules, #Container, Models, Policies, PDP ) @@ -131,6 +136,22 @@ class HTTPServer(Server): for api in __API__: self.api.add_resource(api, *api.__urls__) + @staticmethod + def __check_if_db_is_up(): + first = True + while True: + try: + PDPManager.get_pdp(user_id="admin", pdp_id=None) + except sqlalchemy.exc.ProgrammingError: + time.sleep(1) + if first: + LOG.warning("Waiting for the database...") + first = False + else: + LOG.warning("Database is up, resuming operations...") + break + def run(self): + self.__check_if_db_is_up() self.app.run(debug=True, host=self._host, port=self._port) # nosec diff --git a/moonv4/moon_manager/moon_manager/server.py b/moonv4/moon_manager/moon_manager/server.py index c317e319..f777fac1 100644 --- a/moonv4/moon_manager/moon_manager/server.py +++ b/moonv4/moon_manager/moon_manager/server.py @@ -30,8 +30,9 @@ def main(): configuration.add_component(uuid="manager", name=hostname, port=port, bind=bind) LOG.info("Starting server with IP {} on port {} bind to {}".format(hostname, port, bind)) server = HTTPServer(host=bind, port=port) - server.run() + return server if __name__ == '__main__': - main() + server = main() + server.run() diff --git a/moonv4/moon_manager/requirements.txt b/moonv4/moon_manager/requirements.txt index e7be3d0e..6b2af70b 100644 --- a/moonv4/moon_manager/requirements.txt +++ b/moonv4/moon_manager/requirements.txt @@ -2,4 +2,5 @@ flask flask_restful flask_cors moon_utilities -moon_db
\ No newline at end of file +moon_db +docker-py diff --git a/moonv4/moon_interface/tests/apitests/utils/__init__.py b/moonv4/moon_manager/tests/unit_python/__init__.py index e69de29b..e69de29b 100644 --- a/moonv4/moon_interface/tests/apitests/utils/__init__.py +++ b/moonv4/moon_manager/tests/unit_python/__init__.py diff --git a/moonv4/moon_router/moon_router/api/__init__.py b/moonv4/moon_manager/tests/unit_python/api/__init__.py index e69de29b..e69de29b 100644 --- a/moonv4/moon_router/moon_router/api/__init__.py +++ b/moonv4/moon_manager/tests/unit_python/api/__init__.py diff --git a/moonv4/moon_manager/tests/unit_python/api/test_perimeter.py b/moonv4/moon_manager/tests/unit_python/api/test_perimeter.py new file mode 100644 index 00000000..18d3837a --- /dev/null +++ b/moonv4/moon_manager/tests/unit_python/api/test_perimeter.py @@ -0,0 +1,59 @@ +# import moon_manager +# import moon_manager.api +import json + + +def get_json(data): + return json.loads(data.decode("utf-8")) + + +def get_subjects(client): + req = client.get("/subjects") + assert req.status_code == 200 + subjects = get_json(req.data) + assert isinstance(subjects, dict) + assert "subjects" in subjects + return subjects + + +def add_subjects(client, name): + data = { + "name": name, + "description": "description of {}".format(name), + "password": "password for {}".format(name), + "email": "{}@moon".format(name) + } + req = client.post("/subjects", data=json.dumps(data), + headers={'Content-Type': 'application/json'}) + assert req.status_code == 200 + subjects = get_json(req.data) + assert isinstance(subjects, dict) + key = list(subjects["subjects"].keys())[0] + value = list(subjects["subjects"].values())[0] + assert "subjects" in subjects + assert key == "1111111111111" + assert value['id'] == "1111111111111" + assert value['name'] == name + assert value["description"] == "description of {}".format(name) + assert value["email"] == "{}@moon".format(name) + return subjects + + +def delete_subject(client, name): + subjects = get_subjects(client) + for key, value in subjects['subjects'].items(): + if value['name'] == name: + req = client.delete("/subjects/{}".format(key)) + assert req.status_code == 200 + break + subjects = get_subjects(client) + assert name not in [x['name'] for x in subjects["subjects"].values()] + + +def test_subject(): + import moon_manager.server + server = moon_manager.server.main() + client = server.app.test_client() + get_subjects(client) + add_subjects(client, "testuser") + delete_subject(client, "testuser") diff --git a/moonv4/moon_manager/tests/unit_python/conftest.py b/moonv4/moon_manager/tests/unit_python/conftest.py new file mode 100644 index 00000000..d6f518f7 --- /dev/null +++ b/moonv4/moon_manager/tests/unit_python/conftest.py @@ -0,0 +1,195 @@ +import base64 +import json +import logging +import pytest +import requests_mock + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "interface" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", +) + + +def get_b64_conf(component=None): + if component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') + else: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + + +@pytest.fixture(autouse=True) +def no_requests(monkeypatch): + """ Modify the response from Requests module + """ + with requests_mock.Mocker(real_http=True) as m: + for component in COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': get_b64_conf(component)}] + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'DELETE', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users/', + json={"users": [{ + "id": "1111111111111" + }]} + ) + print("Start populating the DB.") + from moon_db.db_manager import init_engine, main + engine = init_engine() + print("engine={}".format(engine)) + main("upgrade", logging.getLogger("db_manager"), engine) + print("End populating the DB.") + yield m + + +# @pytest.fixture(autouse=True, scope="session") +# def manage_database(): +# from moon_db.db_manager import init_engine, run +# engine = init_engine() +# run("upgrade", logging.getLogger("db_manager"), engine) +# yield +# print("Will close the DB") + + diff --git a/moonv4/moon_manager/tests/unit_python/requirements.txt b/moonv4/moon_manager/tests/unit_python/requirements.txt new file mode 100644 index 00000000..8bd8449f --- /dev/null +++ b/moonv4/moon_manager/tests/unit_python/requirements.txt @@ -0,0 +1,5 @@ +flask +flask_cors +flask_restful +moon_db +moon_utilities
\ No newline at end of file diff --git a/moonv4/moon_orchestrator/Dockerfile b/moonv4/moon_orchestrator/Dockerfile index b68c130f..aafe1784 100644 --- a/moonv4/moon_orchestrator/Dockerfile +++ b/moonv4/moon_orchestrator/Dockerfile @@ -9,6 +9,7 @@ RUN pip3 install pip --upgrade ADD . /root WORKDIR /root/ RUN pip3 install -r requirements.txt --upgrade +#RUN pip3 install /root/dist/* --upgrade RUN pip3 install . --upgrade -CMD ["python3", "bootstrap.py"]
\ No newline at end of file +CMD ["python3", "-m", "moon_orchestrator"]
\ No newline at end of file diff --git a/moonv4/moon_orchestrator/LICENSE b/moonv4/moon_orchestrator/LICENSE index 4143aac2..d6456956 100644 --- a/moonv4/moon_orchestrator/LICENSE +++ b/moonv4/moon_orchestrator/LICENSE @@ -174,31 +174,29 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/moonv4/moon_orchestrator/bootstrap.py b/moonv4/moon_orchestrator/bootstrap.py deleted file mode 100644 index dab78f25..00000000 --- a/moonv4/moon_orchestrator/bootstrap.py +++ /dev/null @@ -1,203 +0,0 @@ -import sys -import time -import requests -import yaml -import logging -import json -import base64 -import mysql.connector -import re -import subprocess -import pika -import pika.credentials -import pika.exceptions - -logging.basicConfig(level=logging.INFO) -log = logging.getLogger("moon.bootstrap") -requests_log = logging.getLogger("requests.packages.urllib3") -requests_log.setLevel(logging.WARNING) -requests_log.propagate = True -pika_log = logging.getLogger("pika") -pika_log.setLevel(logging.ERROR) -pika_log.propagate = True - -CONSUL_HOST = sys.argv[1] if len(sys.argv) > 1 else "consul" -CONSUL_PORT = sys.argv[2] if len(sys.argv) > 2 else 8500 -HEADERS = {"content-type": "application/json"} - - -def search_config_file(): - data_config = None - for _file in ( - "moon.conf", - "conf/moon.conf", - "../moon.conf", - "/etc/moon/moon.conf", - ): - try: - data_config = yaml.safe_load(open(_file)) - except FileNotFoundError: - data_config = None - continue - else: - break - if not data_config: - raise Exception("Configuration file not found...") - return data_config - - -def put(key, value): - url = "http://{host}:{port}/v1/kv/{key}".format(host=CONSUL_HOST, port=CONSUL_PORT, key=key) - log.info(url) - req = requests.put( - url, - headers=HEADERS, - json=value - ) - if req.status_code != 200: - raise Exception("Error connecting to Consul ({}, {})".format(req.status_code, req.text)) - - -def get(key): - url = "http://{host}:{port}/v1/kv/{key}".format(host=CONSUL_HOST, port=CONSUL_PORT, key=key) - req = requests.get(url) - data = req.json() - for item in data: - log.info("{} {} -> {}".format( - req.status_code, - item["Key"], - json.loads(base64.b64decode(item["Value"]).decode("utf-8")) - )) - yield json.loads(base64.b64decode(item["Value"]).decode("utf-8")) - - -def populate_consul(data_config): - while True: - try: - req = requests.get("http://{}:{}/ui".format(CONSUL_HOST, CONSUL_PORT)) - except requests.exceptions.ConnectionError: - log.info("Waiting for Consul ({}:{})".format(CONSUL_HOST, CONSUL_PORT)) - time.sleep(1) - continue - else: - break - # if req.status_code in (302, 200): - # break - # log.info("Waiting for Consul ({}:{})".format(CONSUL_HOST, CONSUL_PORT)) - # time.sleep(1) - log.info("Consul is up") - - req = requests.get("http://{}:{}/v1/kv/database".format(CONSUL_HOST, CONSUL_PORT)) - if req.status_code == 200: - log.info("Consul is already populated") - return - - put("database", data_config["database"]) - put("messenger", data_config["messenger"]) - put("slave", data_config["slave"]) - put("docker", data_config["docker"]) - put("logging", data_config["logging"]) - put("components_port_start", data_config["components"]["port_start"]) - - for _key, _value in data_config["components"].items(): - if type(_value) is dict: - put("components/{}".format(_key), data_config["components"][_key]) - - for _key, _value in data_config["plugins"].items(): - put("plugins/{}".format(_key), data_config["plugins"][_key]) - - for _key, _value in data_config["openstack"].items(): - put("openstack/{}".format(_key), data_config["openstack"][_key]) - - -def wait_for_database(): - log.info(get("database")) - for database in get("database"): - database_url = database['url'] - match = re.search("(?P<proto>^[\\w+]+):\/\/(?P<user>\\w+):(?P<password>.+)@(?P<host>\\w+):*(?P<port>\\d*)", - database_url) - config = match.groupdict() - while True: - try: - conn = mysql.connector.connect( - host=config["host"], - user=config["user"], - password=config["password"], - database="moon" - ) - conn.close() - except mysql.connector.errors.InterfaceError: - log.info("Waiting for Database ({})".format(config["host"])) - time.sleep(1) - continue - else: - log.info("Database i up, populating it...") - output = subprocess.run(["moon_db_manager", "upgrade"]) - if output.returncode != 0: - raise Exception("Error populating the database!") - break - - -def wait_for_message_queue(): - for messenger in get("messenger"): - url = messenger['url'] - match = re.search("(?P<proto>^[\\w+]+):\/\/(?P<user>\\w+):(?P<password>.+)@(?P<host>\\w+):?(?P<port>\\d*)/?(?P<virtual_host>\\w+)", - url) - config = match.groupdict() - while True: - try: - connection = pika.BlockingConnection( - pika.ConnectionParameters( - host=config['host'], - port=int(config['port']), - virtual_host=config['virtual_host'], - credentials=pika.credentials.PlainCredentials( - config['user'], - config['password'] - ) - ) - ) - connection.close() - except ( - pika.exceptions.ProbableAuthenticationError, - pika.exceptions.ConnectionClosed, - ConnectionResetError, - pika.exceptions.IncompatibleProtocolError - ): - log.info("Waiting for MessageQueue ({})".format(config["host"])) - time.sleep(1) - continue - else: - log.info("MessageQueue is up") - break - - -def wait_for_keystone(): - # TODO: Keystone answers request too quickly - # even if it is not fully loaded - # we must test if a token retrieval is possible or not - # to see if Keystone is truly up and running - for config in get("openstack/keystone"): - while True: - try: - req = requests.get(config["url"]) - except requests.exceptions.ConnectionError: - log.info("Waiting for Keystone ({})".format(config["url"])) - time.sleep(1) - continue - else: - log.info("Keystone is up") - break - - -def main(): - data_config = search_config_file() - populate_consul(data_config) - wait_for_database() - wait_for_message_queue() - wait_for_keystone() - import moon_orchestrator.server - moon_orchestrator.server.main() - -main() - diff --git a/moonv4/moon_orchestrator/moon_orchestrator/__main__.py b/moonv4/moon_orchestrator/moon_orchestrator/__main__.py index b1feff49..9ebc3a7f 100644 --- a/moonv4/moon_orchestrator/moon_orchestrator/__main__.py +++ b/moonv4/moon_orchestrator/moon_orchestrator/__main__.py @@ -1,3 +1,4 @@ from moon_orchestrator.server import main -main() +server = main() +server.run() diff --git a/moonv4/moon_orchestrator/moon_orchestrator/api/configuration.py b/moonv4/moon_orchestrator/moon_orchestrator/api/configuration.py deleted file mode 100644 index 887a989b..00000000 --- a/moonv4/moon_orchestrator/moon_orchestrator/api/configuration.py +++ /dev/null @@ -1,63 +0,0 @@ -# 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'. - -import json -from oslo_config import cfg -from oslo_log import log as logging -# from moon_db.core import IntraExtensionRootManager -from moon_db.core import ConfigurationManager - -LOG = logging.getLogger("moon.orchestrator.api.configuration") -CONF = cfg.CONF - - -class Configuration(object): - """ - Retrieve the global configuration. - """ - - __version__ = "0.1.0" - - def get_policy_templates(self, ctx, args): - """List all policy templates - - :param ctx: {"id": "intra_extension_id"} - :param args: {} - :return: { - "template_id": { - "name": "name of the template", - "description": "description of the template", - } - """ - templates = ConfigurationManager.get_policy_templates_dict(ctx["user_id"]) - return {"policy_templates": templates} - - def get_aggregation_algorithms(self, ctx, args): - """List all aggregation algorithms - - :param ctx: {"id": "intra_extension_id"} - :param args: {} - :return: { - "algorithm_id": { - "name": "name of the algorithm", - "description": "description of the algorithm", - } - } - """ - return {'aggregation_algorithms': ConfigurationManager.get_aggregation_algorithms_dict(ctx["user_id"])} - - def get_sub_meta_rule_algorithms(self, ctx, args): - """List all sub meta rule algorithms - - :param ctx: {"id": "intra_extension_id"} - :param args: {} - :return: { - "algorithm_id": { - "name": "name of the algorithm", - "description": "description of the algorithm", - } - } - """ - return {'sub_meta_rule_algorithms': ConfigurationManager.get_sub_meta_rule_algorithms_dict(ctx["user_id"])} diff --git a/moonv4/moon_orchestrator/moon_orchestrator/api/containers.py b/moonv4/moon_orchestrator/moon_orchestrator/api/containers.py deleted file mode 100644 index 23acea5f..00000000 --- a/moonv4/moon_orchestrator/moon_orchestrator/api/containers.py +++ /dev/null @@ -1,123 +0,0 @@ -# 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'. - -import hashlib -from oslo_config import cfg -from oslo_log import log as logging -# from moon_db.core import IntraExtensionRootManager -# from moon_db.core import ConfigurationManager -from moon_utilities.security_functions import call - -LOG = logging.getLogger("moon.orchestrator.api.containers") -CONF = cfg.CONF - - -class Containers(object): - """ - Manage containers. - """ - - __version__ = "0.1.0" - - def __init__(self, docker_manager): - self.docker_manager = docker_manager - self.components = dict() - for pdp_key, pdp_value in call("moon_manager", method="get_pdp", - ctx={"user_id": "admin", "id": None})["pdps"].items(): - self.add_container(ctx={"id": pdp_key, "pipeline": pdp_value["security_pipeline"]}) - - def get_container(self, ctx, args=None): - """Get containers linked to an intra-extension - - :param ctx: { - "id": "intra_extension_uuid", - "keystone_project_id": "Keystone Project UUID" - } - :param args: {} - :return: { - "containers": {...}, - } - """ - uuid = ctx.get("id") - keystone_project_id = ctx.get("keystone_project_id") - # _containers = self.docker_manager.get_component(uuid=uuid) - # LOG.info("containers={}".format(_containers)) - if uuid: - return self.components[uuid] - elif keystone_project_id: - for container_id, container_value in self.components.items(): - if container_value['keystone_project_id'] == keystone_project_id: - return {container_id: container_value} - else: - return {} - return {"containers": self.components} - - def add_container(self, ctx, args=None): - """Add containers - - :param ctx: {"id": "intra_extension_uuid"} - :param args: {} - :return: { - "container_id1": {"status": True}, - "container_id2": {"status": True}, - } - """ - LOG.info("add_container {}".format(ctx)) - pdp = call("moon_manager", method="get_pdp", - ctx={"user_id": "admin", "id": ctx["id"]}, - args={})["pdps"] - pdp_id = list(pdp.keys())[0] - if not pdp[pdp_id]["keystone_project_id"]: - return {"result": "False", "message": "Cannot find keystone_project_id in pdp"} - keystone_project_id = pdp[pdp_id]["keystone_project_id"] - self.components[ctx["id"]] = [] - for policy_key, policy_value in call("moon_manager", method="get_policies", - ctx={"user_id": "admin", "id": None}, - args={})["policies"].items(): - if policy_key in ctx["pipeline"]: - models = call("moon_manager", method="get_models", - ctx={"user_id": "admin", "id": None}, - args={})["models"] - for meta_rule in models[policy_value['model_id']]['meta_rules']: - genre = policy_value['genre'] - pre_container_id = "pdp:{}_metarule:{}_project:{}".format(ctx["id"], meta_rule, keystone_project_id) - container_data = {"pdp": ctx["id"], "metarule": meta_rule, "project": keystone_project_id} - policy_component = self.docker_manager.load(component=genre, - uuid=pre_container_id, - container_data=container_data) - self.components[ctx["id"]].append({ - "meta_rule_id": meta_rule, - "genre": policy_value['genre'], - "keystone_project_id": keystone_project_id, - "container_id": policy_value['genre']+"_"+hashlib.sha224(pre_container_id.encode("utf-8")).hexdigest() - }) - return {"containers": self.components[ctx["id"]]} - - def delete_container(self, ctx, args=None): - """Delete a container - - :param ctx: {"id": "intra_extension_uuid"} - :param args: {} - :return: {} - """ - try: - self.docker_manager.kill(component_id="moon_secpolicy_"+ctx["id"]) - try: - # FIXME (asteroide): need to select other security_function here - self.docker_manager.kill(component_id="moon_secfunction_authz_"+ctx["id"]) - except Exception as e: - LOG.error(e, exc_info=True) - return {"result": True, - "error": {'code': 200, 'title': 'Moon Warning', 'description': str(e)}, - "intra_extension_id": ctx["id"], - "ctx": ctx, "args": args} - except Exception as e: - LOG.error(e, exc_info=True) - return {"result": False, - "error": {'code': 500, 'title': 'Moon Error', 'description': str(e)}, - "intra_extension_id": ctx["id"], - "ctx": ctx, "args": args} - return {"result": True} - diff --git a/moonv4/moon_orchestrator/moon_orchestrator/api/generic.py b/moonv4/moon_orchestrator/moon_orchestrator/api/generic.py index cadd98d3..fd43b1c5 100644 --- a/moonv4/moon_orchestrator/moon_orchestrator/api/generic.py +++ b/moonv4/moon_orchestrator/moon_orchestrator/api/generic.py @@ -2,28 +2,130 @@ # 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'. +""" +Those API are helping API used to manage the Moon platform. +""" +from flask_restful import Resource, request +import logging +import moon_orchestrator.api +from moon_utilities.security_functions import check_auth -class Status(object): +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.orchestrator.api." + __name__) + + +class Status(Resource): """ - Retrieve the current status of all components. + Endpoint for status requests """ - __version__ = "0.1.0" + __urls__ = ("/status", "/status/", "/status/<string:component_id>") - def get_status(self, ctx, args): - """Retrieve the current status of all components.""" - return {"status": "Running"} + def get(self, component_id=None): + """Retrieve status of all components + :return: { + "orchestrator": { + "status": "Running" + }, + "security_router": { + "status": "Running" + } + } + """ + raise NotImplemented -class Logs(object): + +class Logs(Resource): """ - Retrieve the current status of all components. + Endpoint for logs requests """ - __version__ = "0.1.0" + __urls__ = ("/logs", "/logs/", "/logs/<string:component_id>") + + def get(self, component_id=None): + """Get logs from the Moon platform + + :param component_id: the ID of the component your are looking for (optional) + :return: [ + "2015-04-15-13:45:20 + "2015-04-15-13:45:21 + "2015-04-15-13:45:22 + "2015-04-15-13:45:23 + ] + """ + filter_str = request.args.get('filter', '') + from_str = request.args.get('from', '') + to_str = request.args.get('to', '') + event_number = request.args.get('event_number', '') + try: + event_number = int(event_number) + except ValueError: + event_number = None + args = dict() + args["filter"] = filter_str + args["from"] = from_str + args["to"] = to_str + args["event_number"] = event_number + + raise NotImplemented + + +class API(Resource): + """ + Endpoint for API requests + """ - def get_logs(self, ctx, args): - return {"error": "NotImplemented", "ctx": ctx, "args": args} + __urls__ = ( + "/api", + "/api/", + "/api/<string:group_id>", + "/api/<string:group_id>/", + "/api/<string:group_id>/<string:endpoint_id>") + @check_auth + def get(self, group_id="", endpoint_id="", user_id=""): + """Retrieve all API endpoints or a specific endpoint if endpoint_id is given + :param group_id: the name of one existing group (ie generic, ...) + :param endpoint_id: the name of one existing component (ie Logs, Status, ...) + :return: { + "group_name": { + "endpoint_name": { + "description": "a description", + "methods": { + "get": "description of the HTTP method" + }, + "urls": ('/api', '/api/', '/api/<string:endpoint_id>') + } + } + """ + __methods = ("get", "post", "put", "delete", "options", "patch") + api_list = filter(lambda x: "__" not in x, dir(moon_orchestrator.api)) + api_desc = dict() + for api_name in api_list: + api_desc[api_name] = {} + group_api_obj = eval("moon_interface.api.{}".format(api_name)) + api_desc[api_name]["description"] = group_api_obj.__doc__ + if "__version__" in dir(group_api_obj): + api_desc[api_name]["version"] = group_api_obj.__version__ + object_list = list(filter(lambda x: "__" not in x, dir(group_api_obj))) + for obj in map(lambda x: eval("moon_interface.api.{}.{}".format(api_name, x)), object_list): + if "__urls__" in dir(obj): + api_desc[api_name][obj.__name__] = dict() + api_desc[api_name][obj.__name__]["urls"] = obj.__urls__ + api_desc[api_name][obj.__name__]["methods"] = dict() + for _method in filter(lambda x: x in __methods, dir(obj)): + docstring = eval("moon_interface.api.{}.{}.{}.__doc__".format(api_name, obj.__name__, _method)) + api_desc[api_name][obj.__name__]["methods"][_method] = docstring + api_desc[api_name][obj.__name__]["description"] = str(obj.__doc__) + if group_id in api_desc: + if endpoint_id in api_desc[group_id]: + return {group_id: {endpoint_id: api_desc[group_id][endpoint_id]}} + elif len(endpoint_id) > 0: + LOG.error("Unknown endpoint_id {}".format(endpoint_id)) + return {"error": "Unknown endpoint_id {}".format(endpoint_id)} + return {group_id: api_desc[group_id]} + return api_desc diff --git a/moonv4/moon_orchestrator/moon_orchestrator/api/pods.py b/moonv4/moon_orchestrator/moon_orchestrator/api/pods.py new file mode 100644 index 00000000..319788e5 --- /dev/null +++ b/moonv4/moon_orchestrator/moon_orchestrator/api/pods.py @@ -0,0 +1,127 @@ +# 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 moon_utilities.security_functions import check_auth +import logging + +LOG = logging.getLogger("moon.orchestrator.api.pods") + + +class Pods(Resource): + """ + Endpoint for pdp requests + """ + + __urls__ = ( + "/pods", + "/pods/", + "/pods/<string:uuid>", + "/pods/<string:uuid>/", + ) + + def __init__(self, **kwargs): + self.driver = kwargs.get("driver") + self.create_security_function = kwargs.get("create_security_function_hook") + + @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": "...", + } + } + :internal_api: get_pdp + """ + pods = {} + # LOG.info("pods={}".format(self.driver.get_pods())) + if uuid: + return {"pods": self.driver.get_pods(uuid)} + 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} + + @check_auth + def post(self, uuid=None, user_id=None): + """Create a new pod. + + :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" + } + :return: { + "pdp_id1": { + "name": "...", + "replicas": "...", + "description": "...", + } + } + """ + LOG.info("POST param={}".format(request.json)) + self.create_security_function( + 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 = {} + 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} + + @check_auth + def delete(self, uuid=None, user_id=None): + """Delete a pod + + :param uuid: uuid of the pod to delete + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + """ + return {"result": True} + + @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/moonv4/moon_orchestrator/moon_orchestrator/api/slaves.py b/moonv4/moon_orchestrator/moon_orchestrator/api/slaves.py deleted file mode 100644 index 3a16fea1..00000000 --- a/moonv4/moon_orchestrator/moon_orchestrator/api/slaves.py +++ /dev/null @@ -1,78 +0,0 @@ -# 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 oslo_config import cfg -from oslo_log import log as logging -from uuid import uuid4 - -LOG = logging.getLogger("moon.orchestrator.api.slaves") -CONF = cfg.CONF - - -class Slaves(object): - """ - Manage containers. - """ - - __version__ = "0.1.0" - - def __init__(self, slaves): - self.slaves = slaves - - def add_slave(self, ctx, args=None): - """Add a new slave in the global list - - :param ctx: { - "name": "name of the slave", - "description": "description" - } - :param args: {} - :return: { - "uuid_of_the_slave": { - "name": "name of the slave", - "description": "description" - } - } - """ - if "name" in ctx: - for _id, _dict in self.slaves.items(): - if _dict['name'] == ctx['name']: - LOG.warning("A slave named {} already exists!".format(ctx['name'])) - return {"slaves": {_id: _dict}} - uuid = uuid4().hex - ctx.pop("method") - ctx.pop("call_master") - self.slaves[uuid] = ctx - LOG.info("New slave added: {}".format(ctx['name'])) - return {"slaves": {uuid: ctx}} - LOG.warning("No name given for the new slave.") - - def get_slaves(self, ctx, args=None): - """Get all the known slaves - - :param ctx: {} - :param args: {} - :return: { - "uuid_of_the_slave": { - "name": "name of the slave", - "description": "description" - } - } - """ - return {"slaves": self.slaves} - - def delete_slave(self, ctx, args=None): - """Delete a previous slave in the global list - - :param ctx: { - "id": "ID of the slave" - } - :param args: {} - :return: None - """ - if "id" in ctx: - if ctx['id'] in self.slaves: - self.slaves.pop(ctx['id']) - return {"slaves": self.slaves} diff --git a/moonv4/moon_orchestrator/moon_orchestrator/drivers.py b/moonv4/moon_orchestrator/moon_orchestrator/drivers.py new file mode 100644 index 00000000..95000840 --- /dev/null +++ b/moonv4/moon_orchestrator/moon_orchestrator/drivers.py @@ -0,0 +1,175 @@ +# 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 kubernetes import client, config +import logging +import urllib3.exceptions +from moon_utilities import configuration + +LOG = logging.getLogger("moon.orchestrator.drivers") + + +def get_driver(): + try: + return K8S() + except urllib3.exceptions.MaxRetryError as e: + LOG.exception(e) + return Docker() + + +class Driver: + + def __init__(self): + self.cache = {} + # example of cache: + # { + # "uuid_of_pod": { + # "ip": "", + # "hostname": "", + # "port": 30001, + # "pdp": "", + # "keystone_project_id": "", + # "plugin_name": "", + # "namespace": "" + # } + # } + + def get_pods(self, namespace=None): + raise NotImplementedError + + def load_pod(self, data, api_client=None, ext_client=None): + raise NotImplementedError + + def delete_pod(self, uuid=None, name=None): + raise NotImplementedError + + def get_slaves(self): + raise NotImplementedError + + +class K8S(Driver): + + def __init__(self): + super(K8S, self).__init__() + config.load_kube_config() + self.client = client.CoreV1Api() + + def get_pods(self, name=None): + if name: + pods = self.client.list_pod_for_all_namespaces(watch=False) + for pod in pods.items: + LOG.info("get_pods {}".format(pod.metadata.name)) + if name in pod.metadata.name: + return pod + else: + return None + LOG.info("get_pods cache={}".format(self.cache)) + return self.cache + + @staticmethod + def __create_pod(client, data): + pod_manifest = { + 'apiVersion': 'extensions/v1beta1', + 'kind': 'Deployment', + 'metadata': { + 'name': data[0].get('name') + }, + 'spec': { + 'replicas': 1, + 'template': { + 'metadata': {'labels': {'app': data[0].get('name')}}, + 'hostname': data[0].get('name'), + 'spec': { + 'containers': [] + } + }, + } + } + for _data in data: + pod_manifest['spec']['template']['spec']['containers'].append( + { + 'image': _data.get('container', "busybox"), + 'name': _data.get('name'), + 'hostname': _data.get('name'), + 'ports': [ + {"containerPort": _data.get('port', 80)}, + ], + 'env': [ + {'name': "UUID", "value": _data.get('name', "None")}, + {'name': "TYPE", "value": _data.get('genre', "None")}, + {'name': "PORT", "value": str(_data.get('port', 80))}, + {'name': "PDP_ID", "value": _data.get('pdp_id', "None")}, + {'name': "META_RULE_ID", "value": _data.get('meta_rule_id', "None")}, + {'name': "KEYSTONE_PROJECT_ID", + "value": _data.get('keystone_project_id', "None")}, + ] + } + ) + resp = client.create_namespaced_deployment(body=pod_manifest, + namespace='moon') + LOG.info("Pod {} created!".format(data[0].get('name'))) + # logger.info(yaml.dump(pod_manifest, sys.stdout)) + # logger.info(resp) + return resp + + @staticmethod + def __create_service(client, data, expose=False): + service_manifest = { + 'apiVersion': 'v1', + 'kind': 'Service', + 'metadata': { + 'name': data.get('name'), + 'namespace': 'moon' + }, + 'spec': { + 'ports': [{ + 'port': data.get('port', 80), + 'targetPort': data.get('port', 80) + }], + 'selector': { + 'app': data.get('name') + }, + # 'type': 'NodePort', + 'endpoints': [{ + 'port': data.get('port', 80), + 'protocol': 'TCP', + }], + } + } + if expose: + service_manifest['spec']['ports'][0]['nodePort'] = \ + configuration.increment_port() + service_manifest['spec']['type'] = "NodePort" + resp = client.create_namespaced_service(namespace="moon", + body=service_manifest) + LOG.info("Service {} created!".format(data.get('name'))) + return resp + + def load_pod(self, data, api_client=None, ext_client=None, expose=False): + _client = api_client if api_client else self.client + pod = self.__create_pod(client=ext_client, data=data) + service = self.__create_service(client=_client, data=data[0], + expose=expose) + self.cache[pod.metadata.uid] = data + + def delete_pod(self, uuid=None, name=None): + LOG.info("Deleting pod {}".format(uuid)) + # TODO: delete_namespaced_deployment + # https://github.com/kubernetes-incubator/client-python/blob/master/kubernetes/client/apis/extensions_v1beta1_api.py + + def get_slaves(self): + contexts, active_context = config.list_kube_config_contexts() + return contexts, active_context + + +class Docker(Driver): + + def load_pod(self, data, api_client=None, ext_client=None): + LOG.info("Creating pod {}".format(data[0].get('name'))) + raise NotImplementedError + + def delete_pod(self, uuid=None, name=None): + LOG.info("Deleting pod {}".format(uuid)) + raise NotImplementedError diff --git a/moonv4/moon_orchestrator/moon_orchestrator/http_server.py b/moonv4/moon_orchestrator/moon_orchestrator/http_server.py new file mode 100644 index 00000000..7aed18a6 --- /dev/null +++ b/moonv4/moon_orchestrator/moon_orchestrator/http_server.py @@ -0,0 +1,292 @@ +# 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 Flask, jsonify +from flask_cors import CORS, cross_origin +from flask_restful import Resource, Api +import logging +from kubernetes import client, config +import random +import requests +import time +from moon_orchestrator import __version__ +from moon_orchestrator.api.pods import Pods +from moon_orchestrator.api.generic import Logs, Status +from moon_utilities import configuration, exceptions +from moon_utilities.misc import get_random_name +from moon_orchestrator.drivers import get_driver + +LOG = logging.getLogger("moon.orchestrator.http") + + +class Server: + """Base class for HTTP server""" + + def __init__(self, host="localhost", port=80, api=None, **kwargs): + """Run a server + + :param host: hostname of the server + :param port: port for the running server + :param kwargs: optional parameters + :return: a running server + """ + self._host = host + self._port = port + self._api = api + self._extra = kwargs + + @property + def host(self): + return self._host + + @host.setter + def host(self, name): + self._host = name + + @host.deleter + def host(self): + self._host = "" + + @property + def port(self): + return self._port + + @port.setter + def port(self, number): + self._port = number + + @port.deleter + def port(self): + self._port = 80 + + def run(self): + raise NotImplementedError() + +__API__ = ( + Status, Logs + ) + + +class Root(Resource): + """ + The root of the web service + """ + __urls__ = ("/", ) + __methods = ("get", "post", "put", "delete", "options") + + def get(self): + tree = {"/": {"methods": ("get",), "description": "List all methods for that service."}} + for item in __API__: + tree[item.__name__] = {"urls": item.__urls__} + _methods = [] + for _method in self.__methods: + if _method in dir(item): + _methods.append(_method) + tree[item.__name__]["methods"] = _methods + tree[item.__name__]["description"] = item.__doc__.strip() + return { + "version": __version__, + "tree": tree + } + + +class HTTPServer(Server): + + def __init__(self, host="localhost", port=80, **kwargs): + super(HTTPServer, self).__init__(host=host, port=port, **kwargs) + self.app = Flask(__name__) + conf = configuration.get_configuration("components/orchestrator") + self.orchestrator_hostname = conf["components/orchestrator"].get("hostname", "orchestrator") + self.orchestrator_port = conf["components/orchestrator"].get("port", 80) + conf = configuration.get_configuration("components/manager") + self.manager_hostname = conf["components/manager"].get("hostname", "manager") + self.manager_port = conf["components/manager"].get("port", 80) + # TODO : specify only few urls instead of * + # CORS(self.app) + self.api = Api(self.app) + self.driver = get_driver() + LOG.info("Driver = {}".format(self.driver.__class__)) + self.__set_route() + self.__hook_errors() + pdp = None + while True: + try: + pdp = requests.get( + "http://{}:{}/pdp".format(self.manager_hostname, + self.manager_port)) + except requests.exceptions.ConnectionError: + LOG.warning("Manager is not ready, standby...") + time.sleep(1) + except KeyError: + LOG.warning("Manager is not ready, standby...") + time.sleep(1) + else: + if "pdps" in pdp.json(): + break + LOG.debug("pdp={}".format(pdp)) + self.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 + self.create_security_function( + keystone_project_id=_pdp_value.get('keystone_project_id'), + pdp_id=_pdp_key, + policy_ids=_pdp_value.get('security_pipeline', [])) + + def __hook_errors(self): + + def get_404_json(e): + return jsonify({"result": False, "code": 404, "description": str(e)}), 404 + self.app.register_error_handler(404, get_404_json) + + def get_400_json(e): + return jsonify({"result": False, "code": 400, "description": str(e)}), 400 + self.app.register_error_handler(400, lambda e: get_400_json) + self.app.register_error_handler(403, exceptions.AuthException) + + def __set_route(self): + self.api.add_resource(Root, '/') + + for api in __API__: + self.api.add_resource(api, *api.__urls__) + self.api.add_resource(Pods, *Pods.__urls__, + resource_class_kwargs={ + "driver": self.driver, + "create_security_function_hook": + self.create_security_function, + }) + + def run(self): + self.app.run(host=self._host, port=self._port) # nosec + + @staticmethod + def __filter_str(data): + return data.replace("@", "-") + + def create_wrappers(self): + contexts, active_context = self.driver.get_slaves() + LOG.debug("contexts: {}".format(contexts)) + LOG.debug("active_context: {}".format(active_context)) + conf = configuration.get_configuration("components/wrapper") + hostname = conf["components/wrapper"].get( + "hostname", "wrapper") + port = conf["components/wrapper"].get("port", 80) + container = conf["components/wrapper"].get( + "container", + "wukongsun/moon_wrapper:v4.3") + for _ctx in contexts: + _config = config.new_client_from_config(context=_ctx['name']) + LOG.debug("_config={}".format(_config)) + api_client = client.CoreV1Api(_config) + ext_client = client.ExtensionsV1beta1Api(_config) + # TODO: get data from consul + data = [{ + "name": hostname + "-" + get_random_name(), + "container": container, + "port": port, + "namespace": "moon" + }, ] + pod = self.driver.load_pod(data, api_client, ext_client, expose=True) + LOG.debug('wrapper pod={}'.format(pod)) + + def create_security_function(self, keystone_project_id, + pdp_id, policy_ids, manager_data={}, + active_context=None, + active_context_name=None): + """ Create security functions + + :param policy_id: the policy ID mapped to this security function + :param active_context: if present, add the security function in this + context + :param active_context_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) + :return: None + """ + for key, value in self.driver.get_pods().items(): + for _pod in value: + if _pod.get('keystone_project_id') == keystone_project_id: + LOG.warning("A pod for this Keystone project {} " + "already exists.".format(keystone_project_id)) + return + + plugins = configuration.get_plugins() + conf = configuration.get_configuration("components/interface") + i_hostname = conf["components/interface"].get("hostname", "interface") + i_port = conf["components/interface"].get("port", 80) + i_container = conf["components/interface"].get( + "container", + "wukongsun/moon_interface:v4.3") + data = [ + { + "name": i_hostname + "-" + get_random_name(), + "container": i_container, + "port": i_port, + 'pdp_id': pdp_id, + 'genre': "interface", + 'keystone_project_id': keystone_project_id, + "namespace": "moon" + }, + ] + LOG.info("data={}".format(data)) + policies = manager_data.get('policies') + if not policies: + LOG.info("No policy data from Manager, trying to get them") + policies = requests.get("http://{}:{}/policies".format( + self.manager_hostname, self.manager_port)).json().get( + "policies", dict()) + LOG.info("policies={}".format(policies)) + models = manager_data.get('models') + if not models: + LOG.info("No models data from Manager, trying to get them") + models = requests.get("http://{}:{}/models".format( + self.manager_hostname, self.manager_port)).json().get( + "models", dict()) + LOG.info("models={}".format(models)) + + for policy_id in policy_ids: + if policy_id in policies: + genre = policies[policy_id].get("genre", "authz") + if genre in plugins: + for meta_rule in models[policies[policy_id]['model_id']]['meta_rules']: + data.append({ + "name": genre + "-" + get_random_name(), + "container": plugins[genre]['container'], + 'pdp_id': pdp_id, + "port": plugins[genre].get('port', 8080), + 'genre': genre, + 'policy_id': policy_id, + 'meta_rule_id': meta_rule, + 'keystone_project_id': keystone_project_id, + "namespace": "moon" + }) + LOG.info("data={}".format(data)) + contexts, _active_context = self.driver.get_slaves() + LOG.info("active_context_name={}".format(active_context_name)) + LOG.info("active_context={}".format(active_context)) + 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']) + LOG.debug("_config={}".format(_config)) + api_client = client.CoreV1Api(_config) + ext_client = client.ExtensionsV1beta1Api(_config) + self.driver.load_pod(data, api_client, ext_client, expose=False) + return + LOG.info("contexts={}".format(contexts)) + for _ctx in contexts: + _config = config.new_client_from_config(context=_ctx['name']) + LOG.debug("_config={}".format(_config)) + api_client = client.CoreV1Api(_config) + ext_client = client.ExtensionsV1beta1Api(_config) + self.driver.load_pod(data, api_client, ext_client, expose=False) + + diff --git a/moonv4/moon_orchestrator/moon_orchestrator/messenger.py b/moonv4/moon_orchestrator/moon_orchestrator/messenger.py deleted file mode 100644 index 2b7b3866..00000000 --- a/moonv4/moon_orchestrator/moon_orchestrator/messenger.py +++ /dev/null @@ -1,63 +0,0 @@ -# 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'. - -import oslo_messaging -from oslo_log import log as logging -import time -from moon_utilities.api import APIList -from moon_utilities import configuration - -from oslo_config import cfg -from moon_orchestrator.api.generic import Status, Logs -from moon_orchestrator.api.containers import Containers -from moon_orchestrator.api.slaves import Slaves - -TOPIC = "orchestrator" -LOG = logging.getLogger("moon.orchestrator.messenger") -CONF = cfg.CONF - - -class Server: - - def __init__(self, containers, docker_manager, slaves): - cfg.CONF.transport_url = self.__get_transport_url() - self.CONTAINERS = containers - self.transport = oslo_messaging.get_transport(cfg.CONF) - self.target = oslo_messaging.Target(topic=TOPIC, server='server1') - LOG.info("Starting MQ server with topic: {}".format(TOPIC)) - self.docker_manager = docker_manager - for _container in containers: - Status._container = containers[_container] - self.endpoints = [ - APIList((Status, Logs, Containers)), - Status(), - Logs(), - Containers(self.docker_manager), - Slaves(slaves) - ] - self.server = oslo_messaging.get_rpc_server(self.transport, self.target, self.endpoints, - executor='threading', - access_policy=oslo_messaging.DefaultRPCAccessPolicy) - - @staticmethod - def __get_transport_url(): - messenger = configuration.get_configuration(configuration.MESSENGER)["messenger"] - return messenger['url'] - - def run(self): - try: - self.server.start() - while True: - time.sleep(1) - except KeyboardInterrupt: - LOG.warning("Stopping server by crtl+c (please be patient, closing connections...)") - except SystemExit: - LOG.warning("Stopping server (please be patient, closing connections...)") - except Exception as e: - LOG.error("Exception occurred: {}".format(e)) - - self.server.stop() - self.server.wait() - diff --git a/moonv4/moon_orchestrator/moon_orchestrator/server.py b/moonv4/moon_orchestrator/moon_orchestrator/server.py index 8fd2740f..5e16bfcd 100644 --- a/moonv4/moon_orchestrator/moon_orchestrator/server.py +++ b/moonv4/moon_orchestrator/moon_orchestrator/server.py @@ -3,175 +3,34 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -import sys import os -import hashlib -from oslo_log import log as logging -from docker import Client -import docker.errors as docker_errors +import logging from moon_utilities import configuration, exceptions -from moon_orchestrator import messenger - +from moon_orchestrator.http_server import HTTPServer LOG = logging.getLogger("moon.orchestrator") +DOMAIN = "moon_orchestrator" -CONTAINERS = {} -SLAVES = {} -docker_conf = configuration.get_configuration("docker")['docker'] -docker = Client(base_url=docker_conf['url']) -LOG.info("docker_url={}".format(docker_conf['url'])) -docker_network = docker_conf['network'] - - -def kill_handler(signum, frame): - _exit(0) - - -class DockerManager: - - def load(self, component, uuid=None, container_data=None): - """Load a new docker mapping the component given - - :param component: the name of the component (policy or function) - :param uuid: the uuid of the intra_extension linked to that component - :return: the created component - """ - component_id = component+"_"+hashlib.sha224(uuid.encode("utf-8")).hexdigest() - plugins = configuration.get_plugins() - if component in plugins.keys(): - components = configuration.get_components() - configuration.add_component( - name=component_id, - uuid=component_id, - port=configuration.increment_port(), - bind="0.0.0.0", - extra=container_data, - container=plugins[component]['container'] - ) - # _command = plugins[component]['command'] - # try: - # _index = _command.index("<UUID>") - # _command[_index] = component_id - # except ValueError: - # pass - self.run(component_id, environment={"UUID": component_id}) - CONTAINERS[component_id] = components.get(component_id) - CONTAINERS[component_id]["running"] = True - return CONTAINERS[component_id] - - def load_all_containers(self): - LOG.info("Try to load all containers...") - current_containers = [item["Names"][0] for item in docker.containers()] - components = configuration.get_components() - containers_not_running = [] - for c_name in ( - '/keystone', - '/consul', - '/db', - '/messenger' - ): - if c_name not in current_containers: - containers_not_running.append(c_name) - if containers_not_running: - raise exceptions.ContainerMissing( - "Following containers are missing: {}".format(", ".join(containers_not_running))) - for c_name in ( - '/interface', - '/manager', - '/router'): - if c_name not in current_containers: - LOG.info("Starting container {}...".format(c_name)) - self.run(c_name.strip("/")) - else: - LOG.info("Container {} already running...".format(c_name)) - CONTAINERS[c_name] = components.get(c_name.strip("/")) - CONTAINERS[c_name]["running"] = True - - def run(self, name, environment=None): - components = configuration.get_components() - if name in components: - image = components[name]['container'] - params = { - 'image': image, - 'name': name, - 'hostname': name, - 'detach': True, - 'host_config': docker.create_host_config(network_mode=docker_network) - } - if 'port' in components[name] and components[name]['port']: - params["ports"] = [components[name]['port'], ] - params["host_config"] = docker.create_host_config( - network_mode=docker_network, - port_bindings={components[name]['port']: components[name]['port']} - ) - if environment: - params["environment"] = environment - container = docker.create_container(**params) - docker.start(container=container.get('Id')) - - @staticmethod - def get_component(uuid=None): - if uuid: - return CONTAINERS.get(uuid, None) - return CONTAINERS - - @staticmethod - def kill(component_id, delete=True): - LOG.info("Killing container {}".format(component_id)) - docker.kill(container=component_id) - if delete: - docker.remove_container(container=component_id) - +__CWD__ = os.path.dirname(os.path.abspath(__file__)) -def _exit(exit_number=0, error=None): - for _container in CONTAINERS: - LOG.warning("Deleting containers named {}...".format(_container)) - # print(40 * "-" + _container) - try: - # print(docker.logs(container=_container).decode("utf-8")) - docker.kill(container=_container) - except docker_errors.NotFound: - LOG.error("The container {} was not found".format(_container)) - except docker_errors.APIError as e: - LOG.error(e) - else: - docker.remove_container(container=_container) - LOG.info("Moon orchestrator: offline") - - # TODO (asteroide): put in the debug log - if error: - LOG.info(str(error)) - sys.exit(exit_number) - - -def __save_pid(): - try: - open("/var/run/moon_orchestrator.pid", "w").write(str(os.getpid())) - except PermissionError: - LOG.warning("You don't have the right to write PID file in /var/run... Continuing anyway.") - LOG.warning("Writing PID file in {}".format(os.getcwd())) - open("./moon_orchestrator.pid", "w").write(str(os.getpid())) - - -def server(): +def main(): configuration.init_logging() - conf = configuration.add_component("orchestrator", "orchestrator") - LOG.info("Starting main server {}".format(conf["components/orchestrator"]["hostname"])) - - docker_manager = DockerManager() - - docker_manager.load_all_containers() - serv = messenger.Server(containers=CONTAINERS, docker_manager=docker_manager, slaves=SLAVES) try: - serv.run() - finally: - _exit(0) - - -def main(): - server() + conf = configuration.get_configuration("components/orchestrator") + hostname = conf["components/orchestrator"].get("hostname", "orchestrator") + port = conf["components/orchestrator"].get("port", 80) + bind = conf["components/orchestrator"].get("bind", "127.0.0.1") + except exceptions.ConsulComponentNotFound: + hostname = "orchestrator" + bind = "127.0.0.1" + port = 80 + configuration.add_component(uuid="orchestrator", name=hostname, port=port, bind=bind) + LOG.info("Starting server with IP {} on port {} bind to {}".format(hostname, port, bind)) + server = HTTPServer(host=bind, port=port) + return server if __name__ == '__main__': - main() + server = main() + server.run() diff --git a/moonv4/moon_orchestrator/requirements.txt b/moonv4/moon_orchestrator/requirements.txt index c7653278..6197f10f 100644 --- a/moonv4/moon_orchestrator/requirements.txt +++ b/moonv4/moon_orchestrator/requirements.txt @@ -1,12 +1,8 @@ -docker-py -kombu !=4.0.1,!=4.0.0 -oslo.messaging !=5.14.0,!=5.13.0 -oslo.config -oslo.log -vine -jinja2 -sqlalchemy -pymysql +flask +flask_restful +flask_cors werkzeug moon_utilities -moon_db
\ No newline at end of file +moon_db +kubernetes +pyaml
\ No newline at end of file diff --git a/moonv4/moon_orchestrator/tests/unit_python/conftest.py b/moonv4/moon_orchestrator/tests/unit_python/conftest.py new file mode 100644 index 00000000..044489e6 --- /dev/null +++ b/moonv4/moon_orchestrator/tests/unit_python/conftest.py @@ -0,0 +1,18 @@ +import pytest +import requests_mock +import mock_pods +from utilities import CONTEXT + + +@pytest.fixture +def context(): + return CONTEXT + + +@pytest.fixture(autouse=True) +def no_requests(monkeypatch): + """ Modify the response from Requests module + """ + with requests_mock.Mocker(real_http=True) as m: + mock_pods.register_pods(m) + yield m
\ No newline at end of file diff --git a/moonv4/moon_orchestrator/tests/unit_python/mock_pods.py b/moonv4/moon_orchestrator/tests/unit_python/mock_pods.py new file mode 100644 index 00000000..c5633152 --- /dev/null +++ b/moonv4/moon_orchestrator/tests/unit_python/mock_pods.py @@ -0,0 +1,404 @@ +from kubernetes import client, config +from utilities import CONF, get_b64_conf, COMPONENTS + +pdp_mock = { + "pdp_id1": { + "name": "...", + "security_pipeline": ["policy_id_1", "policy_id_2"], + "keystone_project_id": "keystone_project_id1", + "description": "...", + }, + "pdp_id12": { + "name": "...", + "security_pipeline": ["policy_id_1", "policy_id_2"], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } +} + +meta_rules_mock = { + "meta_rule_id1": { + "name": "meta_rule1", + "algorithm": "name of the meta rule algorithm", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + }, + "meta_rule_id2": { + "name": "name of the meta rules2", + "algorithm": "name of the meta rule algorithm", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + } +} + +policies_mock = { + "policy_id_1": { + "name": "test_policy1", + "model_id": "model_id_1", + "genre": "authz", + "description": "test", + }, + "policy_id_2": { + "name": "test_policy2", + "model_id": "model_id_2", + "genre": "authz", + "description": "test", + } +} + +subject_mock = { + "policy_id_1": { + "subject_id": { + "name": "subject_name", + "keystone_id": "keystone_project_id1", + "description": "a description" + } + }, + "policy_id_2": { + "subject_id": { + "name": "subject_name", + "keystone_id": "keystone_project_id1", + "description": "a description" + } + } +} + +subject_assignment_mock = { + "subject_id": { + "policy_id": "ID of the policy", + "subject_id": "ID of the subject", + "category_id": "ID of the category", + "assignments": [], + } +} + +object_mock = { + "policy_id_1": { + "object_id": { + "name": "object_name", + "description": "a description" + } + }, + "policy_id_2": { + "object_id": { + "name": "object_name", + "description": "a description" + } + } +} + +object_assignment_mock = { + "object_id": { + "policy_id": "ID of the policy", + "object_id": "ID of the object", + "category_id": "ID of the category", + "assignments": [], + } +} + +action_mock = { + "policy_id_1": { + "action_id": { + "name": "action_name", + "description": "a description" + } + }, + "policy_id_2": { + "action_id": { + "name": "action_name", + "description": "a description" + } + } +} + +action_assignment_mock = { + "action_id": { + "policy_id": "ID of the policy", + "action_id": "ID of the action", + "category_id": "ID of the category", + "assignments": [], + } +} + +models_mock = { + "model_id_1": { + "name": "test_model", + "description": "test", + "meta_rules": ["meta_rule_id1"] + }, + "model_id_2": { + "name": "test_model", + "description": "test", + "meta_rules": ["meta_rule_id2"] + }, +} + +rules_mock = { + "rules": { + "meta_rule_id": "meta_rule_id1", + "rule_id1": { + "rule": ["subject_data_id1", + "object_data_id1", + "action_data_id1"], + "instructions": ( + {"decision": "grant"}, + # "grant" to immediately exit, + # "continue" to wait for the result of next policy + # "deny" to deny the request + ) + }, + "rule_id2": { + "rule": ["subject_data_id2", + "object_data_id2", + "action_data_id2"], + "instructions": ( + { + "update": { + "operation": "add", + # operations may be "add" or "delete" + "target": "rbac:role:admin" + # add the role admin to the current user + } + }, + {"chain": {"name": "rbac"}} + # chain with the policy named rbac + ) + } + } +} + + +def patch_k8s(monkeypatch): + def _load_kube_config_mockreturn(*args, **kwargs): + return + monkeypatch.setattr(config, 'load_kube_config', + _load_kube_config_mockreturn) + + def list_kube_config_contexts_mockreturn(*args, **kwargs): + return [{"name": "active_context"}], {"name": "active_context"} + monkeypatch.setattr(config, 'list_kube_config_contexts', + list_kube_config_contexts_mockreturn) + + def new_client_from_config_mockreturn(*args, **kwargs): + return {"client": True} + monkeypatch.setattr(config, 'new_client_from_config', + new_client_from_config_mockreturn) + + def list_pod_for_all_namespaces_mockreturn(*args, **kwargs): + class pods: + items = [] + return pods + monkeypatch.setattr(client.CoreV1Api, 'list_pod_for_all_namespaces', + list_pod_for_all_namespaces_mockreturn) + + def create_namespaced_deployment_mockreturn(*args, **kwargs): + + class metadata: + uid = "123456789" + + class pod: + def __init__(self): + self.metadata = metadata() + return pod() + monkeypatch.setattr(client.ExtensionsV1beta1Api, + 'create_namespaced_deployment', + create_namespaced_deployment_mockreturn) + + def create_namespaced_service_mockreturn(*args, **kwargs): + return {} + monkeypatch.setattr(client.CoreV1Api, + 'create_namespaced_service', + create_namespaced_service_mockreturn) + + +def register_pods(m): + """ Modify the response from Requests module + """ + register_consul(m) + register_pdp(m) + # register_meta_rules(m) + register_policies(m) + register_models(m) + # register_policy_subject(m, "policy_id_1") + # register_policy_subject(m, "policy_id_2") + # register_policy_object(m, "policy_id_1") + # register_policy_object(m, "policy_id_2") + # register_policy_action(m, "policy_id_1") + # register_policy_action(m, "policy_id_2") + # register_policy_subject_assignment(m, "policy_id_1", "subject_id") + # register_policy_subject_assignment_list(m1, "policy_id_1") + # register_policy_subject_assignment(m, "policy_id_2", "subject_id") + # register_policy_subject_assignment_list(m1, "policy_id_2") + # register_policy_object_assignment(m, "policy_id_1", "object_id") + # register_policy_object_assignment_list(m1, "policy_id_1") + # register_policy_object_assignment(m, "policy_id_2", "object_id") + # register_policy_object_assignment_list(m1, "policy_id_2") + # register_policy_action_assignment(m, "policy_id_1", "action_id") + # register_policy_action_assignment_list(m1, "policy_id_1") + # register_policy_action_assignment(m, "policy_id_2", "action_id") + # register_policy_action_assignment_list(m1, "policy_id_2") + # register_rules(m, "policy_id1") + + +def register_consul(m): + for component in COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': get_b64_conf(component)}] + ) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/components_port_start', + json=[ + { + "LockIndex": 0, + "Key": "components_port_start", + "Flags": 0, + "Value": "MzEwMDE=", + "CreateIndex": 9, + "ModifyIndex": 9 + } + ], + ) + m.register_uri( + 'PUT', 'http://consul:8500/v1/kv/components_port_start', + json=[], + ) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/plugins?recurse=true', + json=[ + { + "LockIndex": 0, + "Key": "plugins/authz", + "Flags": 0, + "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=", + "CreateIndex": 14, + "ModifyIndex": 656 + } + ], + ) + + +def register_pdp(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'pdp'), + json={'pdps': pdp_mock} + ) + + +def register_meta_rules(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'meta_rules'), + json={'meta_rules': meta_rules_mock} + ) + + +def register_policies(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies'), + json={'policies': policies_mock} + ) + + +def register_models(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'models'), + json={'models': models_mock} + ) + + +def register_policy_subject(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subjects'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'subjects': subject_mock[policy_id]} + ) + + +def register_policy_object(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/objects'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'objects': object_mock[policy_id]} + ) + + +def register_policy_action(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/actions'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'actions': action_mock[policy_id]} + ) + + +def register_policy_subject_assignment(m, policy_id, subj_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subject_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + subj_id), + json={'subject_assignments': subject_assignment_mock} + ) + + +def register_policy_subject_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subject_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'subject_assignments': subject_assignment_mock} + ) + + +def register_policy_object_assignment(m, policy_id, obj_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/object_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + obj_id), + json={'object_assignments': object_assignment_mock} + ) + + +def register_policy_object_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/object_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'object_assignments': object_assignment_mock} + ) + + +def register_policy_action_assignment(m, policy_id, action_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/action_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + action_id), + json={'action_assignments': action_assignment_mock} + ) + + +def register_policy_action_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/action_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'action_assignments': action_assignment_mock} + ) + + +def register_rules(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, 'rules'), + json={'rules': rules_mock} + )
\ No newline at end of file diff --git a/moonv4/moon_orchestrator/tests/unit_python/requirements.txt b/moonv4/moon_orchestrator/tests/unit_python/requirements.txt new file mode 100644 index 00000000..8bd8449f --- /dev/null +++ b/moonv4/moon_orchestrator/tests/unit_python/requirements.txt @@ -0,0 +1,5 @@ +flask +flask_cors +flask_restful +moon_db +moon_utilities
\ No newline at end of file diff --git a/moonv4/moon_orchestrator/tests/unit_python/test_pods.py b/moonv4/moon_orchestrator/tests/unit_python/test_pods.py new file mode 100644 index 00000000..42c8404b --- /dev/null +++ b/moonv4/moon_orchestrator/tests/unit_python/test_pods.py @@ -0,0 +1,43 @@ +import json +from mock_pods import patch_k8s +from utilities import get_json + + +def test_get_pods(context, monkeypatch): + patch_k8s(monkeypatch) + + import moon_orchestrator.server + server = moon_orchestrator.server.main() + _client = server.app.test_client() + req = _client.get("/pods") + assert req.status_code == 200 + assert req.data + data = get_json(req.data) + assert isinstance(data, dict) + assert "pods" in data + + +def test_add_pods(context, monkeypatch): + patch_k8s(monkeypatch) + + import moon_orchestrator.server + server = moon_orchestrator.server.main() + _client = server.app.test_client() + data = { + "keystone_project_id": context.get('project_id'), + "pdp_id": context.get('pdp_id'), + "security_pipeline": context.get('security_pipeline'), + } + 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_delete_pods(context, monkeypatch): + # TODO + pass diff --git a/moonv4/moon_orchestrator/tests/unit_python/utilities.py b/moonv4/moon_orchestrator/tests/unit_python/utilities.py new file mode 100644 index 00000000..aec03d9d --- /dev/null +++ b/moonv4/moon_orchestrator/tests/unit_python/utilities.py @@ -0,0 +1,173 @@ +import base64 +import json +import pytest +from uuid import uuid4 + + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "interface" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + + +CONTEXT = { + "project_id": "a64beb1cc224474fb4badd43173e7101", + "subject_name": "testuser", + "object_name": "vm1", + "action_name": "boot", + "request_id": uuid4().hex, + "interface_name": "interface", + "manager_url": "http://{}:{}".format( + CONF["components"]["manager"]["hostname"], + CONF["components"]["manager"]["port"] + ), + "cookie": uuid4().hex, + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", + "security_pipeline": ["f8f49a779ceb47b3ac810f01ef71b4e0"] + } + + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", + "components/orchestrator", + "components/interface", + "components/wrapper", +) + + +def get_b64_conf(component=None): + if component == "components": + return base64.b64encode( + json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8') + elif component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif not component: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') + + +def get_json(data): + return json.loads(data.decode("utf-8")) + + diff --git a/moonv4/moon_router/Dockerfile b/moonv4/moon_router/Dockerfile deleted file mode 100644 index 1722b801..00000000 --- a/moonv4/moon_router/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM ubuntu:latest - -RUN apt update && apt install python3.5 python3-pip -y -RUN pip3 install pip --upgrade - -ADD . /root -WORKDIR /root/ -RUN pip3 install -r requirements.txt --upgrade -RUN pip3 install . - -CMD ["python3", "-m", "moon_router"]
\ No newline at end of file diff --git a/moonv4/moon_router/README.md b/moonv4/moon_router/README.md deleted file mode 100644 index 91899b31..00000000 --- a/moonv4/moon_router/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Router: Core module for the Moon project - -This package contains the core module for the Moon project -It is designed to provide authorization features to all OpenStack components. - -For any other information, refer to the parent project: - - https://git.opnfv.org/moon - -## Build Image -```bash -docker image build -t wukongsun/moon_router:v4.1 . -``` - -## Push Image -```bash -docker push wukongsun/moon_router:v4.1 -```
\ No newline at end of file diff --git a/moonv4/moon_router/doc/api-moon-secrouter.pdf b/moonv4/moon_router/doc/api-moon-secrouter.pdf Binary files differdeleted file mode 100644 index 9ba75db0..00000000 --- a/moonv4/moon_router/doc/api-moon-secrouter.pdf +++ /dev/null diff --git a/moonv4/moon_router/doc/api.pdf b/moonv4/moon_router/doc/api.pdf Binary files differdeleted file mode 100644 index b7d91293..00000000 --- a/moonv4/moon_router/doc/api.pdf +++ /dev/null diff --git a/moonv4/moon_router/moon_router/__main__.py b/moonv4/moon_router/moon_router/__main__.py deleted file mode 100644 index 0d7a8fe6..00000000 --- a/moonv4/moon_router/moon_router/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from moon_router.server import main - -main() diff --git a/moonv4/moon_router/moon_router/api/generic.py b/moonv4/moon_router/moon_router/api/generic.py deleted file mode 100644 index d066f715..00000000 --- a/moonv4/moon_router/moon_router/api/generic.py +++ /dev/null @@ -1,46 +0,0 @@ -# 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 moon_utilities.security_functions import call - - -class Status(object): - """ - Retrieve the current status of all components. - """ - - __version__ = "0.1.0" - - def __get_status(self, ctx, args={}): - return {"status": "Running"} - - def get_status(self, ctx, args={}): - status = dict() - if "component_id" in ctx and ctx["component_id"] == "security_router": - return {"security_router": self.__get_status(ctx, args)} - elif "component_id" in ctx and ctx["component_id"]: - # TODO (dthom): check if component exist - status[ctx["component_id"]] = call(ctx["component_id"], ctx, "get_status", args=args) - else: - # TODO (dthom): must get the status of all containers - status["orchestrator"] = call("orchestrator", ctx, "get_status", args=args) - status["security_router"] = self.__get_status(ctx, args) - return status - - -class Logs(object): - """ - Retrieve the current status of all components. - """ - - __version__ = "0.1.0" - - def get_logs(self, ctx, args={}): - logs = dict() - logs["orchestrator"] = call("orchestrator", ctx, "get_logs", args=args) - # TODO (dthom): must get the logs of all containers - logs["security_router"] = {"error": "Not implemented", "ctx": ctx, "args": args} - return logs - - diff --git a/moonv4/moon_router/moon_router/api/route.py b/moonv4/moon_router/moon_router/api/route.py deleted file mode 100644 index c9cfb82a..00000000 --- a/moonv4/moon_router/moon_router/api/route.py +++ /dev/null @@ -1,472 +0,0 @@ -# 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'. - -import copy -import time -import itertools -from uuid import uuid4 -from oslo_log import log as logging -from moon_utilities.security_functions import call, notify -from moon_router.api.generic import Status, Logs -from moon_utilities import configuration - -LOG = logging.getLogger("moon.router.api.route") - -API = { - "orchestrator": ( - "add_container", - "delete_container", - "add_slave", - "get_slaves", - "delete_slave" - ), - # TODO (asteroide): need to check if some of those calls need (or not) to be called "update_" - "manager": ( - "get_subject_assignments", - "set_subject_assignment", - "delete_subject_assignment", - "get_object_assignments", - "set_object_assignment", - "delete_object_assignment", - "get_action_assignments", - "set_action_assignment", - "delete_action_assignment", - "get_subject_data", - "add_subject_data", - "delete_subject_data", - "get_object_data", - "add_object_data", - "delete_object_data", - "get_action_data", - "add_action_data", - "delete_action_data", - "get_subject_categories", - "set_subject_category", - "delete_subject_category", - "get_object_categories", - "set_object_category", - "delete_object_category", - "get_action_categories", - "set_action_category", - "delete_action_category", - "add_meta_rules", - "delete_meta_rules", - "get_meta_rules", - "set_meta_rules", - "get_models", - "add_model", - "delete_model", - "update_model", - "get_pdp", - "add_pdp", - "delete_pdp", - "update_pdp", - "get_subjects", - "set_subject", - "delete_subject", - "get_objects", - "set_object", - "delete_object", - "get_actions", - "set_action", - "delete_action", - "get_policies", - "add_policy", - "delete_policy", - "update_policy", - "get_subject_assignments", - "update_subject_assignment", - "delete_subject_assignment", - "get_object_assignments", - "update_object_assignment", - "delete_object_assignment", - "get_action_assignments", - "update_action_assignment", - "delete_action_assignment", - "get_rules", - "add_rule", - "delete_rule", - "update_from_master" - ), - "function": ( - "authz", - "return_authz", - ), -} - - -class Cache(object): - - # TODO (asteroide): set cache integer in CONF file - __UPDATE_INTERVAL = 10 - - __CONTAINERS = {} - __CONTAINERS_UPDATE = 0 - - __CONTAINER_CHAINING_UPDATE = 0 - __CONTAINER_CHAINING = {} - - __PDP = {} - __PDP_UPDATE = 0 - - __POLICIES = {} - __POLICIES_UPDATE = 0 - - __MODELS = {} - __MODELS_UPDATE = 0 - - __AUTHZ_REQUESTS = {} - - def update(self, component=None): - self.__update_container() - self.__update_pdp() - self.__update_policies() - self.__update_models() - for key, value in self.__PDP.items(): - LOG.info("Updating container_chaining with {}".format(value["keystone_project_id"])) - self.__update_container_chaining(value["keystone_project_id"]) - - @property - def authz_requests(self): - return self.__AUTHZ_REQUESTS - - def __update_pdp(self): - pdp = call("moon_manager", method="get_pdp", ctx={"user_id": "admin"}, args={}) - if not pdp["pdps"]: - LOG.info("Updating PDP through master") - pdp = call("moon_manager", method="get_pdp", - ctx={ - "user_id": "admin", - 'call_master': True - }, - args={}) - for _pdp in pdp["pdps"].values(): - if _pdp['keystone_project_id'] not in self.__CONTAINER_CHAINING: - self.__CONTAINER_CHAINING[_pdp['keystone_project_id']] = {} - # Note (asteroide): force update of chaining - self.__update_container_chaining(_pdp['keystone_project_id']) - for key, value in pdp["pdps"].items(): - self.__PDP[key] = value - - @property - def pdp(self): - current_time = time.time() - if self.__PDP_UPDATE + self.__UPDATE_INTERVAL < current_time: - self.__update_pdp() - self.__PDP_UPDATE = current_time - return self.__PDP - - def __update_policies(self): - policies = call("moon_manager", method="get_policies", ctx={"user_id": "admin"}, args={}) - for key, value in policies["policies"].items(): - self.__POLICIES[key] = value - - @property - def policies(self): - current_time = time.time() - if self.__POLICIES_UPDATE + self.__UPDATE_INTERVAL < current_time: - self.__update_policies() - self.__POLICIES_UPDATE = current_time - return self.__POLICIES - - def __update_models(self): - models = call("moon_manager", method="get_models", ctx={"user_id": "admin"}, args={}) - for key, value in models["models"].items(): - self.__MODELS[key] = value - - @property - def models(self): - current_time = time.time() - if self.__MODELS_UPDATE + self.__UPDATE_INTERVAL < current_time: - self.__update_models() - self.__MODELS_UPDATE = current_time - return self.__MODELS - - def __update_container(self): - containers = call("orchestrator", method="get_container", ctx={}, args={}) - for key, value in containers["containers"].items(): - self.__CONTAINERS[key] = value - - @property - def container_chaining(self): - current_time = time.time() - if self.__CONTAINER_CHAINING_UPDATE + self.__UPDATE_INTERVAL < current_time: - for key, value in self.pdp.items(): - self.__update_container_chaining(value["keystone_project_id"]) - self.__CONTAINER_CHAINING_UPDATE = current_time - return self.__CONTAINER_CHAINING - - def __update_container_chaining(self, keystone_project_id): - container_ids = [] - for pdp_id, pdp_value, in CACHE.pdp.items(): - LOG.info("pdp_id, pdp_value = {}, {}".format(pdp_id, pdp_value)) - if pdp_value: - if pdp_value["keystone_project_id"] == keystone_project_id: - for policy_id in pdp_value["security_pipeline"]: - model_id = CACHE.policies[policy_id]['model_id'] - LOG.info("model_id = {}".format(model_id)) - LOG.info("CACHE = {}".format(CACHE.models[model_id])) - for meta_rule_id in CACHE.models[model_id]["meta_rules"]: - LOG.info("CACHE.containers = {}".format(CACHE.containers)) - for container_id, container_values, in CACHE.containers.items(): - LOG.info("container_id, container_values = {}".format(container_id, container_values)) - for container_value in container_values: - LOG.info("container_value[\"meta_rule_id\"] == meta_rule_id = {} {}".format(container_value["meta_rule_id"], meta_rule_id)) - if container_value["meta_rule_id"] == meta_rule_id: - container_ids.append( - { - "container_id": container_value["container_id"], - "genre": container_value["genre"] - } - ) - break - self.__CONTAINER_CHAINING[keystone_project_id] = container_ids - - @property - def containers(self): - """intra_extensions cache - example of content : - { - "pdp_uuid1": "component_uuid1", - "pdp_uuid2": "component_uuid2", - } - :return: - """ - current_time = time.time() - if self.__CONTAINERS_UPDATE + self.__UPDATE_INTERVAL < current_time: - self.__update_container() - self.__CONTAINERS_UPDATE = current_time - return self.__CONTAINERS - - -CACHE = Cache() - - -class AuthzRequest: - - result = None - req_max_delay = 2 - - def __init__(self, ctx, args): - self.ctx = ctx - self.args = args - self.request_id = ctx["request_id"] - if self.ctx['id'] not in CACHE.container_chaining: - LOG.warning("Unknown Project ID {}".format(self.ctx['id'])) - # TODO (asteroide): add a better exception handler - raise Exception("Unknown Project ID {}".format(self.ctx['id'])) - self.container_chaining = CACHE.container_chaining[self.ctx['id']] - ctx["container_chaining"] = copy.deepcopy(self.container_chaining) - LOG.info("self.container_chaining={}".format(self.container_chaining)) - self.pdp_container = self.container_chaining[0]["container_id"] - self.run() - - def run(self): - notify(request_id=self.request_id, container_id=self.pdp_container, payload=self.ctx) - cpt = 0 - while cpt < self.req_max_delay*10: - time.sleep(0.1) - cpt += 1 - if CACHE.authz_requests[self.request_id]: - self.result = CACHE.authz_requests[self.request_id] - return - LOG.warning("Request {} has timed out".format(self.request_id)) - - def is_authz(self): - if not self.result: - return False - authz_results = [] - for key in self.result["pdp_set"]: - if "effect" in self.result["pdp_set"][key]: - if self.result["pdp_set"][key]["effect"] == "grant": - # the pdp is a authorization PDP and grant the request - authz_results.append(True) - elif self.result["pdp_set"][key]["effect"] == "passed": - # the pdp is not a authorization PDP (session or delegation) and had run normally - authz_results.append(True) - elif self.result["pdp_set"][key]["effect"] == "unset": - # the pdp is not a authorization PDP (session or delegation) and had not yep run - authz_results.append(True) - else: - # the pdp is (or not) a authorization PDP and had run badly - authz_results.append(False) - if list(itertools.accumulate(authz_results, lambda x, y: x & y))[-1]: - self.result["pdp_set"]["effect"] = "grant" - if self.result: - if "pdp_set" in self.result and self.result["pdp_set"]["effect"] == "grant": - return True - return False - - -class Router(object): - """ - Route requests to all components. - """ - - __version__ = "0.1.0" - cache_requests = {} - slave_name = "" - - def __init__(self, add_master_cnx): - self.slave = configuration.get_configuration(configuration.SLAVE)["slave"] - try: - self.slave_name = self.slave['name'] - except KeyError: - pass - if self.slave_name and add_master_cnx: - result = call('security_router', method="route", - ctx={ - "name": self.slave_name, - "description": self.slave_name, - "call_master": True, - "method": "add_slave"}, args={}) - if "result" in result and not result["result"]: - LOG.error("An error occurred when sending slave name {} {}".format( - self.slave_name, result - )) - self.slave_id = list(result['slaves'].keys())[0] - result = call('security_router', method="route", - ctx={ - "name": self.slave_name, - "description": self.slave_name, - "call_master": True, - "method": "get_slaves"}, args={}) - if "result" in result and not result["result"]: - LOG.error("An error occurred when receiving slave names {} {}".format( - self.slave_name, result - )) - LOG.info("SLAVES: {}".format(result)) - - def delete(self): - if self.slave_name and self.slave_id: - result = call('security_router', method="route", - ctx={ - "name": self.slave_name, - "description": self.slave_name, - "call_master": True, - "method": "delete_slave", - "id": self.slave_id}, args={}) - if "result" in result and not result["result"]: - LOG.error("An error occurred when sending slave name {} {}".format( - self.slave_name, result - )) - LOG.info("SLAVE CONNECTION ENDED!") - LOG.info(result) - - def check_pdp(self, ctx): - _ctx = copy.deepcopy(ctx) - keystone_id = _ctx.pop('id') - # LOG.info("_ctx {}".format(_ctx)) - ext = call("moon_manager", method="get_pdp", ctx=_ctx, args={}) - # LOG.info("check_pdp {}".format(ext)) - if "error" in ext: - return False - keystone_id_list = map(lambda x: x["keystone_project_id"], ext['pdps'].values()) - if not ext['pdps'] or keystone_id not in keystone_id_list: - if self.slave_name: - _ctx['call_master'] = True - # update from master if exist and test again - LOG.info("Need to update from master {}".format(keystone_id)) - ext = call("moon_manager", method="get_pdp", ctx=_ctx, args={}) - if "error" in ext: - return False - keystone_id_list = map(lambda x: x["keystone_project_id"], ext['pdps'].values()) - if not ext['pdps'] or keystone_id not in keystone_id_list: - return False - else: - # Must update from Master - _ctx["keystone_id"] = keystone_id - _ctx["pdp_id"] = None - _ctx["security_pipeline"] = None - _ctx['call_master'] = False - pdp_value = {} - for pdp_id, pdp_value in ext["pdps"].items(): - if keystone_id == pdp_value["keystone_project_id"]: - _ctx["pdp_id"] = keystone_id - _ctx["security_pipeline"] = pdp_value["security_pipeline"] - break - call("moon_manager", method="update_from_master", ctx=_ctx, args=pdp_value) - CACHE.update() - return True - else: - # return False otherwise - return False - return True - - def send_update(self, api, ctx={}, args={}): - # TODO (asteroide): add threads here - if not self.slave_name: - # Note (asteroide): - # if adding or setting an element: do nothing - # if updating or deleting an element: force deletion in the slave - if "update_" in api or "delete_" in api: - for slave_id, slave_dict in call("orchestrator", method="get_slaves", ctx={}, args={})['slaves'].items(): - LOG.info('send_update slave_id={}'.format(slave_id)) - LOG.info('send_update slave_dict={}'.format(slave_dict)) - ctx['method'] = api.replace("update", "delete") - # TODO (asteroide): force data_id to None to force the deletion in the slave - result = call("security_router_"+slave_dict['name'], method="route", ctx=ctx, args=args) - if "result" in result and not result["result"]: - LOG.error("An error occurred when sending update to {} {}".format( - "security_router_"+slave_dict['name'], result - )) - - def route(self, ctx, args): - """Route the request to the right endpoint - - :param ctx: dictionary depending of the real destination - :param args: dictionary depending of the real destination - :return: dictionary depending of the real destination - """ - LOG.info("Get Route {} {}".format(ctx, args)) - if ctx["method"] == "get_status": - return Status().get_status(ctx=ctx, args=args) - if ctx["method"] == "get_logs": - return Logs().get_logs(ctx=ctx, args=args) - for component in API: - if ctx["method"] in API[component]: - if component == "orchestrator": - return call(component, method=ctx["method"], ctx=ctx, args=args) - if component == "manager": - result = call("moon_manager", method=ctx["method"], ctx=ctx, args=args) - if ctx["method"] == "get_pdp": - _ctx = copy.deepcopy(ctx) - _ctx["call_master"] = True - result2 = call("moon_manager", method=ctx["method"], ctx=_ctx, args=args) - result["pdps"].update(result2["pdps"]) - self.send_update(api=ctx["method"], ctx=ctx, args=args) - return result - if component == "function": - if ctx["method"] == "return_authz": - request_id = ctx["request_id"] - CACHE.authz_requests[request_id] = args - return args - elif self.check_pdp(ctx): - req_id = uuid4().hex - CACHE.authz_requests[req_id] = {} - ctx["request_id"] = req_id - req = AuthzRequest(ctx, args) - # result = copy.deepcopy(req.result) - if req.is_authz(): - return {"authz": True, - "pdp_id": ctx["id"], - "ctx": ctx, "args": args} - return {"authz": False, - "error": {'code': 403, 'title': 'Authz Error', - 'description': "The authz request is refused."}, - "pdp_id": ctx["id"], - "ctx": ctx, "args": args} - return {"result": False, - "error": {'code': 500, 'title': 'Moon Error', - 'description': "Function component not found."}, - "pdp_id": ctx["id"], - "ctx": ctx, "args": args} - - # TODO (asteroide): must raise an exception here ? - return {"result": False, - "error": {'code': 500, 'title': 'Moon Error', 'description': "Endpoint method not found."}, - "intra_extension_id": ctx["id"], - "ctx": ctx, "args": args} - diff --git a/moonv4/moon_router/moon_router/messenger.py b/moonv4/moon_router/moon_router/messenger.py deleted file mode 100644 index 0a377678..00000000 --- a/moonv4/moon_router/moon_router/messenger.py +++ /dev/null @@ -1,69 +0,0 @@ -# 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 oslo_config import cfg -import oslo_messaging -import time -from oslo_log import log as logging -from moon_router.api.generic import Status, Logs -from moon_router.api.route import Router -from moon_utilities.api import APIList -from moon_utilities import configuration - -LOG = logging.getLogger("moon.router.messenger") - - -class Server: - - TOPIC = "security_router" - - def __init__(self, add_master_cnx=False): - slave = configuration.get_configuration(configuration.SLAVE)["slave"] - cfg.CONF.transport_url = self.__get_transport_url() - if add_master_cnx and slave["master"]["url"]: - self.transport = oslo_messaging.get_transport(cfg.CONF, slave["master"]["url"]) - self.TOPIC = self.TOPIC + "_" + slave["name"] - else: - self.transport = oslo_messaging.get_transport(cfg.CONF) - self.target = oslo_messaging.Target(topic=self.TOPIC, server='server1') - LOG.info("Starting MQ server with topic: {}".format(self.TOPIC)) - self.endpoints = [ - APIList((Status, Logs, Router)), - Status(), - Logs(), - Router(add_master_cnx) - ] - self.server = oslo_messaging.get_rpc_server(self.transport, self.target, self.endpoints, - executor='threading', - access_policy=oslo_messaging.DefaultRPCAccessPolicy) - self.__is_alive = False - - @staticmethod - def __get_transport_url(): - messenger = configuration.get_configuration(configuration.MESSENGER)["messenger"] - return messenger['url'] - - def stop(self): - self.__is_alive = False - self.endpoints[-1].delete() - - def run(self): - try: - self.__is_alive = True - self.server.start() - while True: - if self.__is_alive: - time.sleep(1) - else: - break - except KeyboardInterrupt: - print("Stopping server by crtl+c") - except SystemExit: - print("Stopping server with SystemExit") - print("Stopping server") - - self.server.stop() - self.server.wait() - diff --git a/moonv4/moon_router/moon_router/server.py b/moonv4/moon_router/moon_router/server.py deleted file mode 100644 index 1b2bddee..00000000 --- a/moonv4/moon_router/moon_router/server.py +++ /dev/null @@ -1,63 +0,0 @@ -# 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'. - -import os -import threading -import signal -from oslo_log import log as logging -from moon_utilities import configuration, exceptions -from moon_router.messenger import Server - - -class AsyncServer(threading.Thread): - - def __init__(self, add_master_cnx): - threading.Thread.__init__(self) - self.server = Server(add_master_cnx=add_master_cnx) - - def run(self): - self.server.run() - -LOG = logging.getLogger("moon.router") - -__CWD__ = os.path.dirname(os.path.abspath(__file__)) - -background_threads = [] - - -def stop_thread(): - for _t in background_threads: - _t.stop() - - -def main(): - global background_threads - configuration.init_logging() - try: - conf = configuration.get_configuration("components/router") - except exceptions.ConsulComponentNotFound: - conf = configuration.add_component("router", "router") - signal.signal(signal.SIGALRM, stop_thread) - signal.signal(signal.SIGTERM, stop_thread) - signal.signal(signal.SIGABRT, stop_thread) - background_master = None - slave = configuration.get_configuration(configuration.SLAVE)["slave"] - if slave['name']: - background_master = AsyncServer(add_master_cnx=True) - background_threads.append(background_master) - background_slave = AsyncServer(add_master_cnx=False) - background_threads.append(background_slave) - if slave['name']: - background_master.start() - LOG.info("Connecting to master...") - background_slave.start() - LOG.info("Starting main server {}".format(conf["components/router"]["hostname"])) - if slave['name']: - background_master.join() - background_slave.join() - - -if __name__ == '__main__': - main() diff --git a/moonv4/moon_router/tests/moon_db-0.1.0.tar.gz b/moonv4/moon_router/tests/moon_db-0.1.0.tar.gz Binary files differdeleted file mode 100644 index 14df1d47..00000000 --- a/moonv4/moon_router/tests/moon_db-0.1.0.tar.gz +++ /dev/null diff --git a/moonv4/moon_router/tests/moon_policy-0.1.0.tar.gz b/moonv4/moon_router/tests/moon_policy-0.1.0.tar.gz Binary files differdeleted file mode 100644 index d3246532..00000000 --- a/moonv4/moon_router/tests/moon_policy-0.1.0.tar.gz +++ /dev/null diff --git a/moonv4/moon_utilities/Changelog b/moonv4/moon_utilities/Changelog index e39a8b53..952c2aa1 100644 --- a/moonv4/moon_utilities/Changelog +++ b/moonv4/moon_utilities/Changelog @@ -35,3 +35,31 @@ CHANGES ----- - Add authentication features for interface +1.3.0 +----- +- Add cache functionality + +1.3.1 +----- +- Delete Oslo config possibilities + +1.3.2 +----- +- Delete Oslo logging and config + +1.3.3 +----- +- Update the cache + +1.3.4 +----- +- Fix a bug on the connection between interface and authz + +1.4.0 +----- +- Add a waiting loop when the Keystone server is not currently available + +1.4.1 +----- +- Cleanup moon_utilities code + diff --git a/moonv4/moon_utilities/LICENSE b/moonv4/moon_utilities/LICENSE index 4143aac2..d6456956 100644 --- a/moonv4/moon_utilities/LICENSE +++ b/moonv4/moon_utilities/LICENSE @@ -174,31 +174,29 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/moonv4/moon_utilities/README.md b/moonv4/moon_utilities/README.md new file mode 100644 index 00000000..bbc1d458 --- /dev/null +++ b/moonv4/moon_utilities/README.md @@ -0,0 +1,33 @@ +# Moon Python Utilities Package +This package contains the core module for the Moon project. +It is designed to provide authorization feature to all OpenStack components. + +For any other information, refer to the parent project: + + https://git.opnfv.org/moon + +moon_utilities is a common Python lib for other Moon Python packages + +## Build +### Build Python Package +```bash +cd ${MOON_HOME}/moonv4/moon_utilities +python3 setup.py sdist bdist_wheel +``` + +### Push Python Package to PIP +```bash +cd ${MOON_HOME}/moonv4/moon_utilities +gpg --detach-sign -u "${GPG_ID}" -a dist/moon_utilities-X.Y.Z-py3-none-any.whl +gpg --detach-sign -u "${GPG_ID}" -a dist/moon_utilities-X.Y.Z.tar.gz +twine upload dist/moon_db-X.Y.Z-py3-none-any.whl dist/moon_utilities-X.Y.Z-py3-none-any.whl.asc +twine upload dist/moon_db-X.Y.Z.tar.gz dist/moon_uutilities-X.Y.Z.tar.gz.asc +``` + +## Test +### Python Unit Test +launch Docker for Python unit tests +```bash +cd ${MOON_HOME}/moonv4/moon_utilities +docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest +``` diff --git a/moonv4/moon_utilities/README.rst b/moonv4/moon_utilities/README.rst deleted file mode 100644 index ded4e99a..00000000 --- a/moonv4/moon_utilities/README.rst +++ /dev/null @@ -1,9 +0,0 @@ -Core module for the Moon project -================================ - -This package contains the core module for the Moon project -It is designed to provide authorization features to all OpenStack components. - -For any other information, refer to the parent project: - - https://git.opnfv.org/moon diff --git a/moonv4/moon_utilities/moon_utilities/__init__.py b/moonv4/moon_utilities/moon_utilities/__init__.py index 2c7f8f5c..e3ad9307 100644 --- a/moonv4/moon_utilities/moon_utilities/__init__.py +++ b/moonv4/moon_utilities/moon_utilities/__init__.py @@ -3,4 +3,4 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -__version__ = "1.2.0" +__version__ = "1.4.1" diff --git a/moonv4/moon_utilities/moon_utilities/cache.py b/moonv4/moon_utilities/moon_utilities/cache.py new file mode 100644 index 00000000..8c6ee3bf --- /dev/null +++ b/moonv4/moon_utilities/moon_utilities/cache.py @@ -0,0 +1,543 @@ +import logging +import time +import requests +from uuid import uuid4 +from moon_utilities import configuration, exceptions + +LOG = logging.getLogger("moon.utilities.cache") + + +class Cache(object): + # TODO (asteroide): set cache integer in CONF file + ''' + [NOTE] Propose to define the following variables inside the init method + as defining them out side the init, will be treated as private static variables + and keep tracks with any changes done anywhere + for more info : you can check https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables + ''' + __UPDATE_INTERVAL = 10 + + __CONTAINERS = {} + __CONTAINERS_UPDATE = 0 + + __CONTAINER_CHAINING_UPDATE = 0 + __CONTAINER_CHAINING = {} + + __PDP = {} + __PDP_UPDATE = 0 + + __POLICIES = {} + __POLICIES_UPDATE = 0 + + __MODELS = {} + __MODELS_UPDATE = 0 + + __SUBJECTS = {} + __OBJECTS = {} + __ACTIONS = {} + + __SUBJECT_ASSIGNMENTS = {} + __OBJECT_ASSIGNMENTS = {} + __ACTION_ASSIGNMENTS = {} + + __SUBJECT_CATEGORIES = {} + __SUBJECT_CATEGORIES_UPDATE = 0 + __OBJECT_CATEGORIES = {} + __OBJECT_CATEGORIES_UPDATE = 0 + __ACTION_CATEGORIES = {} + __ACTION_CATEGORIES_UPDATE = 0 + + __META_RULES = {} + __META_RULES_UPDATE = 0 + + __RULES = {} + __RULES_UPDATE = 0 + + __AUTHZ_REQUESTS = {} + + def __init__(self): + self.manager_url = "{}://{}:{}".format( + configuration.get_components()['manager'].get('protocol', 'http'), + configuration.get_components()['manager']['hostname'], + configuration.get_components()['manager']['port'] + ) + self.orchestrator_url = "{}://{}:{}".format( + configuration.get_components()['orchestrator'].get('protocol', 'http'), + configuration.get_components()['orchestrator']['hostname'], + configuration.get_components()['orchestrator']['port'] + ) + + def update(self): + self.__update_container() + self.__update_pdp() + self.__update_policies() + self.__update_models() + for key, value in self.__PDP.items(): + # LOG.info("Updating container_chaining with {}".format(value["keystone_project_id"])) + self.__update_container_chaining(value["keystone_project_id"]) + + @property + def authz_requests(self): + return self.__AUTHZ_REQUESTS + + # perimeter functions + + @property + def subjects(self): + return self.__SUBJECTS + + def update_subjects(self, policy_id=None): + req = requests.get("{}/policies/{}/subjects".format( + self.manager_url, policy_id)) + self.__SUBJECTS[policy_id] = req.json()['subjects'] + + def get_subject(self, policy_id, name): + try: + for _subject_id, _subject_dict in self.__SUBJECTS[policy_id].items(): + if _subject_dict["name"] == name: + return _subject_id + except KeyError: + pass + self.update_subjects(policy_id) + for _subject_id, _subject_dict in self.__SUBJECTS[policy_id].items(): + if _subject_dict["name"] == name: + return _subject_id + raise exceptions.SubjectUnknown("Cannot find subject {}".format(name)) + + @property + def objects(self): + return self.__OBJECTS + + def update_objects(self, policy_id=None): + req = requests.get("{}/policies/{}/objects".format( + self.manager_url, policy_id)) + self.__OBJECTS[policy_id] = req.json()['objects'] + + def get_object(self, policy_id, name): + try: + for _object_id, _object_dict in self.__OBJECTS[policy_id].items(): + if _object_dict["name"] == name: + return _object_id + except KeyError: + pass + self.update_objects(policy_id) + for _object_id, _object_dict in self.__OBJECTS[policy_id].items(): + if _object_dict["name"] == name: + return _object_id + raise exceptions.SubjectUnknown("Cannot find object {}".format(name)) + + @property + def actions(self): + return self.__ACTIONS + + def update_actions(self, policy_id=None): + req = requests.get("{}/policies/{}/actions".format( + self.manager_url, policy_id)) + self.__ACTIONS[policy_id] = req.json()['actions'] + + def get_action(self, policy_id, name): + try: + for _action_id, _action_dict in self.__ACTIONS[policy_id].items(): + if _action_dict["name"] == name: + return _action_id + except KeyError: + pass + self.update_actions(policy_id) + for _action_id, _action_dict in self.__ACTIONS[policy_id].items(): + if _action_dict["name"] == name: + return _action_id + raise exceptions.SubjectUnknown("Cannot find action {}".format(name)) + + # meta_rule functions + + @property + def meta_rules(self): + current_time = time.time() + if self.__META_RULES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_meta_rules() + self.__META_RULES_UPDATE = current_time + return self.__META_RULES + + def __update_meta_rules(self): + req = requests.get("{}/meta_rules".format(self.manager_url)) + self.__META_RULES = req.json()['meta_rules'] + + # rule functions + + @property + def rules(self): + current_time = time.time() + if self.__RULES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_rules() + self.__RULES_UPDATE = current_time + return self.__RULES + + def __update_rules(self): + for policy_id in self.__POLICIES: + LOG.info("Get {}".format("{}/policies/{}/rules".format( + self.manager_url, policy_id))) + req = requests.get("{}/policies/{}/rules".format( + self.manager_url, policy_id)) + self.__RULES[policy_id] = req.json()['rules'] + LOG.info("UPDATE RULES {}".format(self.__RULES)) + + # assignment functions + + @property + def subject_assignments(self): + return self.__SUBJECT_ASSIGNMENTS + + def update_subject_assignments(self, policy_id=None, perimeter_id=None): + if perimeter_id: + req = requests.get("{}/policies/{}/subject_assignments/{}".format( + self.manager_url, policy_id, perimeter_id)) + else: + req = requests.get("{}/policies/{}/subject_assignments".format( + self.manager_url, policy_id)) + if policy_id not in self.__SUBJECT_ASSIGNMENTS: + self.__SUBJECT_ASSIGNMENTS[policy_id] = {} + self.__SUBJECT_ASSIGNMENTS[policy_id].update( + req.json()['subject_assignments']) + + def get_subject_assignments(self, policy_id, perimeter_id, category_id): + if policy_id not in self.subject_assignments: + self.update_subject_assignments(policy_id, perimeter_id) + ''' + [NOTE] invalid condition for testing existence of policy_id + because update_subject_assignments function already add an empty object + with the given policy_id and then assign the response to it + as mentioned in these lines of code (line 191,192) + + Note: the same condition applied for the object,action assignment + line 234, 260 + ''' + if policy_id not in self.subject_assignments: + raise Exception("Cannot found the policy {}".format(policy_id)) + for key, value in self.subject_assignments[policy_id].items(): + if perimeter_id == value['subject_id'] and category_id == value['category_id']: + return value['assignments'] + return [] + + @property + def object_assignments(self): + return self.__OBJECT_ASSIGNMENTS + + def update_object_assignments(self, policy_id=None, perimeter_id=None): + if perimeter_id: + req = requests.get("{}/policies/{}/object_assignments/{}".format( + self.manager_url, policy_id, perimeter_id)) + else: + req = requests.get("{}/policies/{}/object_assignments".format( + self.manager_url, policy_id)) + if policy_id not in self.__OBJECT_ASSIGNMENTS: + self.__OBJECT_ASSIGNMENTS[policy_id] = {} + self.__OBJECT_ASSIGNMENTS[policy_id].update( + req.json()['object_assignments']) + + def get_object_assignments(self, policy_id, perimeter_id, category_id): + if policy_id not in self.object_assignments: + self.update_object_assignments(policy_id, perimeter_id) + if policy_id not in self.object_assignments: + raise Exception("Cannot found the policy {}".format(policy_id)) + for key, value in self.object_assignments[policy_id].items(): + if perimeter_id == value['object_id'] and category_id == value['category_id']: + return value['assignments'] + return [] + + @property + def action_assignments(self): + return self.__ACTION_ASSIGNMENTS + + def update_action_assignments(self, policy_id=None, perimeter_id=None): + if perimeter_id: + req = requests.get("{}/policies/{}/action_assignments/{}".format( + self.manager_url, policy_id, perimeter_id)) + else: + req = requests.get("{}/policies/{}/action_assignments".format( + self.manager_url, policy_id)) + if policy_id not in self.__ACTION_ASSIGNMENTS: + self.__ACTION_ASSIGNMENTS[policy_id] = {} + self.__ACTION_ASSIGNMENTS[policy_id].update( + req.json()['action_assignments']) + + def get_action_assignments(self, policy_id, perimeter_id, category_id): + if policy_id not in self.action_assignments: + self.update_action_assignments(policy_id, perimeter_id) + if policy_id not in self.action_assignments: + raise Exception("Cannot found the policy {}".format(policy_id)) + for key, value in self.action_assignments[policy_id].items(): + if perimeter_id == value['action_id'] and category_id == value['category_id']: + return value['assignments'] + return [] + + # category functions + + @property + def subject_categories(self): + current_time = time.time() + if self.__SUBJECT_CATEGORIES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_subject_categories() + self.__SUBJECT_CATEGORIES_UPDATE = current_time + return self.__SUBJECT_CATEGORIES + + def __update_subject_categories(self): + req = requests.get("{}/policies/subject_categories".format( + self.manager_url)) + self.__SUBJECT_CATEGORIES.update(req.json()['subject_categories']) + + @property + def object_categories(self): + current_time = time.time() + if self.__OBJECT_CATEGORIES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_object_categories() + self.__OBJECT_CATEGORIES_UPDATE = current_time + return self.__OBJECT_CATEGORIES + + def __update_object_categories(self): + req = requests.get("{}/policies/object_categories".format( + self.manager_url)) + self.__OBJECT_CATEGORIES.update(req.json()['object_categories']) + + @property + def action_categories(self): + current_time = time.time() + if self.__ACTION_CATEGORIES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_action_categories() + self.__ACTION_CATEGORIES_UPDATE = current_time + return self.__ACTION_CATEGORIES + + def __update_action_categories(self): + req = requests.get("{}/policies/action_categories".format( + self.manager_url)) + self.__ACTION_CATEGORIES.update(req.json()['action_categories']) + + # PDP functions + + def __update_pdp(self): + req = requests.get("{}/pdp".format(self.manager_url)) + pdp = req.json() + for _pdp in pdp["pdps"].values(): + if _pdp['keystone_project_id'] not in self.__CONTAINER_CHAINING: + self.__CONTAINER_CHAINING[_pdp['keystone_project_id']] = {} + # Note (asteroide): force update of chaining + self.__update_container_chaining(_pdp['keystone_project_id']) + for key, value in pdp["pdps"].items(): + self.__PDP[key] = value + + @property + def pdp(self): + """Policy Decision Point + Example of content: + { + "pdp_id": { + "keystone_project_id": "keystone_project_id", + "name": "pdp1", + "description": "test", + "security_pipeline": [ + "policy_id" + ] + } + } + + :return: + """ + current_time = time.time() + if self.__PDP_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_pdp() + self.__PDP_UPDATE = current_time + return self.__PDP + + # policy functions + def __update_policies(self): + req = requests.get("{}/policies".format(self.manager_url)) + policies = req.json() + for key, value in policies["policies"].items(): + self.__POLICIES[key] = value + + @property + def policies(self): + current_time = time.time() + if self.__POLICIES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_policies() + self.__POLICIES_UPDATE = current_time + return self.__POLICIES + + # model functions + + def __update_models(self): + req = requests.get("{}/models".format(self.manager_url)) + models = req.json() + for key, value in models["models"].items(): + self.__MODELS[key] = value + + @property + def models(self): + current_time = time.time() + if self.__MODELS_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_models() + self.__MODELS_UPDATE = current_time + return self.__MODELS + + # helper functions + + def get_policy_from_meta_rules(self, meta_rule_id): + for pdp_key, pdp_value in self.pdp.items(): + for policy_id in pdp_value["security_pipeline"]: + model_id = self.policies[policy_id]["model_id"] + if meta_rule_id in self.models[model_id]["meta_rules"]: + return policy_id + + def get_pdp_from_keystone_project(self, keystone_project_id): + for pdp_key, pdp_value in self.pdp.items(): + if keystone_project_id == pdp_value["keystone_project_id"]: + return pdp_key + + def get_keystone_project_id_from_policy_id(self, policy_id): + for pdp_key, pdp_value in self.pdp.items(): + if policy_id in pdp_value["security_pipeline"]: + return pdp_value["keystone_project_id"] + # for policy_id in pdp_value["security_pipeline"]: + # model_id = self.policies[policy_id]["model_id"] + # if meta_rule_id in self.models[model_id]["meta_rules"]: + # return pdp_value["keystone_project_id"] + + def get_containers_from_keystone_project_id(self, keystone_project_id, + meta_rule_id=None): + for container_id, container_values in self.containers.items(): + for container_value in container_values: + if 'keystone_project_id' not in container_value: + continue + if container_value['keystone_project_id'] == keystone_project_id: + if not meta_rule_id: + yield container_id, container_value + elif container_value.get('meta_rule_id') == meta_rule_id: + yield container_id, container_value + break + + # containers functions + + def __update_container(self): + req = requests.get("{}/pods".format(self.orchestrator_url)) + pods = req.json() + for key, value in pods["pods"].items(): + # if key not in self.__CONTAINERS: + self.__CONTAINERS[key] = value + # else: + # for container in value: + # self.__CONTAINERS[key].update(value) + + def add_container(self, container_data): + """Add a new container in the cache + + :param container_data: dictionary with information for the container + Example: + { + "name": name, + "hostname": name, + "port": { + "PrivatePort": tcp_port, + "Type": "tcp", + "IP": "0.0.0.0", + "PublicPort": tcp_port + }, + "keystone_project_id": uuid, + "pdp_id": self.CACHE.get_pdp_from_keystone_project(uuid), + "meta_rule_id": meta_rule_id, + "container_name": container_name, + "plugin_name": plugin_name + "container_id": "container_id" + } + + :return: + """ + self.__CONTAINERS[uuid4().hex] = { + "keystone_project_id": container_data['keystone_project_id'], + "name": container_data['name'], + "container_id": container_data['container_id'], + "hostname": container_data['name'], + "policy_id": container_data['policy_id'], + "meta_rule_id": container_data['meta_rule_id'], + "port": [ + { + "PublicPort": container_data['port']["PublicPort"], + "Type": container_data['port']["Type"], + "IP": container_data['port']["IP"], + "PrivatePort": container_data['port']["PrivatePort"] + } + ], + "genre": container_data['plugin_name'] + } + self.__update_container_chaining(self.get_keystone_project_id_from_policy_id(container_data['policy_id'])) + + @property + def containers(self): + """Containers cache + example of content : + { + "policy_uuid1": "component_hostname1", + "policy_uuid2": "component_hostname2", + } + :return: + """ + current_time = time.time() + if self.__CONTAINERS_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_container() + self.__CONTAINERS_UPDATE = current_time + return self.__CONTAINERS + + @property + def container_chaining(self): + """Cache for mapping Keystone Project ID with meta_rule ID and container ID + Example of content: + { + "keystone_project_id": [ + { + "container_id": "container_id", + "genre": "genre", + "policy_id": "policy_id", + "meta_rule_id": "meta_rule_id", + } + ] + } + + :return: + """ + current_time = time.time() + if self.__CONTAINER_CHAINING_UPDATE + self.__UPDATE_INTERVAL < current_time: + for key, value in self.pdp.items(): + if not value["keystone_project_id"]: + continue + self.__update_container_chaining(value["keystone_project_id"]) + self.__CONTAINER_CHAINING_UPDATE = current_time + LOG.info(self.__CONTAINER_CHAINING_UPDATE) + return self.__CONTAINER_CHAINING + + def __update_container_chaining(self, keystone_project_id): + container_ids = [] + for pdp_id, pdp_value, in self.__PDP.items(): + if pdp_value: + if pdp_value["keystone_project_id"] == keystone_project_id: + for policy_id in pdp_value["security_pipeline"]: + model_id = self.__POLICIES[policy_id]['model_id'] + for meta_rule_id in self.__MODELS[model_id]["meta_rules"]: + for container_id, container_value in self.get_containers_from_keystone_project_id( + keystone_project_id, + meta_rule_id + ): + _raw = requests.get("{}/pods/{}".format( + self.orchestrator_url, container_value["name"]) + ) + LOG.debug("_raw={}".format(_raw.text)) + container_ids.append( + { + "container_id": container_value["name"], + "genre": container_value["genre"], + "policy_id": policy_id, + "meta_rule_id": meta_rule_id, + "hostname": container_value["name"], + "hostip": "127.0.0.1", + "port": container_value["port"], + } + ) + self.__CONTAINER_CHAINING[keystone_project_id] = container_ids + diff --git a/moonv4/moon_utilities/moon_utilities/configuration.py b/moonv4/moon_utilities/moon_utilities/configuration.py index 32eeff13..cda75de5 100644 --- a/moonv4/moon_utilities/moon_utilities/configuration.py +++ b/moonv4/moon_utilities/moon_utilities/configuration.py @@ -4,15 +4,11 @@ # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -import copy import base64 import json import requests import logging import logging.config -# from oslo_log import log as logging -from oslo_config import cfg -# import oslo_messaging from moon_utilities import exceptions LOG = logging.getLogger("moon.utilities") @@ -21,8 +17,6 @@ CONSUL_HOST = "consul" CONSUL_PORT = "8500" DATABASE = "database" -SLAVE = "slave" -MESSENGER = "messenger" KEYSTONE = "keystone" DOCKER = "docker" COMPONENTS = "components" @@ -33,11 +27,6 @@ def init_logging(): logging.config.dictConfig(config['logging']) -def init_oslo_config(): - cfg.CONF.transport_url = get_configuration("messenger")['messenger']['url'] - cfg.CONF.rpc_response_timeout = 5 - - def increment_port(): components_port_start = int(get_configuration("components_port_start")['components_port_start']) components_port_start += 1 @@ -53,8 +42,8 @@ def get_configuration(key): url = "http://{}:{}/v1/kv/{}".format(CONSUL_HOST, CONSUL_PORT, key) req = requests.get(url) if req.status_code != 200: - LOG.info("url={}".format(url)) - raise exceptions.ConsulComponentNotFound + LOG.error("url={}".format(url)) + raise exceptions.ConsulComponentNotFound("error={}: {}".format(req.status_code, req.text)) data = req.json() if len(data) == 1: data = data[0] @@ -123,4 +112,3 @@ def get_components(): init_logging() -init_oslo_config() diff --git a/moonv4/moon_utilities/moon_utilities/exceptions.py b/moonv4/moon_utilities/moon_utilities/exceptions.py index ba5ecf46..eb606432 100644 --- a/moonv4/moon_utilities/moon_utilities/exceptions.py +++ b/moonv4/moon_utilities/moon_utilities/exceptions.py @@ -138,26 +138,6 @@ class ModelExisting(MoonError): logger = "Error" -class RootExtensionUnknown(IntraExtensionUnknown): - description = _("The root_extension is unknown.") - code = 400 - title = 'Root Extension Unknown' - logger = "Error" - - -class RootPDPNotInitialized(IntraExtensionException): - description = _("The root_extension is not initialized.") - code = 400 - title = 'Root Extension Not Initialized' - logger = "Error" - - -class IntraExtensionCreationError(IntraExtensionException): - description = _("The arguments for the creation of this Extension were malformed.") - code = 400 - title = 'Intra Extension Creation Error' - - # Authz exceptions class AuthzException(MoonError): diff --git a/moonv4/moon_utilities/moon_utilities/get_os_apis.py b/moonv4/moon_utilities/moon_utilities/get_os_apis.py deleted file mode 100644 index dea2a878..00000000 --- a/moonv4/moon_utilities/moon_utilities/get_os_apis.py +++ /dev/null @@ -1,122 +0,0 @@ -import json -import logging -import requests -import argparse - -URLS = { - "keystone": "https://api.github.com/repos/openstack/keystone/contents/api-ref/source/v3", - "nova": "https://api.github.com/repos/openstack/nova/contents/api-ref/source", - "neutron": "https://api.github.com/repos/openstack/neutron-lib/contents/api-ref/source/v2", - "glance": "https://api.github.com/repos/openstack/glance/contents/api-ref/source/v2", - "swift": "https://api.github.com/repos/openstack/swift/contents/api-ref/source", - "cinder": "https://api.github.com/repos/openstack/cinder/contents/api-ref/source/v3", - -} - -logger = None - -USER = "" -PASS = "" - - -def init(): - global logger, USER, PASS - parser = argparse.ArgumentParser() - parser.add_argument("--verbose", "-v", action='store_true', help="verbose mode") - parser.add_argument("--debug", "-d", action='store_true', help="debug mode") - parser.add_argument("--format", "-f", help="Output format (txt, json)", default="json") - parser.add_argument("--output", "-o", help="Output filename") - parser.add_argument("--credentials", "-c", help="Github credential filename (inside format user:pass)") - args = parser.parse_args() - - FORMAT = '%(levelname)s %(message)s' - - if args.verbose: - logging.basicConfig( - format=FORMAT, - level=logging.INFO) - elif args.debug: - logging.basicConfig( - format=FORMAT, - level=logging.DEBUG) - else: - logging.basicConfig( - format=FORMAT, - level=logging.WARNING) - - if args.credentials: - cred = open(args.credentials).read() - USER = cred.split(":")[0] - PASS = cred.split(":")[1] - - logger = logging.getLogger(__name__) - - return args - - -def get_api_item(url): - if USER: - r = requests.get(url, auth=(USER, PASS)) - else: - r = requests.get(url) - items = [] - for line in r.text.splitlines(): - if ".. rest_method::" in line: - items.append(line.replace(".. rest_method::", "").strip()) - logger.debug("\n\t".join(items)) - return items - - -def get_content(key, args): - logger.info("Analysing {}".format(key)) - if USER: - r = requests.get(URLS[key], auth=(USER, PASS)) - else: - r = requests.get(URLS[key]) - data = r.json() - results = {} - for item in data: - try: - logger.debug("{} {}".format(item['name'], item['download_url'])) - if item['type'] == "file" and ".inc" in item['name']: - results[item['name'].replace(".inc", "")] = get_api_item(item['download_url']) - except TypeError: - logger.error("Error with {}".format(item)) - except requests.exceptions.MissingSchema: - logger.error("MissingSchema error {}".format(item)) - return results - - -def to_str(results): - output = "" - for key in results: - output += "{}\n".format(key) - for item in results[key]: - output += "\t{}\n".format(item) - for value in results[key][item]: - output += "\t\t{}\n".format(value) - return output - - -def save(results, args): - if args.output: - if args.format == 'json': - json.dump(results, open(args.output, "w"), indent=4) - elif args.format == 'txt': - open(args.output, "w").write(to_str(results)) - else: - if args.format == 'json': - print(json.dumps(results, indent=4)) - elif args.format in ('txt', 'text'): - print(to_str(results)) - - -def main(): - args = init() - results = {} - for key in URLS: - results[key] = get_content(key, args) - save(results, args) - -if __name__ == "__main__": - main()
\ No newline at end of file diff --git a/moonv4/moon_utilities/moon_utilities/misc.py b/moonv4/moon_utilities/moon_utilities/misc.py index d13b4511..b83523c3 100644 --- a/moonv4/moon_utilities/moon_utilities/misc.py +++ b/moonv4/moon_utilities/moon_utilities/misc.py @@ -4,28 +4,18 @@ # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -import os -import re -import types -import requests -from oslo_log import log as logging -from oslo_config import cfg -import oslo_messaging -from moon_utilities import exceptions -from oslo_config.cfg import ConfigOpts +import logging +import random LOG = logging.getLogger(__name__) -CONF = cfg.CONF def get_uuid_from_name(name, elements, **kwargs): - LOG.error("get_uuid_from_name {} {} {}".format(name, elements, kwargs)) for element in elements: if type(elements[element]) is dict and elements[element].get('name') == name: if kwargs: for args in kwargs: if elements[element].get(args) != kwargs[args]: - LOG.error("get_uuid_from_name2 {} {} {}".format(args, elements[element].get(args), kwargs[args])) return else: return element @@ -45,3 +35,108 @@ def get_name_from_uuid(uuid, elements, **kwargs): else: return elements[element].get('name') + +def get_random_name(): + _list = ( + "windy", + "vengeful", + "precious", + "vivacious", + "quiet", + "confused", + "exultant", + "impossible", + "thick", + "obsolete", + "piquant", + "fanatical", + "tame", + "perfect", + "animated", + "dark", + "stimulating", + "drunk", + "depressed", + "fumbling", + "like", + "undesirable", + "spurious", + "subsequent", + "spiteful", + "last", + "stale", + "hulking", + "giddy", + "minor", + "careful", + "possessive", + "gullible", + "fragile", + "divergent", + "ill-informed", + "false", + "jumpy", + "damaged", + "likeable", + "volatile", + "handsomely", + "wet", + "long-term", + "pretty", + "taboo", + "normal", + "magnificent", + "nutty", + "puzzling", + "small", + "kind", + "devilish", + "chubby", + "paltry", + "cultured", + "old", + "defective", + "hanging", + "innocent", + "jagged", + "economic", + "good", + "sulky", + "real", + "bent", + "shut", + "furry", + "terrific", + "hollow", + "terrible", + "mammoth", + "pleasant", + "scared", + "obnoxious", + "absorbing", + "imported", + "infamous", + "grieving", + "ill-fated", + "mighty", + "handy", + "comfortable", + "astonishing", + "brown", + "assorted", + "wrong", + "unsightly", + "spooky", + "delightful", + "acid", + "inconclusive", + "mere", + "careless", + "historical", + "flashy", + "squealing", + "quarrelsome", + "empty", + "long", + ) + return random.choice(_list) diff --git a/moonv4/moon_utilities/moon_utilities/options.py b/moonv4/moon_utilities/moon_utilities/options.py deleted file mode 100644 index 8b8ccca4..00000000 --- a/moonv4/moon_utilities/moon_utilities/options.py +++ /dev/null @@ -1,300 +0,0 @@ -# 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'. - -import os -import sys -from oslo_config import cfg -from oslo_log import log as logging -from moon_utilities import __version__ - -LOG = logging.getLogger(__name__) -CONF = cfg.CONF - -__CWD__ = os.path.dirname(os.path.abspath(__file__)) - - -def configure(domain="moon", version=__version__, usage=""): - # FIXME (dthom): put DEBUG as default log level doesn't work - extra_log_level_defaults = [ - '{}=DEBUG'.format(__name__), - ] - # LOG.setLevel(logging.DEBUG) - logging.set_defaults( - default_log_levels=logging.get_default_log_levels() + extra_log_level_defaults) - - logging.register_options(CONF) - logging.setup(CONF, domain) - - CONF.register_opts(get_opts()) - - # rabbit_group = cfg.OptGroup(name='messenger', - # title='Messenger options') - # CONF.register_group(rabbit_group) - # CONF.register_opts(get_messenger_opts(), group="messenger") - - slave_group = cfg.OptGroup(name='slave', - title='Messenger options') - CONF.register_group(slave_group) - CONF.register_opts(get_slave_opts(), group="slave") - - database_group = cfg.OptGroup(name='database', - title='Database options') - CONF.register_group(database_group) - CONF.register_opts(get_database_opts(), group="database") - - database_configuration_group = cfg.OptGroup(name='database_configuration', - title='Database configuration options') - CONF.register_group(database_configuration_group) - CONF.register_opts(get_database_configuration_opts(), group="database_configuration") - - orchestrator_group = cfg.OptGroup(name='orchestrator', - title='Orchestrator options') - CONF.register_group(orchestrator_group) - CONF.register_opts(get_orchestrator_opts(), group="orchestrator") - - secrouter_group = cfg.OptGroup(name='security_router', - title='Security Router options') - CONF.register_group(secrouter_group) - CONF.register_opts(get_security_router_opts(), group="security_router") - - manager_group = cfg.OptGroup(name='security_manager', - title='Manager options') - CONF.register_group(manager_group) - CONF.register_opts(get_manager_opts(), group="security_manager") - - secpolicy_group = cfg.OptGroup(name='security_policy', - title='Security policy options') - CONF.register_group(secpolicy_group) - CONF.register_opts(get_security_policy_opts(), group="security_policy") - - secfunction_group = cfg.OptGroup(name='security_function', - title='Security function options') - CONF.register_group(secfunction_group) - CONF.register_opts(get_security_function_opts(), group="security_function") - - interface_group = cfg.OptGroup(name='interface', - title='Interface options') - CONF.register_group(interface_group) - CONF.register_opts(get_interface_opts(), group="interface") - - keystone_group = cfg.OptGroup(name='keystone', - title='Keystone options') - CONF.register_group(keystone_group) - CONF.register_opts(get_keystone_opts(), group="keystone") - - filename = "moon.conf" - for _filename in ( - "/etc/moon/{}", - "conf/{}", - "../conf/{}", - ): - try: - default_config_files = (_filename.format(filename), ) - CONF(args=sys.argv[1:], - project=domain, - # version=pbr.version.VersionInfo('keystone').version_string(), - version=version, - usage=usage, - default_config_files=default_config_files) - except cfg.ConfigFilesNotFoundError: - continue - else: - LOG.info("Using {} configuration file".format(_filename.format(filename))) - return _filename.format(filename) - - -def get_opts(): - return [ - cfg.StrOpt('proxy', - default="", - help='Proxy server to use'), - cfg.StrOpt('dist_dir', - default="", - help='Directory where the python packages can be found'), - cfg.StrOpt('plugin_dir', - default="", - help='Directory where the python plugins can be found'), - cfg.StrOpt('docker_url', - default="unix://var/run/docker.sock", - help='Docker URL to connect to.'), - cfg.StrOpt('policy_directory', - default="/etc/moon/policies", - help='Directory containing all the intra-extension templates'), - cfg.StrOpt('root_policy_directory', - default="/etc/moon/policies/policy_root", - help='Directory containing the Root intra-extension template'), - cfg.StrOpt('master', - default="", - help='URL of the Moon Master'), - cfg.StrOpt('master_login', - default="", - help='Login to log into the Moon Master'), - cfg.StrOpt('master_password', - default="", - help='Password for the Moon Master'), - ] - - -# def get_messenger_opts(): -# return [ -# cfg.StrOpt('host', -# default="0.0.0.0", -# help='RabbitMQ server name or IP.'), -# cfg.IntOpt('port', -# default=8800, -# help='RabbitMQ server port.'), -# ] - - -def get_orchestrator_opts(): - return [ - cfg.StrOpt('host', - default="127.0.0.1", - help='Host binding'), - cfg.IntOpt('port', - default=38000, - help='Port number of the server'), - ] - - -def get_slave_opts(): - return [ - cfg.StrOpt('slave_name', - default="", - help='name of the slave'), - cfg.StrOpt('master_url', - default="", - help='URL of the RabbitMQ bus of the Master, ' - 'example: master_url=rabbit://moon:p4sswOrd1@messenger:5672/moon'), - cfg.StrOpt('master_login', - default="", - help='login name of the master administrator, example: master_login=admin'), - cfg.StrOpt('master_password', - default="", - help='password of the master administrator, example: master_password=XXXXXXX'), - ] - - -def get_security_router_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - cfg.StrOpt('host', - default="127.0.0.1", - help='Host binding'), - cfg.IntOpt('port', - default=38001, - help='Port number of the server'), - ] - - -def get_manager_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - cfg.StrOpt('host', - default="127.0.0.1", - help='Host binding'), - cfg.IntOpt('port', - default=38001, - help='Port number of the server'), - ] - - -def get_security_policy_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - ] - - -def get_security_function_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - ] - - -def get_interface_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - cfg.StrOpt('host', - default="127.0.0.1", - help='Host binding'), - cfg.IntOpt('port', - default=38002, - help='Port number of the server'), - ] - - -def get_database_opts(): - return [ - cfg.StrOpt('url', - default="mysql+pymysql://moonuser:password@localhost/moon", - help='URL of the database'), - cfg.StrOpt('driver', - default="sql", - help='Driver binding'), - ] - - -def get_database_configuration_opts(): - return [ - cfg.StrOpt('url', - default="", - help='URL of the database'), - cfg.StrOpt('driver', - default="memory", - help='Driver binding'), - ] - - -def get_keystone_opts(): - return [ - cfg.StrOpt('url', - default="http://localhost:35357", - help='URL of the Keystone manager.'), - cfg.StrOpt('user', - default="admin", - help='Username of the Keystone manager.'), - cfg.StrOpt('password', - default="nomoresecrete", - help='Password of the Keystone manager.'), - cfg.StrOpt('project', - default="admin", - help='Project used to connect to the Keystone manager.'), - cfg.StrOpt('domain', - default="Default", - help='Default domain for the Keystone manager.'), - cfg.StrOpt('check_token', - default="true", - help='If true, yes or strict, always check Keystone tokens against the server'), - cfg.StrOpt('server_crt', - default="", - help='If using Keystone in HTTPS mode, give a certificate filename here'), - ] - -filename = configure() - - -def get_docker_template_dir(templatename="template.dockerfile"): - path = os.path.dirname(os.path.abspath(filename)) - PATHS = ( - path, - os.path.join(path, "dockers"), - "/etc/moon/" - "~/.moon/" - ) - for _path in PATHS: - if os.path.isfile(os.path.join(_path, templatename)): - return _path - raise Exception("Configuration error, cannot find docker template in {}".format(PATHS)) - diff --git a/moonv4/moon_utilities/moon_utilities/security_functions.py b/moonv4/moon_utilities/moon_utilities/security_functions.py index ad1a44fa..50ab4daf 100644 --- a/moonv4/moon_utilities/moon_utilities/security_functions.py +++ b/moonv4/moon_utilities/moon_utilities/security_functions.py @@ -12,28 +12,14 @@ import requests import time from functools import wraps from flask import request -from oslo_log import log as logging -from oslo_config import cfg -import oslo_messaging +import logging from moon_utilities import exceptions from moon_utilities import configuration LOG = logging.getLogger("moon.utilities." + __name__) -CONF = cfg.CONF keystone_config = configuration.get_configuration("openstack/keystone")["openstack/keystone"] -slave = configuration.get_configuration(configuration.SLAVE)["slave"] - -__transport_master = oslo_messaging.get_transport(cfg.CONF, slave.get("master_url")) -__transport = oslo_messaging.get_transport(CONF) - -__n_transport = oslo_messaging.get_notification_transport(CONF) -__n_notifier = oslo_messaging.Notifier(__n_transport, - 'router.host', - driver='messagingv2', - topics=['authz-workers']) -__n_notifier = __n_notifier.prepare(publisher_id='router') - +TOKENS = {} __targets = {} @@ -111,6 +97,7 @@ def enforce(action_names, object_name, **extra): def login(user=None, password=None, domain=None, project=None, url=None): + start_time = time.time() if not user: user = keystone_config['user'] if not password: @@ -151,15 +138,19 @@ def login(user=None, password=None, domain=None, project=None, url=None): } } - req = requests.post("{}/auth/tokens".format(url), - json=data_auth, headers=headers, - verify=keystone_config['certificate']) - - if req.status_code in (200, 201, 204): - headers['X-Auth-Token'] = req.headers['X-Subject-Token'] - return headers - LOG.error(req.text) - raise exceptions.KeystoneError + while True: + req = requests.post("{}/auth/tokens".format(url), + json=data_auth, headers=headers, + verify=keystone_config['certificate']) + + if req.status_code in (200, 201, 204): + headers['X-Auth-Token'] = req.headers['X-Subject-Token'] + return headers + LOG.warning("Waiting for Keystone...") + if time.time() - start_time == 100: + LOG.error(req.text) + raise exceptions.KeystoneError + time.sleep(5) def logout(headers, url=None): @@ -173,95 +164,92 @@ def logout(headers, url=None): raise exceptions.KeystoneError -def notify(request_id, container_id, payload, event_type="authz"): - ctxt = { - 'request_id': request_id, - 'container_id': container_id - } - __n_notifier.critical(ctxt, event_type, payload=payload) - # FIXME (asteroide): the notification mus be done 2 times otherwise the notification - # may not be sent (need to search why) - __n_notifier.critical(ctxt, event_type, payload=payload) - - -def call(endpoint="security_router", ctx=None, method="route", **kwargs): - if not ctx: - ctx = dict() - if endpoint not in __targets: - __targets[endpoint] = dict() - __targets[endpoint]["endpoint"] = oslo_messaging.Target(topic=endpoint, version='1.0') - __targets[endpoint]["client"] = dict() - __targets[endpoint]["client"]["internal"] = oslo_messaging.RPCClient(__transport, - __targets[endpoint]["endpoint"]) - __targets[endpoint]["client"]["external"] = oslo_messaging.RPCClient(__transport_master, - __targets[endpoint]["endpoint"]) - if 'call_master' in ctx and ctx['call_master'] and slave.get("master_url"): - client = __targets[endpoint]["client"]["external"] - LOG.info("Calling master {} on {}...".format(method, endpoint)) - else: - client = __targets[endpoint]["client"]["internal"] - LOG.info("Calling {} on {}...".format(method, endpoint)) - result = copy.deepcopy(client.call(ctx, method, **kwargs)) - LOG.info("result={}".format(result)) - del client - return result - - class Context: - def __init__(self, _keystone_project_id, _subject, _object, _action, _request_id): - from moon_db.core import PDPManager, ModelManager, PolicyManager - self.PolicyManager = PolicyManager - self.ModelManager = ModelManager - self.PDPManager = PDPManager - self.__keystone_project_id = _keystone_project_id + def __init__(self, init_context, cache): + self.cache = cache + self.__keystone_project_id = init_context.get("project_id") self.__pdp_id = None self.__pdp_value = None - for _pdp_key, _pdp_value in PDPManager.get_pdp("admin").items(): - if _pdp_value["keystone_project_id"] == _keystone_project_id: + for _pdp_key, _pdp_value in self.cache.pdp.items(): + if _pdp_value["keystone_project_id"] == self.__keystone_project_id: self.__pdp_id = _pdp_key self.__pdp_value = copy.deepcopy(_pdp_value) break - self.__subject = _subject - self.__object = _object - self.__action = _action + if not self.__pdp_value: + raise exceptions.AuthzException( + "Cannot create context for authz " + "with Keystone project ID {}".format( + self.__keystone_project_id + )) + self.__subject = init_context.get("subject_name") + self.__object = init_context.get("object_name") + self.__action = init_context.get("action_name") self.__current_request = None - self.__request_id = _request_id - self.__index = 0 - self.__init_initial_request() + self.__request_id = init_context.get("req_id") + self.__cookie = init_context.get("cookie") + self.__manager_url = init_context.get("manager_url") + self.__interface_name = init_context.get("interface_name") + self.__index = -1 + # self.__init_initial_request() self.__headers = [] - policies = PolicyManager.get_policies("admin") - models = ModelManager.get_models("admin") + policies = self.cache.policies + models = self.cache.models for policy_id in self.__pdp_value["security_pipeline"]: model_id = policies[policy_id]["model_id"] for meta_rule in models[model_id]["meta_rules"]: self.__headers.append(meta_rule) - self.__meta_rules = ModelManager.get_meta_rules("admin") + self.__meta_rules = self.cache.meta_rules self.__pdp_set = {} + # self.__init_pdp_set() + + def delete_cache(self): + self.cache = {} + + def set_cache(self, cache): + self.cache = cache + + def increment_index(self): + self.__index += 1 + self.__init_current_request() self.__init_pdp_set() - def __init_initial_request(self): - subjects = self.PolicyManager.get_subjects("admin", policy_id=None) - for _subject_id, _subject_dict in subjects.items(): - if _subject_dict["name"] == self.__subject: - self.__subject = _subject_id - break - else: - raise exceptions.SubjectUnknown("Cannot find subject {}".format(self.__subject)) - objects = self.PolicyManager.get_objects("admin", policy_id=None) - for _object_id, _object_dict in objects.items(): - if _object_dict["name"] == self.__object: - self.__object = _object_id - break - else: - raise exceptions.ObjectUnknown("Cannot find object {}".format(self.__object)) - actions = self.PolicyManager.get_actions("admin", policy_id=None) - for _action_id, _action_dict in actions.items(): - if _action_dict["name"] == self.__action: - self.__action = _action_id - break - else: - raise exceptions.ActionUnknown("Cannot find action {}".format(self.__action)) + @property + def current_state(self): + return self.__pdp_set[self.__headers[self.__index]]['effect'] + + @current_state.setter + def current_state(self, state): + if state not in ("grant", "deny", "passed"): + state = "passed" + self.__pdp_set[self.__headers[self.__index]]['effect'] = state + + @current_state.deleter + def current_state(self): + self.__pdp_set[self.__headers[self.__index]]['effect'] = "unset" + + @property + def current_policy_id(self): + return self.__pdp_value["security_pipeline"][self.__index] + + @current_policy_id.setter + def current_policy_id(self, value): + pass + + @current_policy_id.deleter + def current_policy_id(self): + pass + + def __init_current_request(self): + self.__subject = self.cache.get_subject( + self.__pdp_value["security_pipeline"][self.__index], + self.__subject) + self.__object = self.cache.get_object( + self.__pdp_value["security_pipeline"][self.__index], + self.__object) + self.__action = self.cache.get_action( + self.__pdp_value["security_pipeline"][self.__index], + self.__action) self.__current_request = dict(self.initial_request) def __init_pdp_set(self): @@ -269,67 +257,70 @@ class Context: self.__pdp_set[header] = dict() self.__pdp_set[header]["meta_rules"] = self.__meta_rules[header] self.__pdp_set[header]["target"] = self.__add_target(header) - # TODO (asteroide): the following information must be retrieve somewhere self.__pdp_set[header]["effect"] = "unset" self.__pdp_set["effect"] = "deny" - @staticmethod - def update_target(context): - from moon_db.core import PDPManager, ModelManager, PolicyManager - # result = dict() - current_request = context['current_request'] - _subject = current_request.get("subject") - _object = current_request.get("object") - _action = current_request.get("action") - meta_rule_id = context['headers'][context['index']] - policy_id = PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id) - meta_rules = ModelManager.get_meta_rules("admin") - # for meta_rule_id in meta_rules: - for sub_cat in meta_rules[meta_rule_id]['subject_categories']: - if sub_cat not in context["pdp_set"][meta_rule_id]["target"]: - context["pdp_set"][meta_rule_id]["target"][sub_cat] = [] - for assign in PolicyManager.get_subject_assignments("admin", policy_id, _subject, sub_cat).values(): - for assign in assign["assignments"]: - if assign not in context["pdp_set"][meta_rule_id]["target"][sub_cat]: - context["pdp_set"][meta_rule_id]["target"][sub_cat].append(assign) - for obj_cat in meta_rules[meta_rule_id]['object_categories']: - if obj_cat not in context["pdp_set"][meta_rule_id]["target"]: - context["pdp_set"][meta_rule_id]["target"][obj_cat] = [] - for assign in PolicyManager.get_object_assignments("admin", policy_id, _object, obj_cat).values(): - for assign in assign["assignments"]: - if assign not in context["pdp_set"][meta_rule_id]["target"][obj_cat]: - context["pdp_set"][meta_rule_id]["target"][obj_cat].append(assign) - for act_cat in meta_rules[meta_rule_id]['action_categories']: - if act_cat not in context["pdp_set"][meta_rule_id]["target"]: - context["pdp_set"][meta_rule_id]["target"][act_cat] = [] - for assign in PolicyManager.get_action_assignments("admin", policy_id, _action, act_cat).values(): - for assign in assign["assignments"]: - if assign not in context["pdp_set"][meta_rule_id]["target"][act_cat]: - context["pdp_set"][meta_rule_id]["target"][act_cat].append(assign) - # context["pdp_set"][meta_rule_id]["target"].update(result) + # def update_target(self, context): + # # result = dict() + # current_request = context['current_request'] + # _subject = current_request.get("subject") + # _object = current_request.get("object") + # _action = current_request.get("action") + # meta_rule_id = context['headers'][context['index']] + # policy_id = self.cache.get_policy_from_meta_rules(meta_rule_id) + # meta_rules = self.cache.meta_rules() + # # for meta_rule_id in meta_rules: + # for sub_cat in meta_rules[meta_rule_id]['subject_categories']: + # if sub_cat not in context["pdp_set"][meta_rule_id]["target"]: + # context["pdp_set"][meta_rule_id]["target"][sub_cat] = [] + # for assign in self.cache.get_subject_assignments(policy_id, _subject, sub_cat).values(): + # for assign in assign["assignments"]: + # if assign not in context["pdp_set"][meta_rule_id]["target"][sub_cat]: + # context["pdp_set"][meta_rule_id]["target"][sub_cat].append(assign) + # for obj_cat in meta_rules[meta_rule_id]['object_categories']: + # if obj_cat not in context["pdp_set"][meta_rule_id]["target"]: + # context["pdp_set"][meta_rule_id]["target"][obj_cat] = [] + # for assign in self.cache.get_object_assignments(policy_id, _object, obj_cat).values(): + # for assign in assign["assignments"]: + # if assign not in context["pdp_set"][meta_rule_id]["target"][obj_cat]: + # context["pdp_set"][meta_rule_id]["target"][obj_cat].append(assign) + # for act_cat in meta_rules[meta_rule_id]['action_categories']: + # if act_cat not in context["pdp_set"][meta_rule_id]["target"]: + # context["pdp_set"][meta_rule_id]["target"][act_cat] = [] + # for assign in self.cache.get_action_assignments(policy_id, _action, act_cat).values(): + # for assign in assign["assignments"]: + # if assign not in context["pdp_set"][meta_rule_id]["target"][act_cat]: + # context["pdp_set"][meta_rule_id]["target"][act_cat].append(assign) + # # context["pdp_set"][meta_rule_id]["target"].update(result) def __add_target(self, meta_rule_id): + """build target from meta_rule + + Target is dict of categories as keys ; and the value of each category + will be a list of assignments + + """ result = dict() _subject = self.__current_request["subject"] _object = self.__current_request["object"] _action = self.__current_request["action"] - meta_rules = self.ModelManager.get_meta_rules("admin") - policy_id = self.PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id) + meta_rules = self.cache.meta_rules + policy_id = self.cache.get_policy_from_meta_rules(meta_rule_id) for sub_cat in meta_rules[meta_rule_id]['subject_categories']: if sub_cat not in result: result[sub_cat] = [] - for assign in self.PolicyManager.get_subject_assignments("admin", policy_id, _subject, sub_cat).values(): - result[sub_cat].extend(assign["assignments"]) + result[sub_cat].extend( + self.cache.get_subject_assignments(policy_id, _subject, sub_cat)) for obj_cat in meta_rules[meta_rule_id]['object_categories']: if obj_cat not in result: result[obj_cat] = [] - for assign in self.PolicyManager.get_object_assignments("admin", policy_id, _object, obj_cat).values(): - result[obj_cat].extend(assign["assignments"]) + result[obj_cat].extend( + self.cache.get_object_assignments(policy_id, _object, obj_cat)) for act_cat in meta_rules[meta_rule_id]['action_categories']: if act_cat not in result: result[act_cat] = [] - for assign in self.PolicyManager.get_action_assignments("admin", policy_id, _action, act_cat).values(): - result[act_cat].extend(assign["assignments"]) + result[act_cat].extend( + self.cache.get_action_assignments(policy_id, _action, act_cat)) return result def __repr__(self): @@ -356,6 +347,8 @@ pdp_set: {pdp_set} "index": copy.deepcopy(self.__index), "pdp_set": copy.deepcopy(self.__pdp_set), "request_id": copy.deepcopy(self.__request_id), + "manager_url": copy.deepcopy(self.__manager_url), + "interface_name": copy.deepcopy(self.__interface_name), } @property @@ -371,6 +364,42 @@ pdp_set: {pdp_set} raise Exception("You cannot update the request_id") @property + def manager_url(self): + return self.__manager_url + + @manager_url.setter + def manager_url(self, value): + raise Exception("You cannot update the manager_url") + + @manager_url.deleter + def manager_url(self): + raise Exception("You cannot update the manager_url") + + @property + def interface_name(self): + return self.__interface_name + + @interface_name.setter + def interface_name(self, value): + raise Exception("You cannot update the interface_name") + + @interface_name.deleter + def interface_name(self): + raise Exception("You cannot update the interface_name") + + @property + def cookie(self): + return self.__cookie + + @cookie.setter + def cookie(self, value): + raise Exception("You cannot update the cookie") + + @cookie.deleter + def cookie(self): + raise Exception("You cannot delete the cookie") + + @property def initial_request(self): return { "subject": self.__subject, @@ -395,7 +424,8 @@ pdp_set: {pdp_set} @current_request.setter def current_request(self, value): self.__current_request = copy.deepcopy(value) - # Note (asteroide): if the current request is modified, we must update the PDP Set. + # Note (asteroide): if the current request is modified, + # we must update the PDP Set. self.__init_pdp_set() @current_request.deleter @@ -425,7 +455,7 @@ pdp_set: {pdp_set} @index.deleter def index(self): - self.__index = 0 + self.__index = -1 @property def pdp_set(self): @@ -439,8 +469,6 @@ pdp_set: {pdp_set} def pdp_set(self): self.__pdp_set = {} -TOKENS = {} - def check_token(token, url=None): _verify = False diff --git a/moonv4/moon_utilities/requirements.txt b/moonv4/moon_utilities/requirements.txt index e30f5d29..5b80e5f2 100644 --- a/moonv4/moon_utilities/requirements.txt +++ b/moonv4/moon_utilities/requirements.txt @@ -1,8 +1,3 @@ -kombu !=4.0.1,!=4.0.0 -oslo.messaging -oslo.config -oslo.log -vine werkzeug flask requests
\ No newline at end of file diff --git a/moonv4/moon_utilities/setup.py b/moonv4/moon_utilities/setup.py index 6c9ffd3d..21e11419 100644 --- a/moonv4/moon_utilities/setup.py +++ b/moonv4/moon_utilities/setup.py @@ -17,13 +17,13 @@ setup( packages=find_packages(), - author="Thomas Duval", + author='Thomas Duval', - author_email="thomas.duval@orange.com", + author_email='thomas.duval@orange.com', - description="Some utilities for all the Moon components", + description='Some utilities for all the Moon components', - long_description=open('README.rst').read(), + long_description=open('README.md').read(), install_requires=required, @@ -32,12 +32,11 @@ setup( url='https://git.opnfv.org/cgit/moon', classifiers=[ - "Programming Language :: Python", - "Development Status :: 1 - Planning", - "License :: OSI Approved", - "Natural Language :: French", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3", + 'Programming Language :: Python :: 3', + 'Development Status :: 1 - Planning', + 'License :: OSI Approved', + 'Natural Language :: English', + 'Operating System :: OS Independent', ], ) diff --git a/moonv4/moon_utilities/tests/unit_python/conftest.py b/moonv4/moon_utilities/tests/unit_python/conftest.py new file mode 100644 index 00000000..7217586a --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/conftest.py @@ -0,0 +1,17 @@ +import pytest +import requests_mock +import mock_components +import mock_keystone +import mock_cache + + +@pytest.fixture(autouse=True) +def no_requests(monkeypatch): + """ Modify the response from Requests module + """ + with requests_mock.Mocker(real_http=True) as m: + mock_components.register_components(m) + mock_keystone.register_keystone(m) + mock_cache.register_cache(m) + print("End registering URI") + yield m
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/mock_cache.py b/moonv4/moon_utilities/tests/unit_python/mock_cache.py new file mode 100644 index 00000000..b2b287a9 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/mock_cache.py @@ -0,0 +1,321 @@ +from utilities import CONF + +pdp_mock = { + "pdp_id1": { + "name": "...", + "security_pipeline": ["policy_id_1", "policy_id_2"], + "keystone_project_id": "keystone_project_id1", + "description": "...", + }, + "pdp_id12": { + "name": "...", + "security_pipeline": ["policy_id_1", "policy_id_2"], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } +} + +meta_rules_mock = { + "meta_rule_id1": { + "name": "meta_rule1", + "algorithm": "name of the meta rule algorithm", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + }, + "meta_rule_id2": { + "name": "name of the meta rules2", + "algorithm": "name of the meta rule algorithm", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + } +} + +policies_mock = { + "policy_id_1": { + "name": "test_policy1", + "model_id": "model_id_1", + "genre": "authz", + "description": "test", + }, + "policy_id_2": { + "name": "test_policy2", + "model_id": "model_id_2", + "genre": "authz", + "description": "test", + } +} + +subject_mock = { + "policy_id_1": { + "subject_id": { + "name": "subject_name", + "keystone_id": "keystone_project_id1", + "description": "a description" + } + }, + "policy_id_2": { + "subject_id": { + "name": "subject_name", + "keystone_id": "keystone_project_id1", + "description": "a description" + } + } +} + +subject_assignment_mock = { + "subject_id": { + "policy_id": "ID of the policy", + "subject_id": "ID of the subject", + "category_id": "ID of the category", + "assignments": [], + } +} + +object_mock = { + "policy_id_1": { + "object_id": { + "name": "object_name", + "description": "a description" + } + }, + "policy_id_2": { + "object_id": { + "name": "object_name", + "description": "a description" + } + } +} + +object_assignment_mock = { + "object_id": { + "policy_id": "ID of the policy", + "object_id": "ID of the object", + "category_id": "ID of the category", + "assignments": [], + } +} + +action_mock = { + "policy_id_1": { + "action_id": { + "name": "action_name", + "description": "a description" + } + }, + "policy_id_2": { + "action_id": { + "name": "action_name", + "description": "a description" + } + } +} + +action_assignment_mock = { + "action_id": { + "policy_id": "ID of the policy", + "action_id": "ID of the action", + "category_id": "ID of the category", + "assignments": [], + } +} + +models_mock = { + "model_id_1": { + "name": "test_model", + "description": "test", + "meta_rules": ["meta_rule_id1"] + }, + "model_id_2": { + "name": "test_model", + "description": "test", + "meta_rules": ["meta_rule_id2"] + }, +} + +rules_mock = { + "rules": { + "meta_rule_id": "meta_rule_id1", + "rule_id1": { + "rule": ["subject_data_id1", + "object_data_id1", + "action_data_id1"], + "instructions": ( + {"decision": "grant"}, + # "grant" to immediately exit, + # "continue" to wait for the result of next policy + # "deny" to deny the request + ) + }, + "rule_id2": { + "rule": ["subject_data_id2", + "object_data_id2", + "action_data_id2"], + "instructions": ( + { + "update": { + "operation": "add", + # operations may be "add" or "delete" + "target": "rbac:role:admin" + # add the role admin to the current user + } + }, + {"chain": {"name": "rbac"}} + # chain with the policy named rbac + ) + } + } +} + + +def register_cache(m): + """ Modify the response from Requests module + """ + register_pdp(m) + register_meta_rules(m) + register_policies(m) + register_models(m) + register_policy_subject(m, "policy_id_1") + register_policy_subject(m, "policy_id_2") + register_policy_object(m, "policy_id_1") + register_policy_object(m, "policy_id_2") + register_policy_action(m, "policy_id_1") + register_policy_action(m, "policy_id_2") + register_policy_subject_assignment(m, "policy_id_1", "subject_id") + # register_policy_subject_assignment_list(m1, "policy_id_1") + register_policy_subject_assignment(m, "policy_id_2", "subject_id") + # register_policy_subject_assignment_list(m1, "policy_id_2") + register_policy_object_assignment(m, "policy_id_1", "object_id") + # register_policy_object_assignment_list(m1, "policy_id_1") + register_policy_object_assignment(m, "policy_id_2", "object_id") + # register_policy_object_assignment_list(m1, "policy_id_2") + register_policy_action_assignment(m, "policy_id_1", "action_id") + # register_policy_action_assignment_list(m1, "policy_id_1") + register_policy_action_assignment(m, "policy_id_2", "action_id") + # register_policy_action_assignment_list(m1, "policy_id_2") + register_rules(m, "policy_id1") + + +def register_pdp(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'pdp'), + json={'pdps': pdp_mock} + ) + + +def register_meta_rules(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'meta_rules'), + json={'meta_rules': meta_rules_mock} + ) + + +def register_policies(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies'), + json={'policies': policies_mock} + ) + + +def register_models(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'models'), + json={'models': models_mock} + ) + + +def register_policy_subject(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subjects'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'subjects': subject_mock[policy_id]} + ) + + +def register_policy_object(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/objects'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'objects': object_mock[policy_id]} + ) + + +def register_policy_action(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/actions'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'actions': action_mock[policy_id]} + ) + + +def register_policy_subject_assignment(m, policy_id, subj_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subject_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + subj_id), + json={'subject_assignments': subject_assignment_mock} + ) + + +def register_policy_subject_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subject_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'subject_assignments': subject_assignment_mock} + ) + + +def register_policy_object_assignment(m, policy_id, obj_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/object_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + obj_id), + json={'object_assignments': object_assignment_mock} + ) + + +def register_policy_object_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/object_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'object_assignments': object_assignment_mock} + ) + + +def register_policy_action_assignment(m, policy_id, action_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/action_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + action_id), + json={'action_assignments': action_assignment_mock} + ) + + +def register_policy_action_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/action_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'action_assignments': action_assignment_mock} + ) + + +def register_rules(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, 'rules'), + json={'rules': rules_mock} + )
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/mock_components.py b/moonv4/moon_utilities/tests/unit_python/mock_components.py new file mode 100644 index 00000000..a0319e1a --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/mock_components.py @@ -0,0 +1,27 @@ +import utilities + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", + "components/orchestrator", + "components/interface", +) + + +def register_components(m): + for component in COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': utilities.get_b64_conf(component)}] + ) + + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/components?recurse=true', + json=[ + {"Key": key, "Value": utilities.get_b64_conf(key)} for key in COMPONENTS + ], + # json={'Key': "components", 'Value': get_b64_conf("components")} + )
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/mock_keystone.py b/moonv4/moon_utilities/tests/unit_python/mock_keystone.py new file mode 100644 index 00000000..c0b26b88 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/mock_keystone.py @@ -0,0 +1,23 @@ +def register_keystone(m): + m.register_uri( + 'POST', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'DELETE', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users/', + json={"users": [{ + "id": "1111111111111" + }]} + )
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/requirements.txt b/moonv4/moon_utilities/tests/unit_python/requirements.txt new file mode 100644 index 00000000..3c1ad607 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/requirements.txt @@ -0,0 +1,2 @@ +pytest +requests_mock
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/test_cache.py b/moonv4/moon_utilities/tests/unit_python/test_cache.py new file mode 100644 index 00000000..3d4f7292 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/test_cache.py @@ -0,0 +1,75 @@ +import pytest + + +def test_authz_request(): + from moon_utilities import cache + c = cache.Cache() + assert isinstance(c.authz_requests, dict) + + +def test_get_subject_success(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'subject_name' + subject_id = cache_obj.get_subject(policy_id, name) + assert subject_id is not None + + +def test_get_subject_failure(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'invalid name' + with pytest.raises(Exception) as exception_info: + cache_obj.get_subject(policy_id, name) + assert str(exception_info.value) == '400: Subject Unknown' + + +def test_get_object_success(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'object_name' + object_id = cache_obj.get_object(policy_id, name) + assert object_id is not None + + +def test_get_object_failure(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'invalid name' + with pytest.raises(Exception) as exception_info: + cache_obj.get_object(policy_id, name) + assert str(exception_info.value) == '400: Subject Unknown' + + +def test_get_action_success(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'action_name' + action_id = cache_obj.get_action(policy_id, name) + assert action_id is not None + + +def test_get_action_failure(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'invalid name' + with pytest.raises(Exception) as exception_info: + cache_obj.get_action(policy_id, name) + assert str(exception_info.value) == '400: Subject Unknown' + + +def test_cache_manager(): + from moon_utilities import cache + cache_obj = cache.Cache() + assert cache_obj.pdp is not None + assert cache_obj.meta_rules is not None + assert len(cache_obj.meta_rules) == 2 + assert cache_obj.policies is not None + assert len(cache_obj.policies) == 2 + assert cache_obj.models is not None
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/test_configuration.py b/moonv4/moon_utilities/tests/unit_python/test_configuration.py new file mode 100644 index 00000000..0ebff995 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/test_configuration.py @@ -0,0 +1,5 @@ + +def test_get_components(): + from moon_utilities import configuration + assert isinstance(configuration.get_components(), dict) + diff --git a/moonv4/moon_utilities/tests/unit_python/utilities.py b/moonv4/moon_utilities/tests/unit_python/utilities.py new file mode 100644 index 00000000..1d79d890 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/utilities.py @@ -0,0 +1,136 @@ +import base64 +import json + + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "interface" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + + +def get_b64_conf(component=None): + if component == "components": + return base64.b64encode( + json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8') + elif component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif not component: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') diff --git a/moonv4/moon_wrapper/Dockerfile b/moonv4/moon_wrapper/Dockerfile index 2f55c8da..55e7208d 100644 --- a/moonv4/moon_wrapper/Dockerfile +++ b/moonv4/moon_wrapper/Dockerfile @@ -6,6 +6,7 @@ RUN pip3 install pip --upgrade ADD . /root WORKDIR /root/ RUN pip3 install -r requirements.txt --upgrade +RUN pip3 install /root/dist/* --upgrade RUN pip3 install . CMD ["python3", "-m", "moon_wrapper"] diff --git a/moonv4/moon_wrapper/LICENSE b/moonv4/moon_wrapper/LICENSE index 4143aac2..d6456956 100644 --- a/moonv4/moon_wrapper/LICENSE +++ b/moonv4/moon_wrapper/LICENSE @@ -174,31 +174,29 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/moonv4/moon_wrapper/moon_wrapper/__main__.py b/moonv4/moon_wrapper/moon_wrapper/__main__.py index 1a04e9ce..46cafa76 100644 --- a/moonv4/moon_wrapper/moon_wrapper/__main__.py +++ b/moonv4/moon_wrapper/moon_wrapper/__main__.py @@ -1,3 +1,4 @@ from moon_wrapper.server import main -main() +server = main() +server.run() diff --git a/moonv4/moon_wrapper/moon_wrapper/api/__init__.py b/moonv4/moon_wrapper/moon_wrapper/api/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/moonv4/moon_wrapper/moon_wrapper/api/__init__.py diff --git a/moonv4/moon_consul/moon_consul/api/generic.py b/moonv4/moon_wrapper/moon_wrapper/api/generic.py index 69f25eef..68687ddb 100644 --- a/moonv4/moon_consul/moon_consul/api/generic.py +++ b/moonv4/moon_wrapper/moon_wrapper/api/generic.py @@ -7,16 +7,70 @@ Those API are helping API used to manage the Moon platform. """ from flask_restful import Resource, request -# from oslo_config import cfg from oslo_log import log as logging -# from moon_utilities.security_functions import call -import moon_consul.api -# from moon_utilities.auth import check_auth +import moon_wrapper.api +from moon_utilities.security_functions import check_auth __version__ = "0.1.0" -LOG = logging.getLogger(__name__) -# CONF = cfg.CONF +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class Status(Resource): + """ + Endpoint for status requests + """ + + __urls__ = ("/status", "/status/", "/status/<string:component_id>") + + def get(self, component_id=None): + """Retrieve status of all components + + :return: { + "orchestrator": { + "status": "Running" + }, + "security_router": { + "status": "Running" + } + } + """ + raise NotImplemented + + +class Logs(Resource): + """ + Endpoint for logs requests + """ + + __urls__ = ("/logs", "/logs/", "/logs/<string:component_id>") + + def get(self, component_id=None): + """Get logs from the Moon platform + + :param component_id: the ID of the component your are looking for (optional) + :return: [ + "2015-04-15-13:45:20 + "2015-04-15-13:45:21 + "2015-04-15-13:45:22 + "2015-04-15-13:45:23 + ] + """ + filter_str = request.args.get('filter', '') + from_str = request.args.get('from', '') + to_str = request.args.get('to', '') + event_number = request.args.get('event_number', '') + try: + event_number = int(event_number) + except ValueError: + event_number = None + args = dict() + args["filter"] = filter_str + args["from"] = from_str + args["to"] = to_str + args["event_number"] = event_number + + raise NotImplemented class API(Resource): @@ -31,7 +85,7 @@ class API(Resource): "/api/<string:group_id>/", "/api/<string:group_id>/<string:endpoint_id>") - # @check_auth + @check_auth def get(self, group_id="", endpoint_id="", user_id=""): """Retrieve all API endpoints or a specific endpoint if endpoint_id is given @@ -49,7 +103,7 @@ class API(Resource): } """ __methods = ("get", "post", "put", "delete", "options", "patch") - api_list = filter(lambda x: "__" not in x, dir(moon_consul.api)) + api_list = filter(lambda x: "__" not in x, dir(moon_wrapper.api)) api_desc = dict() for api_name in api_list: api_desc[api_name] = {} @@ -75,4 +129,3 @@ class API(Resource): return {"error": "Unknown endpoint_id {}".format(endpoint_id)} return {group_id: api_desc[group_id]} return api_desc - diff --git a/moonv4/moon_wrapper/moon_wrapper/api/wrapper.py b/moonv4/moon_wrapper/moon_wrapper/api/wrapper.py new file mode 100644 index 00000000..32eb4e68 --- /dev/null +++ b/moonv4/moon_wrapper/moon_wrapper/api/wrapper.py @@ -0,0 +1,127 @@ +# 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'. +""" +Authz is the endpoint to get authorization response +""" + +import flask +from flask import request +from flask_restful import Resource +import logging +import json +import requests +from moon_utilities import exceptions +import time +from uuid import uuid4 + +# from moon_interface.api.authz import pdp_in_cache, pdp_in_manager, container_exist, \ +# create_containers, create_authz_request +# from moon_interface.authz_requests import AuthzRequest +from moon_utilities import configuration + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.wrapper.api." + __name__) + + +class Wrapper(Resource): + """ + Endpoint for authz requests + """ + + __urls__ = ( + "/authz", + "/authz/", + ) + + def __init__(self, **kwargs): + self.port = kwargs.get("port") + self.CACHE = kwargs.get("cache", {}) + self.TIMEOUT = 5 + + # def get(self): + # LOG.info("GET") + # return self.manage_data() + + def post(self): + LOG.debug("POST {}".format(request.form)) + response = flask.make_response("False") + if self.manage_data(): + response = flask.make_response("True") + response.headers['content-type'] = 'application/octet-stream' + return response + + @staticmethod + def __get_subject(target, credentials): + _subject = target.get("user_id", "") + if not _subject: + _subject = credentials.get("user_id", "none") + return _subject + + @staticmethod + def __get_object(target, credentials): + try: + # note: case of Glance + return target['target']['name'] + except KeyError: + pass + + # note: default case + return target.get("project_id", "none") + + @staticmethod + def __get_project_id(target, credentials): + LOG.info("__get_project_id {}".format(target)) + return target.get("project_id", "none") + + def get_interface_url(self, project_id): + LOG.info("project_id {}".format(project_id)) + for containers in self.CACHE.containers.values(): + LOG.info("containers {}".format(containers)) + for container in containers: + if container.get("keystone_project_id") == project_id: + if "interface" in container['name']: + return "http://{}:{}".format( + container['name'], + container['port']) + self.CACHE.update() + # Note (asteroide): test an other time after the update + for containers in self.CACHE.containers.values(): + for container in containers: + if container.get("keystone_project_id") == project_id: + if "interface" in container['name']: + return "http://{}:{}".format( + container['name'], + container['port']) + raise exceptions.AuthzException("Keystone Project " + "ID ({}) is unknown or not mapped " + "to a PDP.".format(project_id)) + + def manage_data(self): + data = request.form + if not dict(request.form): + data = json.loads(request.data.decode("utf-8")) + target = json.loads(data.get('target', {})) + credentials = json.loads(data.get('credentials', {})) + rule = data.get('rule', "") + _subject = self.__get_subject(target, credentials) + _object = self.__get_object(target, credentials) + _project_id = self.__get_project_id(target, credentials) + LOG.debug("POST with args project={} / " + "subject={} - object={} - action={}".format( + _project_id, _subject, _object, rule)) + interface_url = self.get_interface_url(_project_id) + LOG.debug("interface_url={}".format(interface_url)) + req = requests.get("{}/authz/{}/{}/{}/{}".format( + interface_url, + _project_id, + _subject, + _object, + rule + )) + LOG.debug("Get interface {}".format(req.text)) + if req.status_code == 200: + if req.json().get("result", False): + return True diff --git a/moonv4/moon_wrapper/moon_wrapper/http_server.py b/moonv4/moon_wrapper/moon_wrapper/http_server.py index f50213c7..39951089 100644 --- a/moonv4/moon_wrapper/moon_wrapper/http_server.py +++ b/moonv4/moon_wrapper/moon_wrapper/http_server.py @@ -3,74 +3,139 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -import requests -import json -from flask import Flask, request +from flask import Flask, jsonify +from flask_cors import CORS, cross_origin +from flask_restful import Resource, Api import logging -from moon_utilities import configuration +from moon_wrapper import __version__ +from moon_wrapper.api.generic import Status, Logs, API +from moon_wrapper.api.wrapper import Wrapper +from moon_utilities.cache import Cache +from moon_utilities import configuration, exceptions logger = logging.getLogger("moon.wrapper.http") -def __get_subject(target, credentials): - _subject = target.get("user_id", "") - if not _subject: - _subject = credentials.get("user_id", "") - return _subject - - -def __get_object(target, credentials): - try: - # note: case of Glance - return target['target']['name'] - except KeyError: - pass - - # note: default case - return target.get("project_id", "") - - -def __get_project_id(target, credentials): - return target.get("project_id", "") - - -def HTTPServer(host, port): - app = Flask(__name__) - conf = configuration.get_configuration("components/wrapper") - timeout = conf["components/wrapper"].get("timeout", 5) - conf = configuration.get_configuration("components/interface") - interface_hostname = conf["components/interface"].get("hostname", "interface") - interface_port = conf["components/interface"].get("port", 80) - conf = configuration.get_configuration("logging") - try: - debug = conf["logging"]["loggers"]['moon']['level'] == "DEBUG" - except KeyError: - debug = False - - @app.route("/", methods=['POST', 'GET']) - def wrapper(): - try: - target = json.loads(request.form.get('target', {})) - credentials = json.loads(request.form.get('credentials', {})) - rule = request.form.get('rule', "") - _subject = __get_subject(target, credentials) - _object = __get_object(target, credentials) - _project_id = __get_project_id(target, credentials) - logger.info("GET with args {} / {} - {} - {}".format(_project_id, _subject, _object, rule)) - _url = "http://{}:{}/authz/{}/{}/{}/{}".format( - interface_hostname, - interface_port, - _project_id, - _subject, - _object, - rule - ) - req = requests.get(url=_url, timeout=timeout) - logger.info("req txt={}".format(req.text)) - if req.json()["result"] == True: - return "True" - except Exception as e: - logger.exception("An exception occurred: {}".format(e)) - return "False" - - app.run(debug=debug, host=host, port=port) +CACHE = Cache() + + +class Server: + """Base class for HTTP server""" + + def __init__(self, host="localhost", port=80, api=None, **kwargs): + """Run a server + + :param host: hostname of the server + :param port: port for the running server + :param kwargs: optional parameters + :return: a running server + """ + self._host = host + self._port = port + self._api = api + self._extra = kwargs + + @property + def host(self): + return self._host + + @host.setter + def host(self, name): + self._host = name + + @host.deleter + def host(self): + self._host = "" + + @property + def port(self): + return self._port + + @port.setter + def port(self, number): + self._port = number + + @port.deleter + def port(self): + self._port = 80 + + def run(self): + raise NotImplementedError() + +__API__ = ( + Status, Logs, API + ) + + +class Root(Resource): + """ + The root of the web service + """ + __urls__ = ("/", ) + __methods = ("get", "post", "put", "delete", "options") + + def get(self): + tree = {"/": {"methods": ("get",), + "description": "List all methods for that service."}} + for item in __API__: + tree[item.__name__] = {"urls": item.__urls__} + _methods = [] + for _method in self.__methods: + if _method in dir(item): + _methods.append(_method) + tree[item.__name__]["methods"] = _methods + tree[item.__name__]["description"] = item.__doc__.strip() + return { + "version": __version__, + "tree": tree + } + + +class HTTPServer(Server): + + def __init__(self, host="localhost", port=80, **kwargs): + super(HTTPServer, self).__init__(host=host, port=port, **kwargs) + self.app = Flask(__name__) + self.port = port + conf = configuration.get_configuration("components/orchestrator") + _hostname = conf["components/orchestrator"].get("hostname", + "orchestrator") + _port = conf["components/orchestrator"].get("port", 80) + _protocol = conf["components/orchestrator"].get("protocol", "http") + self.orchestrator_url = "{}://{}:{}".format( + _protocol, _hostname, _port) + # Todo : specify only few urls instead of * + # CORS(self.app) + self.api = Api(self.app) + self.__set_route() + self.__hook_errors() + + def __hook_errors(self): + + def get_404_json(e): + return jsonify({"result": False, "code": 404, + "description": str(e)}), 404 + self.app.register_error_handler(404, get_404_json) + + def get_400_json(e): + return jsonify({"result": False, "code": 400, + "description": str(e)}), 400 + self.app.register_error_handler(400, lambda e: get_400_json) + self.app.register_error_handler(403, exceptions.AuthException) + + def __set_route(self): + self.api.add_resource(Root, '/') + + for api in __API__: + self.api.add_resource(api, *api.__urls__) + self.api.add_resource(Wrapper, *Wrapper.__urls__, + resource_class_kwargs={ + "orchestrator_url": self.orchestrator_url, + "cache": CACHE, + } + ) + + def run(self): + self.app.run(host=self._host, port=self._port) # nosec + # self.app.run(debug=True, host=self._host, port=self._port) # nosec + diff --git a/moonv4/moon_wrapper/moon_wrapper/server.py b/moonv4/moon_wrapper/moon_wrapper/server.py index 2e5f15b9..a3461018 100644 --- a/moonv4/moon_wrapper/moon_wrapper/server.py +++ b/moonv4/moon_wrapper/moon_wrapper/server.py @@ -25,8 +25,9 @@ def main(): configuration.add_component(uuid="wrapper", name=hostname, port=port, bind=bind) LOG.info("Starting server with IP {} on port {} bind to {}".format(hostname, port, bind)) server = HTTPServer(host=bind, port=port) - server.run() + return server if __name__ == '__main__': - main() + server = main() + server.run() diff --git a/moonv4/moon_wrapper/requirements.txt b/moonv4/moon_wrapper/requirements.txt index 51b57277..85ec611f 100644 --- a/moonv4/moon_wrapper/requirements.txt +++ b/moonv4/moon_wrapper/requirements.txt @@ -1,4 +1,5 @@ flask flask_restful -babel +flask_cors +werkzeug moon_utilities
\ No newline at end of file diff --git a/moonv4/moon_wrapper/tests/README.md b/moonv4/moon_wrapper/tests/README.md new file mode 100644 index 00000000..73a9fcd2 --- /dev/null +++ b/moonv4/moon_wrapper/tests/README.md @@ -0,0 +1,35 @@ +# Tests + +## Python Unit Test for moon_db + +- launch Docker for Python unit tests + + + cd ${MOON_HOME}/moonv4/moon_db/ + docker run -ti --volume ${PWD}:/data asteroide/moon_tests + + +## Build and upload python packages + +- build python packages + + + python setup.py sdist bdist_wheel + + +- upload moon_db to PIP + + + python setup.py upload + + +or + + + gpg --detach-sign -u "${GPG_ID}" -a dist/moon_db-X.Y.Z-py3-none-any.whl + gpg --detach-sign -u "${GPG_ID}" -a dist/moon_db-X.Y.Z.tar.gz + twine upload dist/moon_db-X.Y.Z-py3-none-any.whl dist/moon_db-X.Y.Z-py3-none-any.whl.asc + twine upload dist/moon_db-X.Y.Z.tar.gz dist/moon_db-X.Y.Z.tar.gz.asc + + + diff --git a/moonv4/moon_wrapper/tests/unit_python/api/__init__.py b/moonv4/moon_wrapper/tests/unit_python/api/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/moonv4/moon_wrapper/tests/unit_python/api/__init__.py diff --git a/moonv4/moon_wrapper/tests/unit_python/api/test_wrapper.py b/moonv4/moon_wrapper/tests/unit_python/api/test_wrapper.py new file mode 100644 index 00000000..7e9a7421 --- /dev/null +++ b/moonv4/moon_wrapper/tests/unit_python/api/test_wrapper.py @@ -0,0 +1,28 @@ +import json + + +def get_json(data): + return json.loads(data.decode("utf-8")) + + +def test_authz_true(context): + import moon_wrapper.server + server = moon_wrapper.server.main() + client = server.app.test_client() + _target = { + 'target': { + "name": context.get('object_name'), + }, + "project_id": context.get('project_id'), + "user_id": context.get('subject_name') + } + authz_data = { + 'rule': context.get('action_name'), + 'target': json.dumps(_target), + 'credentials': 'null'} + req = client.post("/authz", data=json.dumps(authz_data)) + assert req.status_code == 200 + assert req.data + assert isinstance(req.data, bytes) + assert req.data == b"True" + diff --git a/moonv4/moon_wrapper/tests/unit_python/conftest.py b/moonv4/moon_wrapper/tests/unit_python/conftest.py new file mode 100644 index 00000000..61c3da71 --- /dev/null +++ b/moonv4/moon_wrapper/tests/unit_python/conftest.py @@ -0,0 +1,687 @@ +import base64 +import json +import os +import pickle +import pytest +import requests_mock +from uuid import uuid4 +from requests.packages.urllib3.response import HTTPResponse + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "orchestrator" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", + "components/orchestrator", + "components/interface", + "components/wrapper", +) + +CONTEXT = { + "project_id": "a64beb1cc224474fb4badd43173e7101", + "subject_name": "testuser", + "object_name": "vm1", + "action_name": "boot", + "request_id": uuid4().hex, + "interface_name": "interface", + "manager_url": "http://{}:{}".format( + CONF["components"]["manager"]["hostname"], + CONF["components"]["manager"]["port"] + ), + "cookie": uuid4().hex + } + + +def get_b64_conf(component=None): + if component == "components": + return base64.b64encode( + json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8') + elif component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif not component: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') + + +MOCK_URLS = [ + ('GET', 'http://consul:8500/v1/kv/components?recurse=true', + {'json': {"Key": key, "Value": get_b64_conf(key)} + for key in COMPONENTS} + ), + ('POST', 'http://keystone:5000/v3/auth/tokens', + {'headers': {'X-Subject-Token': "111111111"}}), + ('DELETE', 'http://keystone:5000/v3/auth/tokens', + {'headers': {'X-Subject-Token': "111111111"}}), + ('POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + {'json': {"users": {}}}), + ('GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + {'json': {"users": {}}}), + ('POST', 'http://keystone:5000/v3/users/', + {'json': {"users": [{ + "id": "1111111111111" + }]}}), +] + + +@pytest.fixture +def db(): + return CONF['database'] + + +@pytest.fixture +def context(): + return CONTEXT + + +def set_env_variables(): + os.environ['UUID'] = "1111111111" + os.environ['TYPE'] = "authz" + os.environ['PORT'] = "8081" + os.environ['PDP_ID'] = "b3d3e18abf3340e8b635fd49e6634ccd" + os.environ['META_RULE_ID'] = "f8f49a779ceb47b3ac810f01ef71b4e0" + os.environ['KEYSTONE_PROJECT_ID'] = CONTEXT['project_id'] + + +def get_pickled_context(): + from moon_utilities.security_functions import Context + from moon_utilities.cache import Cache + CACHE = Cache() + CACHE.update() + _context = Context(context(), CACHE) + _context.increment_index() + _context.pdp_set['effect'] = 'grant' + _context.pdp_set[os.environ['META_RULE_ID']]['effect'] = 'grant' + return pickle.dumps(_context) + + +@pytest.fixture(autouse=True) +def set_consul_and_db(monkeypatch): + """ Modify the response from Requests module + """ + set_env_variables() + with requests_mock.Mocker(real_http=True) as m: + for component in COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': get_b64_conf(component)}] + ) + # for _data in MOCK_URLS: + # m.register_uri(_data[0], _data[1], **_data[2]) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/components?recurse=true', + json=[ + {"Key": key, "Value": get_b64_conf(key)} for key in COMPONENTS + ], + ) + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/plugins/authz', + json=[ + { + "LockIndex": 0, + "Key": "plugins/authz", + "Flags": 0, + "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=", + "CreateIndex": 14, + "ModifyIndex": 656 + } + ], + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'DELETE', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users/', + json={"users": [{ + "id": "1111111111111" + }]} + ) + m.register_uri( + 'GET', 'http://orchestrator:8083/pods', + json={ + "pods": { + "721760dd-de5f-11e7-8001-3863bbb766f3": [ + { + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", + "port": 8080, + "genre": "interface", + "name": "interface-paltry", + "keystone_project_id": "a64beb1cc224474fb4badd43173e7101", + "namespace": "moon", + "container": "wukongsun/moon_interface:v4.3" + }, + { + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", + "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "port": 8081, + "genre": "authz", + "name": "authz-economic", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "keystone_project_id": "a64beb1cc224474fb4badd43173e7101", + "namespace": "moon", + "container": "wukongsun/moon_authz:v4.3" + } + ], + "232399a4-de5f-11e7-8001-3863bbb766f3": [ + { + "port": 8080, + "namespace": "moon", + "name": "wrapper-paltry", + "container": "wukongsun/moon_wrapper:v4.3.1" + } + ] + } + } + ) + m.register_uri( + 'GET', 'http://orchestrator:8083/pods/authz-economic', + json={ + "pods": None + } + ) + m.register_uri( + 'GET', 'http://manager:8082/pdp', + json={ + "pdps": { + "b3d3e18abf3340e8b635fd49e6634ccd": { + "description": "test", + "security_pipeline": [ + "f8f49a779ceb47b3ac810f01ef71b4e0" + ], + "name": "pdp_rbac", + "keystone_project_id": "a64beb1cc224474fb4badd43173e7101" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies', + json={ + "policies": { + "f8f49a779ceb47b3ac810f01ef71b4e0": { + "name": "RBAC policy example", + "model_id": "cd923d8633ff4978ab0e99938f5153d6", + "description": "test", + "genre": "authz" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/models', + json={ + "models": { + "cd923d8633ff4978ab0e99938f5153d6": { + "name": "RBAC", + "meta_rules": [ + "f8f49a779ceb47b3ac810f01ef71b4e0" + ], + "description": "test" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/meta_rules', + json={ + "meta_rules": { + "f8f49a779ceb47b3ac810f01ef71b4e0": { + "subject_categories": [ + "14e6ae0ba34d458b876c791b73aa17bd" + ], + "action_categories": [ + "241a2a791554421a91c9f1bc564aa94d" + ], + "description": "", + "name": "rbac", + "object_categories": [ + "6d48500f639d4c2cab2b1f33ef93a1e8" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subjects', + json={ + "subjects": { + "89ba91c18dd54abfbfde7a66936c51a6": { + "description": "test", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ], + "name": "testuser", + "email": "mail", + "id": "89ba91c18dd54abfbfde7a66936c51a6", + "partner_id": "" + }, + "31fd15ad14784a9696fcc887dddbfaf9": { + "description": "test", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ], + "name": "adminuser", + "email": "mail", + "id": "31fd15ad14784a9696fcc887dddbfaf9", + "partner_id": "" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/objects', + json={ + "objects": { + "67b8008a3f8d4f8e847eb628f0f7ca0e": { + "name": "vm1", + "description": "test", + "id": "67b8008a3f8d4f8e847eb628f0f7ca0e", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + }, + "9089b3d2ce5b4e929ffc7e35b55eba1a": { + "name": "vm0", + "description": "test", + "id": "9089b3d2ce5b4e929ffc7e35b55eba1a", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/actions', + json={ + "actions": { + "cdb3df220dc05a6ea3334b994827b068": { + "name": "boot", + "description": "test", + "id": "cdb3df220dc04a6ea3334b994827b068", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + }, + "cdb3df220dc04a6ea3334b994827b068": { + "name": "stop", + "description": "test", + "id": "cdb3df220dc04a6ea3334b994827b068", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + }, + "9f5112afe9b34a6c894eb87246ccb7aa": { + "name": "start", + "description": "test", + "id": "9f5112afe9b34a6c894eb87246ccb7aa", + "partner_id": "", + "policy_list": [ + "f8f49a779ceb47b3ac810f01ef71b4e0", + "636cd473324f4c0bbd9102cb5b62a16d" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subject_assignments', + json={ + "subject_assignments": { + "826c1156d0284fc9b4b2ddb279f63c52": { + "category_id": "14e6ae0ba34d458b876c791b73aa17bd", + "assignments": [ + "24ea95256c5f4c888c1bb30a187788df", + "6b227b77184c48b6a5e2f3ed1de0c02a", + "31928b17ec90438ba5a2e50ae7650e63", + "4e60f554dd3147af87595fb6b37dcb13", + "7a5541b63a024fa88170a6b59f99ccd7", + "dd2af27812f742029d289df9687d6126" + ], + "id": "826c1156d0284fc9b4b2ddb279f63c52", + "subject_id": "89ba91c18dd54abfbfde7a66936c51a6", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + }, + "7407ffc1232944279b0cbcb0847c86f7": { + "category_id": "315072d40d774c43a89ff33937ed24eb", + "assignments": [ + "6b227b77184c48b6a5e2f3ed1de0c02a", + "31928b17ec90438ba5a2e50ae7650e63", + "7a5541b63a024fa88170a6b59f99ccd7", + "dd2af27812f742029d289df9687d6126" + ], + "id": "7407ffc1232944279b0cbcb0847c86f7", + "subject_id": "89ba91c18dd54abfbfde7a66936c51a6", + "policy_id": "3e65256389b448cb9897917ea235f0bb" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/object_assignments', + json={ + "object_assignments": { + "201ad05fd3f940948b769ab9214fe295": { + "object_id": "9089b3d2ce5b4e929ffc7e35b55eba1a", + "assignments": [ + "030fbb34002e4236a7b74eeb5fd71e35", + "06bcb8655b9d46a9b90e67ef7c825b50", + "34eb45d7f46d4fb6bc4965349b8e4b83", + "4b7793dbae434c31a77da9d92de9fa8c" + ], + "id": "201ad05fd3f940948b769ab9214fe295", + "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + }, + "90c5e86f8be34c0298fbd1973e4fb043": { + "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e", + "assignments": [ + "a098918e915b4b12bccb89f9a3f3b4e4", + "06bcb8655b9d46a9b90e67ef7c825b50", + "7dc76c6142af47c88b60cc2b0df650ba", + "4b7793dbae434c31a77da9d92de9fa8c" + ], + "id": "90c5e86f8be34c0298fbd1973e4fb043", + "category_id": "33aece52d45b4474a20dc48a76800daf", + "policy_id": "3e65256389b448cb9897917ea235f0bb" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/action_assignments', + json={ + "action_assignments": { + "2128e3ffbd1c4ef5be515d625745c2d4": { + "category_id": "241a2a791554421a91c9f1bc564aa94d", + "action_id": "cdb3df220dc05a6ea3334b994827b068", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "id": "2128e3ffbd1c4ef5be515d625745c2d4", + "assignments": [ + "570c036781e540dc9395b83098c40ba7", + "7fe17d7a2e3542719f8349c3f2273182", + "015ca6f40338422ba3f692260377d638", + "23d44c17bf88480f83e8d57d2aa1ea79" + ] + }, + "cffb98852f3a4110af7a0ddfc4e19201": { + "category_id": "4a2c5abaeaf644fcaf3ca8df64000d53", + "action_id": "cdb3df220dc04a6ea3334b994827b068", + "policy_id": "3e65256389b448cb9897917ea235f0bb", + "id": "cffb98852f3a4110af7a0ddfc4e19201", + "assignments": [ + "570c036781e540dc9395b83098c40ba7", + "7fe17d7a2e3542719f8349c3f2273182", + "015ca6f40338422ba3f692260377d638", + "23d44c17bf88480f83e8d57d2aa1ea79" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subject_assignments/89ba91c18dd54abfbfde7a66936c51a6', + json={ + "subject_assignments": { + "826c1156d0284fc9b4b2ddb279f63c52": { + "category_id": "14e6ae0ba34d458b876c791b73aa17bd", + "assignments": [ + "24ea95256c5f4c888c1bb30a187788df", + "6b227b77184c48b6a5e2f3ed1de0c02a", + "31928b17ec90438ba5a2e50ae7650e63", + "4e60f554dd3147af87595fb6b37dcb13", + "7a5541b63a024fa88170a6b59f99ccd7", + "dd2af27812f742029d289df9687d6126" + ], + "id": "826c1156d0284fc9b4b2ddb279f63c52", + "subject_id": "89ba91c18dd54abfbfde7a66936c51a6", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/object_assignments/67b8008a3f8d4f8e847eb628f0f7ca0e', + json={ + "object_assignments": { + "201ad05fd3f940948b769ab9214fe295": { + "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e", + "assignments": [ + "030fbb34002e4236a7b74eeb5fd71e35", + "06bcb8655b9d46a9b90e67ef7c825b50", + "34eb45d7f46d4fb6bc4965349b8e4b83", + "4b7793dbae434c31a77da9d92de9fa8c" + ], + "id": "201ad05fd3f940948b769ab9214fe295", + "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/action_assignments/cdb3df220dc05a6ea3334b994827b068', + json={ + "action_assignments": { + "2128e3ffbd1c4ef5be515d625745c2d4": { + "category_id": "241a2a791554421a91c9f1bc564aa94d", + "action_id": "cdb3df220dc05a6ea3334b994827b068", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "id": "2128e3ffbd1c4ef5be515d625745c2d4", + "assignments": [ + "570c036781e540dc9395b83098c40ba7", + "7fe17d7a2e3542719f8349c3f2273182", + "015ca6f40338422ba3f692260377d638", + "23d44c17bf88480f83e8d57d2aa1ea79" + ] + } + } + } + ) + m.register_uri( + 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/rules', + json={ + "rules": { + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "rules": [ + { + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "rule": [ + "24ea95256c5f4c888c1bb30a187788df", + "030fbb34002e4236a7b74eeb5fd71e35", + "570c036781e540dc9395b83098c40ba7" + ], + "enabled": True, + "id": "0201a2bcf56943c1904dbac016289b71", + "instructions": [ + { + "decision": "grant" + } + ], + "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + }, + { + "policy_id": "ecc2451c494e47b5bca7250cd324a360", + "rule": [ + "54f574cd2043468da5d65e4f6ed6e3c9", + "6559686961a3490a978f246ac9f85fbf", + "ac0d1f600bf447e8bd2f37b7cc47f2dc" + ], + "enabled": True, + "id": "a83fed666af8436192dfd8b3c83a6fde", + "instructions": [ + { + "decision": "grant" + } + ], + "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0" + } + ] + } + } + ) + m.register_uri( + 'POST', 'http://127.0.0.1:8081/authz', + content=get_pickled_context() + ) + m.register_uri( + 'GET', 'http://interface-paltry:8080/authz/{}/{}/{}/{}'.format( + CONTEXT.get("project_id"), + CONTEXT.get("subject_name"), + CONTEXT.get("object_name"), + CONTEXT.get("action_name"), + ), + json={"result": True, "message": "================"} + ) + # from moon_db.db_manager import init_engine, run + # engine = init_engine() + # run("upgrade", logging.getLogger("db_manager"), engine) + yield m + # os.unlink(CONF['database']['url'].replace("sqlite:///", "")) + + diff --git a/moonv4/moon_wrapper/tests/unit_python/requirements.txt b/moonv4/moon_wrapper/tests/unit_python/requirements.txt new file mode 100644 index 00000000..8bd8449f --- /dev/null +++ b/moonv4/moon_wrapper/tests/unit_python/requirements.txt @@ -0,0 +1,5 @@ +flask +flask_cors +flask_restful +moon_db +moon_utilities
\ No newline at end of file diff --git a/moonv4/moon_consul/Changelog b/moonv4/python_moonclient/Changelog index 5ccc3c27..854200cb 100644 --- a/moonv4/moon_consul/Changelog +++ b/moonv4/python_moonclient/Changelog @@ -9,5 +9,4 @@ CHANGES 0.1.0 ----- -- First version of the moon_consul component. - +- First version of the python-moonclient
\ No newline at end of file diff --git a/moonv4/moon_router/LICENSE b/moonv4/python_moonclient/LICENSE index 4143aac2..d6456956 100644 --- a/moonv4/moon_router/LICENSE +++ b/moonv4/python_moonclient/LICENSE @@ -174,31 +174,29 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/moonv4/moon_router/MANIFEST.in b/moonv4/python_moonclient/MANIFEST.in index 1f674d50..2a5ac509 100644 --- a/moonv4/moon_router/MANIFEST.in +++ b/moonv4/python_moonclient/MANIFEST.in @@ -3,7 +3,8 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -include README.rst +include README.md include LICENSE +include Changelog include setup.py include requirements.txt diff --git a/moonv4/python_moonclient/README.md b/moonv4/python_moonclient/README.md new file mode 100644 index 00000000..d091cdf5 --- /dev/null +++ b/moonv4/python_moonclient/README.md @@ -0,0 +1,33 @@ +# python-moonclient Package +This package contains the core module for the Moon project. +It is designed to provide authorization feature to all OpenStack components. + +For any other information, refer to the parent project: + + https://git.opnfv.org/moon + +moon_utilities is a common Python lib for other Moon Python packages + +## Build +### Build Python Package +```bash +cd ${MOON_HOME}/moonv4/python_moonclient +python3 setup.py sdist bdist_wheel +``` + +### Push Python Package to PIP +```bash +cd ${MOON_HOME}/moonv4/python_moonclient +gpg --detach-sign -u "${GPG_ID}" -a dist/python_moonclient-X.Y.Z-py3-none-any.whl +gpg --detach-sign -u "${GPG_ID}" -a dist/python_moonclient-X.Y.Z.tar.gz +twine upload dist/python_moonclient-X.Y.Z-py3-none-any.whl dist/python_moonclient-X.Y.Z-py3-none-any.whl.asc +twine upload dist/python_moonclient-X.Y.Z.tar.gz dist/python_moonclient-X.Y.Z.tar.gz.asc +``` + +## Test +### Python Unit Test +launch Docker for Python unit tests +```bash +cd ${MOON_HOME}/moonv4/python_moonclient +docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest +``` diff --git a/moonv4/python_moonclient/python_moonclient/__init__.py b/moonv4/python_moonclient/python_moonclient/__init__.py new file mode 100644 index 00000000..d7cdd111 --- /dev/null +++ b/moonv4/python_moonclient/python_moonclient/__init__.py @@ -0,0 +1,6 @@ +# 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'. + +__version__ = "0.0.1" diff --git a/moonv4/python_moonclient/python_moonclient/config.py b/moonv4/python_moonclient/python_moonclient/config.py new file mode 100644 index 00000000..d6317820 --- /dev/null +++ b/moonv4/python_moonclient/python_moonclient/config.py @@ -0,0 +1,44 @@ +import base64 +import json +import requests + + +def get_configuration(consul_host, consul_port, key): + url = "http://{}:{}/v1/kv/{}".format(consul_host, consul_port, key) + req = requests.get(url) + if req.status_code != 200: + raise Exception("xxx") + data = req.json() + if len(data) == 1: + data = data[0] + return {data["Key"]: json.loads(base64.b64decode(data["Value"]).decode("utf-8"))} + else: + return [ + {item["Key"]: json.loads(base64.b64decode(item["Value"]).decode("utf-8"))} + for item in data + ] + + +def get_config_data(consul_host, consul_port): + conf_data = dict() + conf_data['manager_host'] = get_configuration(consul_host, consul_port, + 'components/manager')['components/manager']['external']['hostname'] + conf_data['manager_port'] = get_configuration(consul_host, consul_port, + 'components/manager')['components/manager']['external']['port'] + # conf_data['authz_host'] = get_configuration(consul_host, consul_port, + # 'components/interface')['components/interface']['external']['hostname'] + # conf_data['authz_port'] = get_configuration(consul_host, consul_port, + # 'components/interface')['components/interface']['external']['port'] + conf_data['keystone_host'] = get_configuration(consul_host, consul_port, + 'openstack/keystone')['openstack/keystone']['external']['url'] + # conf_data['keystone_port'] = '5000' + conf_data['keystone_user'] = get_configuration(consul_host, consul_port, + 'openstack/keystone')['openstack/keystone']['user'] + conf_data['keystone_password'] = get_configuration(consul_host, consul_port, + 'openstack/keystone')['openstack/keystone']['password'] + conf_data['keystone_project'] = get_configuration(consul_host, consul_port, + 'openstack/keystone')['openstack/keystone']['project'] + return conf_data + +# get_conf_data('88.88.88.2', '30005') +# get_conf_data('127.0.0.1', 8082) diff --git a/moonv4/python_moonclient/requirements.txt b/moonv4/python_moonclient/requirements.txt new file mode 100644 index 00000000..5b80e5f2 --- /dev/null +++ b/moonv4/python_moonclient/requirements.txt @@ -0,0 +1,3 @@ +werkzeug +flask +requests
\ No newline at end of file diff --git a/moonv4/python_moonclient/setup.py b/moonv4/python_moonclient/setup.py new file mode 100644 index 00000000..000e87ca --- /dev/null +++ b/moonv4/python_moonclient/setup.py @@ -0,0 +1,42 @@ +# 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 setuptools import setup, find_packages +import python_moonclient + +with open('requirements.txt') as f: + required = f.read().splitlines() + +setup( + + name='python-moonclient', + + version=python_moonclient.__version__, + + packages=find_packages(), + + author='Thomas Duval & Ruan He', + + author_email='thomas.duval@orange.com, ruan.he@orange.com', + + description='client lib for all the Moon components', + + long_description=open('README.md').read(), + + install_requires=required, + + include_package_data=True, + + url='https://git.opnfv.org/cgit/moon', + + classifiers=[ + 'Programming Language :: Python :: 3', + 'Development Status :: 1 - Planning', + 'License :: OSI Approved', + 'Natural Language :: English', + 'Operating System :: OS Independent', + ], + +) diff --git a/moonv4/python_moonclient/tests/unit_python/conftest.py b/moonv4/python_moonclient/tests/unit_python/conftest.py new file mode 100644 index 00000000..d26df946 --- /dev/null +++ b/moonv4/python_moonclient/tests/unit_python/conftest.py @@ -0,0 +1,12 @@ +import pytest +import requests_mock +import mock_config + + +@pytest.fixture(autouse=True) +def no_requests(monkeypatch): + """ Modify the response from Requests module + """ + with requests_mock.Mocker(real_http=True) as m: + mock_config.register_consul(m) + yield m diff --git a/moonv4/python_moonclient/tests/unit_python/mock_config.py b/moonv4/python_moonclient/tests/unit_python/mock_config.py new file mode 100644 index 00000000..a3084485 --- /dev/null +++ b/moonv4/python_moonclient/tests/unit_python/mock_config.py @@ -0,0 +1,35 @@ +import utilities + + +components_manager_mock = { + "port": 8082, + "bind": "0.0.0.0", + "hostname": "manager", + "container": "wukongsun/moon_manager:v4.3.1", + "external": { + "port": 30001, + "hostname": "88.88.88.2" + } +} + + +openstack_keystone_mock = { + "url": "http://keystone:5000/v3", + "user": "admin", + "password": "p4ssw0rd", + "domain": "default", + "project": "admin", + "check_token": False, + "certificate": False, + "external": { + "url": "http://88.88.88.2:30006/v3" + } +} + + +def register_consul(m): + for component in utilities.COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': utilities.get_b64_conf(component)}] + ) diff --git a/moonv4/python_moonclient/tests/unit_python/requirements.txt b/moonv4/python_moonclient/tests/unit_python/requirements.txt new file mode 100644 index 00000000..3c1ad607 --- /dev/null +++ b/moonv4/python_moonclient/tests/unit_python/requirements.txt @@ -0,0 +1,2 @@ +pytest +requests_mock
\ No newline at end of file diff --git a/moonv4/python_moonclient/tests/unit_python/test_config.py b/moonv4/python_moonclient/tests/unit_python/test_config.py new file mode 100644 index 00000000..21b5f630 --- /dev/null +++ b/moonv4/python_moonclient/tests/unit_python/test_config.py @@ -0,0 +1,8 @@ +import pytest +import utilities + + +def test_authz_request(): + from python_moonclient import config + conf_data = config.get_config_data("consul", 8500) + assert isinstance(conf_data, dict) diff --git a/moonv4/python_moonclient/tests/unit_python/utilities.py b/moonv4/python_moonclient/tests/unit_python/utilities.py new file mode 100644 index 00000000..ae2932c7 --- /dev/null +++ b/moonv4/python_moonclient/tests/unit_python/utilities.py @@ -0,0 +1,153 @@ +import base64 +import json + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin", + "external": { + "url": "http://keystone:5000/v3", + } + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager", + "external": { + "hostname": "manager", + "port": 30001 + } + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "orchestrator" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", + "components/orchestrator", + "components/interface", + "components/wrapper", +) + + +def get_b64_conf(component=None): + if component == "components": + return base64.b64encode( + json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8') + elif component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif not component: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') diff --git a/moonv4/templates/glance/policy.json b/moonv4/templates/glance/policy.json new file mode 100644 index 00000000..5505f67f --- /dev/null +++ b/moonv4/templates/glance/policy.json @@ -0,0 +1,62 @@ +{ + "context_is_admin": "role:admin", + "default": "role:admin", + + "add_image": "http://my_hostname:31001/authz", + "delete_image": "http://my_hostname:31001/authz", + "get_image": "http://my_hostname:31001/authz", + "get_images": "http://my_hostname:31001/authz", + "modify_image": "http://my_hostname:31001/authz", + "publicize_image": "role:admin", + "communitize_image": "", + "copy_from": "", + + "download_image": "", + "upload_image": "", + + "delete_image_location": "", + "get_image_location": "", + "set_image_location": "", + + "add_member": "", + "delete_member": "", + "get_member": "", + "get_members": "", + "modify_member": "", + + "manage_image_cache": "role:admin", + + "get_task": "role:admin", + "get_tasks": "role:admin", + "add_task": "role:admin", + "modify_task": "role:admin", + + "deactivate": "", + "reactivate": "", + + "get_metadef_namespace": "", + "get_metadef_namespaces":"", + "modify_metadef_namespace":"", + "add_metadef_namespace":"", + + "get_metadef_object":"", + "get_metadef_objects":"", + "modify_metadef_object":"", + "add_metadef_object":"", + + "list_metadef_resource_types":"", + "get_metadef_resource_type":"", + "add_metadef_resource_type_association":"", + + "get_metadef_property":"", + "get_metadef_properties":"", + "modify_metadef_property":"", + "add_metadef_property":"", + + "get_metadef_tag":"", + "get_metadef_tags":"", + "modify_metadef_tag":"", + "add_metadef_tag":"", + "add_metadef_tags":"" + +} diff --git a/moonv4/templates/moonforming/Dockerfile b/moonv4/templates/moonforming/Dockerfile new file mode 100644 index 00000000..87a067f9 --- /dev/null +++ b/moonv4/templates/moonforming/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3 +WORKDIR /usr/src/app +RUN pip install --no-cache-dir --upgrade requests pyyaml moon_utilities moon_db + +ENV POPULATE_ARGS "-v" + +ADD . /root +WORKDIR /root + +CMD sh /root/run.sh ${POPULATE_ARGS}
\ No newline at end of file diff --git a/moonv4/templates/moonforming/README.md b/moonv4/templates/moonforming/README.md new file mode 100644 index 00000000..f6327693 --- /dev/null +++ b/moonv4/templates/moonforming/README.md @@ -0,0 +1,12 @@ +Introduction +============ + +moonforming is a container used to automatize the configuration of the Moon patform + +Usage +===== + +```bash +docker run asteroide/moonforming:v1.1 +``` + diff --git a/moonv4/moon_interface/tests/apitests/scenario/mls.py b/moonv4/templates/moonforming/conf/mls.py index 3a3ded43..0e6285c9 100644 --- a/moonv4/moon_interface/tests/apitests/scenario/mls.py +++ b/moonv4/templates/moonforming/conf/mls.py @@ -1,9 +1,10 @@ -pdp_name = "pdp1" +pdp_name = "pdp_mls" policy_name = "MLS Policy example" model_name = "MLS" +policy_genre = "authz" -subjects = {"user0": "", "user1": "", "user2": "", } +subjects = {"adminuser": "", "user1": "", "user2": "", } objects = {"vm0": "", "vm1": "", } actions = {"start": "", "stop": ""} @@ -20,7 +21,7 @@ object_data = { action_data = {"action-type": {"vm-action": "", "storage-action": "", }} subject_assignments = { - "user0": {"subject-security-level": "high"}, + "adminuser": {"subject-security-level": "high"}, "user1": {"subject-security-level": "medium"}, } object_assignments = { @@ -33,21 +34,25 @@ action_assignments = { } meta_rule = { - "mls": {"id": "", "value": ("subject-security-level", "object-security-level", "action-type")}, + "mls": { + "id": "", + "value": ("subject-security-level", + "object-security-level", + "action-type")}, } rules = { "mls": ( { - "rules": ("high", "medium", "vm-action"), + "rule": ("high", "medium", "vm-action"), "instructions": ({"decision": "grant"}) }, { - "rules": ("high", "low", "vm-action"), + "rule": ("high", "low", "vm-action"), "instructions": ({"decision": "grant"}) }, { - "rules": ("medium", "low", "vm-action"), + "rule": ("medium", "low", "vm-action"), "instructions": ({"decision": "grant"}) }, ) diff --git a/moonv4/moon_interface/tests/apitests/scenario/rbac.py b/moonv4/templates/moonforming/conf/rbac.py index 89fd7de8..25c010fd 100644 --- a/moonv4/moon_interface/tests/apitests/scenario/rbac.py +++ b/moonv4/templates/moonforming/conf/rbac.py @@ -1,10 +1,10 @@ -pdp_name = "pdp1" +pdp_name = "pdp_rbac" policy_name = "RBAC policy example" model_name = "RBAC" policy_genre = "authz" -subjects = {"user0": "", "user1": "", } +subjects = {"adminuser": "", "user1": "", } objects = {"vm0": "", "vm1": "", } actions = {"start": "", "stop": ""} @@ -16,9 +16,24 @@ subject_data = {"role": {"admin": "", "employee": "", "*": ""}} object_data = {"id": {"vm0": "", "vm1": "", "*": ""}} action_data = {"action-type": {"vm-action": "", "*": ""}} -subject_assignments = {"user0": ({"role": "employee"}, {"role": "*"}), "user1": ({"role": "employee"}, {"role": "*"}), } -object_assignments = {"vm0": ({"id": "vm0"}, {"id": "*"}), "vm1": ({"id": "vm1"}, {"id": "*"})} -action_assignments = {"start": ({"action-type": "vm-action"}, {"action-type": "*"}), "stop": ({"action-type": "vm-action"}, {"action-type": "*"})} +subject_assignments = { + "adminuser": + ({"role": "admin"}, {"role": "employee"}, {"role": "*"}), + "user1": + ({"role": "employee"}, {"role": "*"}), +} +object_assignments = { + "vm0": + ({"id": "vm0"}, {"id": "*"}), + "vm1": + ({"id": "vm1"}, {"id": "*"}) +} +action_assignments = { + "start": + ({"action-type": "vm-action"}, {"action-type": "*"}), + "stop": + ({"action-type": "vm-action"}, {"action-type": "*"}) +} meta_rule = { "rbac": {"id": "", "value": ("role", "id", "action-type")}, @@ -29,7 +44,9 @@ rules = { { "rule": ("admin", "vm0", "vm-action"), "instructions": ( - {"decision": "grant"}, # "grant" to immediately exit, "continue" to wait for the result of next policy + {"decision": "grant"}, + # "grant" to immediately exit, + # "continue" to wait for the result of next policy ) }, { diff --git a/moonv4/templates/moonforming/conf2consul.py b/moonv4/templates/moonforming/conf2consul.py new file mode 100644 index 00000000..46c99d5c --- /dev/null +++ b/moonv4/templates/moonforming/conf2consul.py @@ -0,0 +1,103 @@ +import os +import sys +import requests +import yaml +import logging +import json +import base64 + +logging.basicConfig(level=logging.INFO) +log = logging.getLogger("moon.conf2consul") +requests_log = logging.getLogger("requests.packages.urllib3") +requests_log.setLevel(logging.WARNING) +requests_log.propagate = True + +if len(sys.argv) == 2: + if os.path.isfile(sys.argv[1]): + CONF_FILENAME = sys.argv[1] + CONSUL_HOST = "consul" + else: + CONF_FILENAME = "moon.conf" + CONSUL_HOST = sys.argv[1] + CONSUL_PORT = 8500 +else: + CONSUL_HOST = sys.argv[1] if len(sys.argv) > 1 else "consul" + CONSUL_PORT = sys.argv[2] if len(sys.argv) > 2 else 8500 + CONF_FILENAME = sys.argv[3] if len(sys.argv) > 3 else "moon.conf" +HEADERS = {"content-type": "application/json"} + + +def search_config_file(): + data_config = None + for _file in ( + CONF_FILENAME, + "conf/moon.conf", + "../moon.conf", + "../conf/moon.conf", + "/etc/moon/moon.conf", + ): + try: + data_config = yaml.safe_load(open(_file)) + except FileNotFoundError: + data_config = None + continue + else: + break + if not data_config: + raise Exception("Configuration file not found...") + return data_config + + +def put(key, value): + url = "http://{host}:{port}/v1/kv/{key}".format(host=CONSUL_HOST, port=CONSUL_PORT, key=key) + log.info(url) + req = requests.put( + url, + headers=HEADERS, + json=value + ) + if req.status_code != 200: + raise Exception("Error connecting to Consul ({}, {})".format(req.status_code, req.text)) + + +def get(key): + url = "http://{host}:{port}/v1/kv/{key}".format(host=CONSUL_HOST, port=CONSUL_PORT, key=key) + req = requests.get(url) + data = req.json() + for item in data: + log.info("{} {} -> {}".format( + req.status_code, + item["Key"], + json.loads(base64.b64decode(item["Value"]).decode("utf-8")) + )) + yield json.loads(base64.b64decode(item["Value"]).decode("utf-8")) + + +def main(): + data_config = search_config_file() + req = requests.head("http://{}:{}/ui/".format(CONSUL_HOST, CONSUL_PORT)) + if req.status_code != 200: + log.critical("Consul is down...") + log.critical("request info: {}/{}".format(req, req.text)) + sys.exit(1) + + put("database", data_config["database"]) + # put("messenger", data_config["messenger"]) + # put("slave", data_config["slave"]) + # put("docker", data_config["docker"]) + put("logging", data_config["logging"]) + put("components_port_start", data_config["components"]["port_start"]) + + for _key, _value in data_config["components"].items(): + if type(_value) is dict: + put("components/{}".format(_key), data_config["components"][_key]) + + for _key, _value in data_config["plugins"].items(): + put("plugins/{}".format(_key), data_config["plugins"][_key]) + + for _key, _value in data_config["openstack"].items(): + put("openstack/{}".format(_key), data_config["openstack"][_key]) + + +main() + diff --git a/moonv4/templates/moonforming/moon.conf b/moonv4/templates/moonforming/moon.conf new file mode 100644 index 00000000..dc498e34 --- /dev/null +++ b/moonv4/templates/moonforming/moon.conf @@ -0,0 +1,79 @@ +database: + url: mysql+pymysql://moon:p4sswOrd1@db/moon + driver: sql + +openstack: + keystone: + url: http://keystone:5000/v3 + user: admin + password: p4ssw0rd + domain: default + project: admin + check_token: false + certificate: false + +plugins: + authz: + container: wukongsun/moon_authz:v4.3 + port: 8081 + session: + container: asteroide/session:latest + port: 8082 + +components: + interface: + port: 8080 + bind: 0.0.0.0 + hostname: interface + container: wukongsun/moon_interface:v4.3 + orchestrator: + port: 8083 + bind: 0.0.0.0 + hostname: orchestrator + container: wukongsun/moon_orchestrator:v4.3 + wrapper: + port: 8080 + bind: 0.0.0.0 + hostname: wrapper + container: wukongsun/moon_wrapper:v4.3.1 + timeout: 5 + manager: + port: 8082 + bind: 0.0.0.0 + hostname: manager + container: wukongsun/moon_manager:v4.3.1 + port_start: 31001 + +logging: + version: 1 + + formatters: + brief: + format: "%(levelname)s %(name)s %(message)-30s" + custom: + format: "%(asctime)-15s %(levelname)s %(name)s %(message)s" + + handlers: + console: + class : logging.StreamHandler + formatter: brief + level : INFO + stream : ext://sys.stdout + file: + class : logging.handlers.RotatingFileHandler + formatter: custom + level : DEBUG + filename: /tmp/moon.log + maxBytes: 1048576 + backupCount: 3 + + loggers: + moon: + level: DEBUG + handlers: [console, file] + propagate: no + + root: + level: ERROR + handlers: [console] + diff --git a/moonv4/moon_interface/tests/apitests/populate_default_values.py b/moonv4/templates/moonforming/populate_default_values.py index 740ad8ed..fa099458 100644 --- a/moonv4/moon_interface/tests/apitests/populate_default_values.py +++ b/moonv4/templates/moonforming/populate_default_values.py @@ -7,8 +7,11 @@ from utils.policies import * parser = argparse.ArgumentParser() parser.add_argument('filename', help='scenario filename', nargs=1) -parser.add_argument("--verbose", "-v", action='store_true', help="verbose mode") +parser.add_argument("--verbose", "-v", action='store_true', + help="verbose mode") parser.add_argument("--debug", "-d", action='store_true', help="debug mode") +parser.add_argument("--keystone-pid", "-k", dest="keystone_pid", default="", + help="Force a particular Keystone Project ID") args = parser.parse_args() FORMAT = '%(asctime)-15s %(levelname)s %(message)s' @@ -29,7 +32,7 @@ requests_log = logging.getLogger("requests.packages.urllib3") requests_log.setLevel(logging.WARNING) requests_log.propagate = True -logger = logging.getLogger(__name__) +logger = logging.getLogger("moonforming") if args.filename: print("Loading: {}".format(args.filename[0])) @@ -202,11 +205,12 @@ def create_policy(model_id, meta_rule_list): def create_pdp(policy_id=None): logger.info("Creating PDP {}".format(scenario.pdp_name)) projects = get_keystone_projects() - admin_project_id = None - for _project in projects['projects']: - if _project['name'] == "admin": - admin_project_id = _project['id'] - assert admin_project_id + project_id = args.keystone_pid + if not project_id: + for _project in projects['projects']: + if _project['name'] == "admin": + project_id = _project['id'] + assert project_id pdps = check_pdp()["pdps"] for pdp_id, pdp_value in pdps.items(): if scenario.pdp_name == pdp_value["name"]: @@ -214,7 +218,7 @@ def create_pdp(policy_id=None): logger.debug("Found existing PDP named {} (will add policy {})".format(scenario.pdp_name, policy_id)) return pdp_id _pdp_id = add_pdp(name=scenario.pdp_name, policy_id=policy_id) - map_to_keystone(pdp_id=_pdp_id, keystone_project_id=admin_project_id) + map_to_keystone(pdp_id=_pdp_id, keystone_project_id=project_id) return _pdp_id if __name__ == "__main__": diff --git a/moonv4/templates/moonforming/run.sh b/moonv4/templates/moonforming/run.sh new file mode 100644 index 00000000..71543f9e --- /dev/null +++ b/moonv4/templates/moonforming/run.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +populate_args=$* + +echo "Waiting for Consul (http://consul:8500)" +while ! python -c "import requests; req = requests.get('http://consul:8500')" 2>/dev/null ; do + sleep 5 ; + echo "." +done + +echo "Consul (http://consul:8500) is up." + +python3 /root/conf2consul.py /etc/moon/moon.conf + +echo "Waiting for DB (tcp://db:3306)" +while ! python -c "import socket, sys; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.connect(('db', 3306)); sys.exit(0)" 2>/dev/null ; do + sleep 5 ; + echo "." +done + +echo "Database (http://db:3306) is up." + +moon_db_manager upgrade + +echo "Waiting for Keystone (http://keystone:5000)" +while ! python -c "import requests; req = requests.get('http://keystone:5000')" 2>/dev/null ; do + sleep 5 ; + echo "." +done + +echo "Keystone (http://keystone:5000) is up." + +echo "Waiting for Manager (http://manager:8082)" +while ! python -c "import requests; req = requests.get('http://manager:8082')" 2>/dev/null ; do + sleep 5 ; + echo "." +done + +echo "Manager (http://manager:8082) is up." + +cd /root + +python3 populate_default_values.py $populate_args /root/conf/rbac.py +python3 populate_default_values.py $populate_args /root/conf/mls.py diff --git a/moonv4/templates/moonforming/utils/__init__.py b/moonv4/templates/moonforming/utils/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/moonv4/templates/moonforming/utils/__init__.py diff --git a/moonv4/templates/moonforming/utils/config.py b/moonv4/templates/moonforming/utils/config.py new file mode 100644 index 00000000..30c8ea4f --- /dev/null +++ b/moonv4/templates/moonforming/utils/config.py @@ -0,0 +1,22 @@ +import yaml + + +def get_config_data(filename="moon.conf"): + data_config = None + for _file in ( + filename, + "conf/moon.conf", + "../moon.conf", + "../conf/moon.conf", + "/etc/moon/moon.conf", + ): + try: + data_config = yaml.safe_load(open(_file)) + except FileNotFoundError: + data_config = None + continue + else: + break + if not data_config: + raise Exception("Configuration file not found...") + return data_config diff --git a/moonv4/moon_interface/tests/apitests/utils/models.py b/moonv4/templates/moonforming/utils/models.py index 68133b5b..3cf31354 100644 --- a/moonv4/moon_interface/tests/apitests/utils/models.py +++ b/moonv4/templates/moonforming/utils/models.py @@ -1,27 +1,12 @@ -import os -import yaml import requests import copy +import utils.config +config = utils.config.get_config_data() -for path in ( - "moon.conf", - "../moon.conf", - "{}/moon_orchestrator/conf/moon.conf".format(os.getenv("MOON_HOME")), - "/etc/moon/moon.conf" -): - try: - config = yaml.safe_load(open(path)) - except FileNotFoundError: - config = None - continue - else: - print("Using {}".format(path)) - break -if not config: - raise Exception("Configuration file not found...") - -URL = "http://{}:{}".format(config['components']['interface']['hostname'], config['components']['interface']['port']) +URL = "http://{}:{}".format( + config['components']['manager']['hostname'], + config['components']['manager']['port']) URL = URL + "{}" HEADERS = {"content-type": "application/json"} diff --git a/moonv4/moon_interface/tests/apitests/utils/pdp.py b/moonv4/templates/moonforming/utils/pdp.py index c0c83441..f3c6df37 100644 --- a/moonv4/moon_interface/tests/apitests/utils/pdp.py +++ b/moonv4/templates/moonforming/utils/pdp.py @@ -1,25 +1,13 @@ -import os -import yaml +import logging import requests +import utils.config -for path in ( - "moon.conf", - "../moon.conf", - "{}/moon_orchestrator/conf/moon.conf".format(os.getenv("MOON_HOME")), - "/etc/moon/moon.conf" -): - try: - config = yaml.safe_load(open(path)) - except FileNotFoundError: - config = None - continue - else: - print("Using {}".format(path)) - break -if not config: - raise Exception("Configuration file not found...") - -URL = "http://{}:{}".format(config['components']['interface']['hostname'], config['components']['interface']['port']) +config = utils.config.get_config_data() +logger = logging.getLogger("moonforming.utils.policies") + +URL = "http://{}:{}".format( + config['components']['manager']['hostname'], + config['components']['manager']['port']) HEADERS = {"content-type": "application/json"} KEYSTONE_USER = config['openstack']['keystone']['user'] KEYSTONE_PASSWORD = config['openstack']['keystone']['password'] @@ -29,7 +17,7 @@ KEYSTONE_SERVER = config['openstack']['keystone']['url'] pdp_template = { "name": "test_pdp", "security_pipeline": [], - "keystone_project_id": "", + "keystone_project_id": None, "description": "test", } @@ -60,6 +48,8 @@ def get_keystone_projects(): } req = requests.post("{}/auth/tokens".format(KEYSTONE_SERVER), json=data_auth, headers=HEADERS) + logger.debug("{}/auth/tokens".format(KEYSTONE_SERVER)) + logger.debug(req.text) assert req.status_code in (200, 201) TOKEN = req.headers['X-Subject-Token'] HEADERS['X-Auth-Token'] = TOKEN @@ -109,6 +99,8 @@ def add_pdp(name="test_pdp", policy_id=None): if policy_id: pdp_template['security_pipeline'].append(policy_id) req = requests.post(URL + "/pdp", json=pdp_template, headers=HEADERS) + logger.debug(req.status_code) + logger.debug(req) assert req.status_code == 200 result = req.json() assert type(result) is dict diff --git a/moonv4/moon_interface/tests/apitests/utils/policies.py b/moonv4/templates/moonforming/utils/policies.py index fdde92ef..bd08291a 100644 --- a/moonv4/moon_interface/tests/apitests/utils/policies.py +++ b/moonv4/templates/moonforming/utils/policies.py @@ -1,25 +1,11 @@ -import os -import yaml +import logging import requests +import utils.config -for path in ( - "moon.conf", - "../moon.conf", - "{}/moon_orchestrator/conf/moon.conf".format(os.getenv("MOON_HOME")), - "/etc/moon/moon.conf" -): - try: - config = yaml.safe_load(open(path)) - except FileNotFoundError: - config = None - continue - else: - print("Using {}".format(path)) - break -if not config: - raise Exception("Configuration file not found...") +config = utils.config.get_config_data() +logger = logging.getLogger("moonforming.utils.policies") -URL = "http://{}:{}".format(config['components']['interface']['hostname'], config['components']['interface']['port']) +URL = "http://{}:{}".format(config['components']['manager']['hostname'], config['components']['manager']['port']) URL = URL + "{}" HEADERS = {"content-type": "application/json"} FILE = open("/tmp/test.log", "w") @@ -124,10 +110,13 @@ def delete_policy(policy_id): def add_subject(policy_id=None, name="test_subject"): subject_template['name'] = name if policy_id: + logger.debug(URL.format("/policies/{}/subjects".format(policy_id))) req = requests.post(URL.format("/policies/{}/subjects".format(policy_id)), json=subject_template, headers=HEADERS) else: + logger.debug(URL.format("/subjects")) req = requests.post(URL.format("/subjects"), json=subject_template, headers=HEADERS) + logger.debug(req.text) assert req.status_code == 200 result = req.json() assert "subjects" in result diff --git a/moonv4/templates/nova/policy.json b/moonv4/templates/nova/policy.json new file mode 100644 index 00000000..29763ce3 --- /dev/null +++ b/moonv4/templates/nova/policy.json @@ -0,0 +1,488 @@ +{ + "context_is_admin": "role:admin", + "admin_or_owner": "is_admin:True or project_id:%(project_id)s", + "default": "rule:admin_or_owner", + + "cells_scheduler_filter:TargetCellFilter": "is_admin:True", + + "compute:create": "http://my_hostname:31001/authz", + "compute:create:attach_network": "", + "compute:create:attach_volume": "", + "compute:create:forced_host": "is_admin:True", + + "compute:get": "http://my_hostname:31001/authz", + "compute:get_all": "http://my_hostname:31001/authz", + "compute:get_all_tenants": "is_admin:True", + + "compute:update": "", + + "compute:get_instance_metadata": "", + "compute:get_all_instance_metadata": "", + "compute:get_all_instance_system_metadata": "", + "compute:update_instance_metadata": "", + "compute:delete_instance_metadata": "", + + "compute:get_instance_faults": "", + "compute:get_diagnostics": "", + "compute:get_instance_diagnostics": "", + + "compute:start": "rule:admin_or_owner", + "compute:stop": "rule:admin_or_owner", + + "compute:get_lock": "", + "compute:lock": "rule:admin_or_owner", + "compute:unlock": "rule:admin_or_owner", + "compute:unlock_override": "rule:admin_api", + + "compute:get_vnc_console": "", + "compute:get_spice_console": "", + "compute:get_rdp_console": "", + "compute:get_serial_console": "", + "compute:get_mks_console": "", + "compute:get_console_output": "", + + "compute:reset_network": "", + "compute:inject_network_info": "", + "compute:add_fixed_ip": "", + "compute:remove_fixed_ip": "", + + "compute:attach_volume": "", + "compute:detach_volume": "", + "compute:swap_volume": "", + + "compute:attach_interface": "", + "compute:detach_interface": "", + + "compute:set_admin_password": "", + + "compute:rescue": "", + "compute:unrescue": "", + + "compute:suspend": "", + "compute:resume": "", + + "compute:pause": "", + "compute:unpause": "", + + "compute:shelve": "", + "compute:shelve_offload": "", + "compute:unshelve": "", + + "compute:snapshot": "", + "compute:snapshot_volume_backed": "", + "compute:backup": "", + + "compute:resize": "", + "compute:confirm_resize": "", + "compute:revert_resize": "", + + "compute:rebuild": "", + "compute:reboot": "", + "compute:delete": "rule:admin_or_owner", + "compute:soft_delete": "rule:admin_or_owner", + "compute:force_delete": "rule:admin_or_owner", + + "compute:security_groups:add_to_instance": "", + "compute:security_groups:remove_from_instance": "", + + "compute:delete": "", + "compute:soft_delete": "", + "compute:force_delete": "", + "compute:restore": "", + + "compute:volume_snapshot_create": "", + "compute:volume_snapshot_delete": "", + + "admin_api": "is_admin:True", + "compute_extension:accounts": "rule:admin_api", + "compute_extension:admin_actions": "rule:admin_api", + "compute_extension:admin_actions:pause": "rule:admin_or_owner", + "compute_extension:admin_actions:unpause": "rule:admin_or_owner", + "compute_extension:admin_actions:suspend": "rule:admin_or_owner", + "compute_extension:admin_actions:resume": "rule:admin_or_owner", + "compute_extension:admin_actions:lock": "rule:admin_or_owner", + "compute_extension:admin_actions:unlock": "rule:admin_or_owner", + "compute_extension:admin_actions:resetNetwork": "rule:admin_api", + "compute_extension:admin_actions:injectNetworkInfo": "rule:admin_api", + "compute_extension:admin_actions:createBackup": "rule:admin_or_owner", + "compute_extension:admin_actions:migrateLive": "rule:admin_api", + "compute_extension:admin_actions:resetState": "rule:admin_api", + "compute_extension:admin_actions:migrate": "rule:admin_api", + "compute_extension:aggregates": "rule:admin_api", + "compute_extension:agents": "rule:admin_api", + "compute_extension:attach_interfaces": "", + "compute_extension:baremetal_nodes": "rule:admin_api", + "compute_extension:cells": "rule:admin_api", + "compute_extension:cells:create": "rule:admin_api", + "compute_extension:cells:delete": "rule:admin_api", + "compute_extension:cells:update": "rule:admin_api", + "compute_extension:cells:sync_instances": "rule:admin_api", + "compute_extension:certificates": "", + "compute_extension:cloudpipe": "rule:admin_api", + "compute_extension:cloudpipe_update": "rule:admin_api", + "compute_extension:config_drive": "", + "compute_extension:console_output": "", + "compute_extension:consoles": "", + "compute_extension:createserverext": "", + "compute_extension:deferred_delete": "", + "compute_extension:disk_config": "", + "compute_extension:evacuate": "rule:admin_api", + "compute_extension:extended_server_attributes": "rule:admin_api", + "compute_extension:extended_status": "", + "compute_extension:extended_availability_zone": "", + "compute_extension:extended_ips": "", + "compute_extension:extended_ips_mac": "", + "compute_extension:extended_vif_net": "", + "compute_extension:extended_volumes": "", + "compute_extension:fixed_ips": "rule:admin_api", + "compute_extension:flavor_access": "", + "compute_extension:flavor_access:addTenantAccess": "rule:admin_api", + "compute_extension:flavor_access:removeTenantAccess": "rule:admin_api", + "compute_extension:flavor_disabled": "", + "compute_extension:flavor_rxtx": "", + "compute_extension:flavor_swap": "", + "compute_extension:flavorextradata": "", + "compute_extension:flavorextraspecs:index": "", + "compute_extension:flavorextraspecs:show": "", + "compute_extension:flavorextraspecs:create": "rule:admin_api", + "compute_extension:flavorextraspecs:update": "rule:admin_api", + "compute_extension:flavorextraspecs:delete": "rule:admin_api", + "compute_extension:flavormanage": "rule:admin_api", + "compute_extension:floating_ip_dns": "", + "compute_extension:floating_ip_pools": "", + "compute_extension:floating_ips": "", + "compute_extension:floating_ips_bulk": "rule:admin_api", + "compute_extension:fping": "", + "compute_extension:fping:all_tenants": "rule:admin_api", + "compute_extension:hide_server_addresses": "is_admin:False", + "compute_extension:hosts": "rule:admin_api", + "compute_extension:hypervisors": "rule:admin_api", + "compute_extension:image_size": "", + "compute_extension:instance_actions": "", + "compute_extension:instance_actions:events": "rule:admin_api", + "compute_extension:instance_usage_audit_log": "rule:admin_api", + "compute_extension:keypairs": "", + "compute_extension:keypairs:index": "", + "compute_extension:keypairs:show": "", + "compute_extension:keypairs:create": "", + "compute_extension:keypairs:delete": "", + "compute_extension:multinic": "", + "compute_extension:networks": "rule:admin_api", + "compute_extension:networks:view": "", + "compute_extension:networks_associate": "rule:admin_api", + "compute_extension:os-tenant-networks": "", + "compute_extension:quotas:show": "", + "compute_extension:quotas:update": "rule:admin_api", + "compute_extension:quotas:delete": "rule:admin_api", + "compute_extension:quota_classes": "", + "compute_extension:rescue": "", + "compute_extension:security_group_default_rules": "rule:admin_api", + "compute_extension:security_groups": "", + "compute_extension:server_diagnostics": "rule:admin_api", + "compute_extension:server_groups": "", + "compute_extension:server_password": "", + "compute_extension:server_usage": "", + "compute_extension:services": "rule:admin_api", + "compute_extension:shelve": "", + "compute_extension:shelveOffload": "rule:admin_api", + "compute_extension:simple_tenant_usage:show": "rule:admin_or_owner", + "compute_extension:simple_tenant_usage:list": "rule:admin_api", + "compute_extension:unshelve": "", + "compute_extension:users": "rule:admin_api", + "compute_extension:virtual_interfaces": "", + "compute_extension:virtual_storage_arrays": "", + "compute_extension:volumes": "", + "compute_extension:volume_attachments:index": "", + "compute_extension:volume_attachments:show": "", + "compute_extension:volume_attachments:create": "", + "compute_extension:volume_attachments:update": "", + "compute_extension:volume_attachments:delete": "", + "compute_extension:volumetypes": "", + "compute_extension:availability_zone:list": "", + "compute_extension:availability_zone:detail": "rule:admin_api", + "compute_extension:used_limits_for_admin": "rule:admin_api", + "compute_extension:migrations:index": "rule:admin_api", + "compute_extension:os-assisted-volume-snapshots:create": "rule:admin_api", + "compute_extension:os-assisted-volume-snapshots:delete": "rule:admin_api", + "compute_extension:console_auth_tokens": "rule:admin_api", + "compute_extension:os-server-external-events:create": "rule:admin_api", + + "network:get_all": "", + "network:get": "", + "network:create": "", + "network:delete": "", + "network:associate": "", + "network:disassociate": "", + "network:get_vifs_by_instance": "", + "network:allocate_for_instance": "", + "network:deallocate_for_instance": "", + "network:validate_networks": "", + "network:get_instance_uuids_by_ip_filter": "", + "network:get_instance_id_by_floating_address": "", + "network:setup_networks_on_host": "", + "network:get_backdoor_port": "", + + "network:get_floating_ip": "", + "network:get_floating_ip_pools": "", + "network:get_floating_ip_by_address": "", + "network:get_floating_ips_by_project": "", + "network:get_floating_ips_by_fixed_address": "", + "network:allocate_floating_ip": "", + "network:associate_floating_ip": "", + "network:disassociate_floating_ip": "", + "network:release_floating_ip": "", + "network:migrate_instance_start": "", + "network:migrate_instance_finish": "", + + "network:get_fixed_ip": "", + "network:get_fixed_ip_by_address": "", + "network:add_fixed_ip_to_instance": "", + "network:remove_fixed_ip_from_instance": "", + "network:add_network_to_project": "", + "network:get_instance_nw_info": "", + + "network:get_dns_domains": "", + "network:add_dns_entry": "", + "network:modify_dns_entry": "", + "network:delete_dns_entry": "", + "network:get_dns_entries_by_address": "", + "network:get_dns_entries_by_name": "", + "network:create_private_dns_domain": "", + "network:create_public_dns_domain": "", + "network:delete_dns_domain": "", + "network:attach_external_network": "rule:admin_api", + "network:get_vif_by_mac_address": "", + + "os_compute_api:servers:detail:get_all_tenants": "is_admin:True", + "os_compute_api:servers:index:get_all_tenants": "is_admin:True", + "os_compute_api:servers:confirm_resize": "", + "os_compute_api:servers:create": "http://my_hostname:31001/authz", + "os_compute_api:servers:create:attach_network": "", + "os_compute_api:servers:create:attach_volume": "", + "os_compute_api:servers:create:forced_host": "rule:admin_api", + "os_compute_api:servers:delete": "http://my_hostname:31001/authz", + "os_compute_api:servers:update": "http://my_hostname:31001/authz", + "os_compute_api:servers:detail": "http://my_hostname:31001/authz", + "os_compute_api:servers:index": "http://my_hostname:31001/authz", + "os_compute_api:servers:reboot": "http://my_hostname:31001/authz", + "os_compute_api:servers:rebuild": "http://my_hostname:31001/authz", + "os_compute_api:servers:resize": "http://my_hostname:31001/authz", + "os_compute_api:servers:revert_resize": "http://my_hostname:31001/authz", + "os_compute_api:servers:show": "http://my_hostname:31001/authz", + "os_compute_api:servers:create_image": "", + "os_compute_api:servers:create_image:allow_volume_backed": "", + "os_compute_api:servers:start": "rule:admin_or_owner", + "os_compute_api:servers:stop": "rule:admin_or_owner", + "os_compute_api:os-access-ips:discoverable": "", + "os_compute_api:os-access-ips": "", + "os_compute_api:os-admin-actions": "rule:admin_api", + "os_compute_api:os-admin-actions:discoverable": "", + "os_compute_api:os-admin-actions:reset_network": "rule:admin_api", + "os_compute_api:os-admin-actions:inject_network_info": "rule:admin_api", + "os_compute_api:os-admin-actions:reset_state": "rule:admin_api", + "os_compute_api:os-admin-password": "", + "os_compute_api:os-admin-password:discoverable": "", + "os_compute_api:os-aggregates:discoverable": "", + "os_compute_api:os-aggregates:index": "rule:admin_api", + "os_compute_api:os-aggregates:create": "rule:admin_api", + "os_compute_api:os-aggregates:show": "rule:admin_api", + "os_compute_api:os-aggregates:update": "rule:admin_api", + "os_compute_api:os-aggregates:delete": "rule:admin_api", + "os_compute_api:os-aggregates:add_host": "rule:admin_api", + "os_compute_api:os-aggregates:remove_host": "rule:admin_api", + "os_compute_api:os-aggregates:set_metadata": "rule:admin_api", + "os_compute_api:os-agents": "rule:admin_api", + "os_compute_api:os-agents:discoverable": "", + "os_compute_api:os-attach-interfaces": "", + "os_compute_api:os-attach-interfaces:discoverable": "", + "os_compute_api:os-baremetal-nodes": "rule:admin_api", + "os_compute_api:os-baremetal-nodes:discoverable": "", + "os_compute_api:os-block-device-mapping-v1:discoverable": "", + "os_compute_api:os-cells": "rule:admin_api", + "os_compute_api:os-cells:create": "rule:admin_api", + "os_compute_api:os-cells:delete": "rule:admin_api", + "os_compute_api:os-cells:update": "rule:admin_api", + "os_compute_api:os-cells:sync_instances": "rule:admin_api", + "os_compute_api:os-cells:discoverable": "", + "os_compute_api:os-certificates:create": "", + "os_compute_api:os-certificates:show": "", + "os_compute_api:os-certificates:discoverable": "", + "os_compute_api:os-cloudpipe": "rule:admin_api", + "os_compute_api:os-cloudpipe:discoverable": "", + "os_compute_api:os-config-drive": "", + "os_compute_api:os-consoles:discoverable": "", + "os_compute_api:os-consoles:create": "", + "os_compute_api:os-consoles:delete": "", + "os_compute_api:os-consoles:index": "", + "os_compute_api:os-consoles:show": "", + "os_compute_api:os-console-output:discoverable": "", + "os_compute_api:os-console-output": "", + "os_compute_api:os-remote-consoles": "", + "os_compute_api:os-remote-consoles:discoverable": "", + "os_compute_api:os-create-backup:discoverable": "", + "os_compute_api:os-create-backup": "rule:admin_or_owner", + "os_compute_api:os-deferred-delete": "", + "os_compute_api:os-deferred-delete:discoverable": "", + "os_compute_api:os-disk-config": "", + "os_compute_api:os-disk-config:discoverable": "", + "os_compute_api:os-evacuate": "rule:admin_api", + "os_compute_api:os-evacuate:discoverable": "", + "os_compute_api:os-extended-server-attributes": "rule:admin_api", + "os_compute_api:os-extended-server-attributes:discoverable": "", + "os_compute_api:os-extended-status": "", + "os_compute_api:os-extended-status:discoverable": "", + "os_compute_api:os-extended-availability-zone": "", + "os_compute_api:os-extended-availability-zone:discoverable": "", + "os_compute_api:extensions": "", + "os_compute_api:extension_info:discoverable": "", + "os_compute_api:os-extended-volumes": "", + "os_compute_api:os-extended-volumes:discoverable": "", + "os_compute_api:os-fixed-ips": "rule:admin_api", + "os_compute_api:os-fixed-ips:discoverable": "", + "os_compute_api:os-flavor-access": "", + "os_compute_api:os-flavor-access:discoverable": "", + "os_compute_api:os-flavor-access:remove_tenant_access": "rule:admin_api", + "os_compute_api:os-flavor-access:add_tenant_access": "rule:admin_api", + "os_compute_api:os-flavor-rxtx": "", + "os_compute_api:os-flavor-rxtx:discoverable": "", + "os_compute_api:flavors:discoverable": "", + "os_compute_api:os-flavor-extra-specs:discoverable": "", + "os_compute_api:os-flavor-extra-specs:index": "", + "os_compute_api:os-flavor-extra-specs:show": "", + "os_compute_api:os-flavor-extra-specs:create": "rule:admin_api", + "os_compute_api:os-flavor-extra-specs:update": "rule:admin_api", + "os_compute_api:os-flavor-extra-specs:delete": "rule:admin_api", + "os_compute_api:os-flavor-manage:discoverable": "", + "os_compute_api:os-flavor-manage": "rule:admin_api", + "os_compute_api:os-floating-ip-dns": "", + "os_compute_api:os-floating-ip-dns:discoverable": "", + "os_compute_api:os-floating-ip-dns:domain:update": "rule:admin_api", + "os_compute_api:os-floating-ip-dns:domain:delete": "rule:admin_api", + "os_compute_api:os-floating-ip-pools": "", + "os_compute_api:os-floating-ip-pools:discoverable": "", + "os_compute_api:os-floating-ips": "", + "os_compute_api:os-floating-ips:discoverable": "", + "os_compute_api:os-floating-ips-bulk": "rule:admin_api", + "os_compute_api:os-floating-ips-bulk:discoverable": "", + "os_compute_api:os-fping": "", + "os_compute_api:os-fping:discoverable": "", + "os_compute_api:os-fping:all_tenants": "rule:admin_api", + "os_compute_api:os-hide-server-addresses": "is_admin:False", + "os_compute_api:os-hide-server-addresses:discoverable": "", + "os_compute_api:os-hosts": "rule:admin_api", + "os_compute_api:os-hosts:discoverable": "", + "os_compute_api:os-hypervisors": "rule:admin_api", + "os_compute_api:os-hypervisors:discoverable": "", + "os_compute_api:images:discoverable": "", + "os_compute_api:image-size": "", + "os_compute_api:image-size:discoverable": "", + "os_compute_api:os-instance-actions": "", + "os_compute_api:os-instance-actions:discoverable": "", + "os_compute_api:os-instance-actions:events": "rule:admin_api", + "os_compute_api:os-instance-usage-audit-log": "rule:admin_api", + "os_compute_api:os-instance-usage-audit-log:discoverable": "", + "os_compute_api:ips:discoverable": "", + "os_compute_api:ips:index": "rule:admin_or_owner", + "os_compute_api:ips:show": "rule:admin_or_owner", + "os_compute_api:os-keypairs:discoverable": "", + "os_compute_api:os-keypairs": "", + "os_compute_api:os-keypairs:index": "rule:admin_api or user_id:%(user_id)s", + "os_compute_api:os-keypairs:show": "rule:admin_api or user_id:%(user_id)s", + "os_compute_api:os-keypairs:create": "rule:admin_api or user_id:%(user_id)s", + "os_compute_api:os-keypairs:delete": "rule:admin_api or user_id:%(user_id)s", + "os_compute_api:limits:discoverable": "", + "os_compute_api:limits": "", + "os_compute_api:os-lock-server:discoverable": "", + "os_compute_api:os-lock-server:lock": "rule:admin_or_owner", + "os_compute_api:os-lock-server:unlock": "rule:admin_or_owner", + "os_compute_api:os-lock-server:unlock:unlock_override": "rule:admin_api", + "os_compute_api:os-migrate-server:discoverable": "", + "os_compute_api:os-migrate-server:migrate": "rule:admin_api", + "os_compute_api:os-migrate-server:migrate_live": "rule:admin_api", + "os_compute_api:os-multinic": "", + "os_compute_api:os-multinic:discoverable": "", + "os_compute_api:os-networks": "rule:admin_api", + "os_compute_api:os-networks:view": "", + "os_compute_api:os-networks:discoverable": "", + "os_compute_api:os-networks-associate": "rule:admin_api", + "os_compute_api:os-networks-associate:discoverable": "", + "os_compute_api:os-pause-server:discoverable": "", + "os_compute_api:os-pause-server:pause": "rule:admin_or_owner", + "os_compute_api:os-pause-server:unpause": "rule:admin_or_owner", + "os_compute_api:os-pci:pci_servers": "", + "os_compute_api:os-pci:discoverable": "", + "os_compute_api:os-pci:index": "rule:admin_api", + "os_compute_api:os-pci:detail": "rule:admin_api", + "os_compute_api:os-pci:show": "rule:admin_api", + "os_compute_api:os-personality:discoverable": "", + "os_compute_api:os-preserve-ephemeral-rebuild:discoverable": "", + "os_compute_api:os-quota-sets:discoverable": "", + "os_compute_api:os-quota-sets:show": "rule:admin_or_owner", + "os_compute_api:os-quota-sets:defaults": "", + "os_compute_api:os-quota-sets:update": "rule:admin_api", + "os_compute_api:os-quota-sets:delete": "rule:admin_api", + "os_compute_api:os-quota-sets:detail": "rule:admin_api", + "os_compute_api:os-quota-class-sets:update": "rule:admin_api", + "os_compute_api:os-quota-class-sets:show": "is_admin:True or quota_class:%(quota_class)s", + "os_compute_api:os-quota-class-sets:discoverable": "", + "os_compute_api:os-rescue": "", + "os_compute_api:os-rescue:discoverable": "", + "os_compute_api:os-scheduler-hints:discoverable": "", + "os_compute_api:os-security-group-default-rules:discoverable": "", + "os_compute_api:os-security-group-default-rules": "rule:admin_api", + "os_compute_api:os-security-groups": "", + "os_compute_api:os-security-groups:discoverable": "", + "os_compute_api:os-server-diagnostics": "rule:admin_api", + "os_compute_api:os-server-diagnostics:discoverable": "", + "os_compute_api:os-server-password": "", + "os_compute_api:os-server-password:discoverable": "", + "os_compute_api:os-server-usage": "", + "os_compute_api:os-server-usage:discoverable": "", + "os_compute_api:os-server-groups": "", + "os_compute_api:os-server-groups:discoverable": "", + "os_compute_api:os-services": "rule:admin_api", + "os_compute_api:os-services:discoverable": "", + "os_compute_api:server-metadata:discoverable": "", + "os_compute_api:server-metadata:index": "rule:admin_or_owner", + "os_compute_api:server-metadata:show": "rule:admin_or_owner", + "os_compute_api:server-metadata:delete": "rule:admin_or_owner", + "os_compute_api:server-metadata:create": "rule:admin_or_owner", + "os_compute_api:server-metadata:update": "rule:admin_or_owner", + "os_compute_api:server-metadata:update_all": "rule:admin_or_owner", + "os_compute_api:servers:discoverable": "", + "os_compute_api:os-shelve:shelve": "", + "os_compute_api:os-shelve:shelve:discoverable": "", + "os_compute_api:os-shelve:shelve_offload": "rule:admin_api", + "os_compute_api:os-simple-tenant-usage:discoverable": "", + "os_compute_api:os-simple-tenant-usage:show": "rule:admin_or_owner", + "os_compute_api:os-simple-tenant-usage:list": "rule:admin_api", + "os_compute_api:os-suspend-server:discoverable": "", + "os_compute_api:os-suspend-server:suspend": "rule:admin_or_owner", + "os_compute_api:os-suspend-server:resume": "rule:admin_or_owner", + "os_compute_api:os-tenant-networks": "rule:admin_or_owner", + "os_compute_api:os-tenant-networks:discoverable": "", + "os_compute_api:os-shelve:unshelve": "", + "os_compute_api:os-user-data:discoverable": "", + "os_compute_api:os-virtual-interfaces": "", + "os_compute_api:os-virtual-interfaces:discoverable": "", + "os_compute_api:os-volumes": "", + "os_compute_api:os-volumes:discoverable": "", + "os_compute_api:os-volumes-attachments:index": "", + "os_compute_api:os-volumes-attachments:show": "", + "os_compute_api:os-volumes-attachments:create": "", + "os_compute_api:os-volumes-attachments:update": "", + "os_compute_api:os-volumes-attachments:delete": "", + "os_compute_api:os-volumes-attachments:discoverable": "", + "os_compute_api:os-availability-zone:list": "", + "os_compute_api:os-availability-zone:discoverable": "", + "os_compute_api:os-availability-zone:detail": "rule:admin_api", + "os_compute_api:os-used-limits": "rule:admin_api", + "os_compute_api:os-used-limits:discoverable": "", + "os_compute_api:os-migrations:index": "rule:admin_api", + "os_compute_api:os-migrations:discoverable": "", + "os_compute_api:os-assisted-volume-snapshots:create": "rule:admin_api", + "os_compute_api:os-assisted-volume-snapshots:delete": "rule:admin_api", + "os_compute_api:os-assisted-volume-snapshots:discoverable": "", + "os_compute_api:os-console-auth-tokens": "rule:admin_api", + "os_compute_api:os-server-external-events:create": "rule:admin_api" +} diff --git a/moonv4/templates/python_unit_test/Dockerfile b/moonv4/templates/python_unit_test/Dockerfile new file mode 100644 index 00000000..b8fb5151 --- /dev/null +++ b/moonv4/templates/python_unit_test/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3 + +RUN pip install pytest requests_mock requests --upgrade +ADD requirements.txt /root +RUN pip install -r /root/requirements.txt --upgrade + +ADD run_tests.sh /root +CMD ["sh", "/root/run_tests.sh"]
\ No newline at end of file diff --git a/moonv4/templates/python_unit_test/README.md b/moonv4/templates/python_unit_test/README.md new file mode 100644 index 00000000..45d3a988 --- /dev/null +++ b/moonv4/templates/python_unit_test/README.md @@ -0,0 +1,8 @@ +# Python Unit Test Docker + +## Build +- `docker image build -t wukongsun/moon_python_unit_test .` + +## Push to DockerHub +- `docker login --username=wukongsun` +- `docker image push wukongsun/moon_python_unit_test`
\ No newline at end of file diff --git a/moonv4/moon_router/requirements.txt b/moonv4/templates/python_unit_test/requirements.txt index 9eb4e201..b611b008 100644 --- a/moonv4/moon_router/requirements.txt +++ b/moonv4/templates/python_unit_test/requirements.txt @@ -1,7 +1,10 @@ kombu !=4.0.1,!=4.0.0 oslo.messaging oslo.config -vine oslo.log -babel -moon_utilities
\ No newline at end of file +vine +werkzeug +flask +requests +pytest +requests_mock
\ No newline at end of file diff --git a/moonv4/templates/python_unit_test/run_tests.sh b/moonv4/templates/python_unit_test/run_tests.sh new file mode 100644 index 00000000..6c586f87 --- /dev/null +++ b/moonv4/templates/python_unit_test/run_tests.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +cd /data +pip3 install -r tests/unit_python/requirements.txt --upgrade +pip3 install . + +if [ -f /data/tests/unit_python/run_tests.sh ]; +then + bash /data/tests/unit_python/run_tests.sh; +fi + +cd /data/tests/unit_python +pytest . diff --git a/moonv4/tests/get_keystone_projects.py b/moonv4/tests/get_keystone_projects.py new file mode 100644 index 00000000..7b37b0e7 --- /dev/null +++ b/moonv4/tests/get_keystone_projects.py @@ -0,0 +1,19 @@ +from utils import pdp +from utils import parse +from utils import models +from utils import policies +from utils import pdp + +if __name__ == "__main__": + args = parse.parse() + consul_host = args.consul_host + consul_port = args.consul_port + + models.init(consul_host, consul_port) + policies.init(consul_host, consul_port) + pdp.init(consul_host, consul_port) + + projects = pdp.get_keystone_projects() + + for _project in projects['projects']: + print("{} {}".format(_project['id'], _project['name'])) diff --git a/moonv4/tests/populate_default_values.py b/moonv4/tests/populate_default_values.py index 740ad8ed..28795526 100644 --- a/moonv4/tests/populate_default_values.py +++ b/moonv4/tests/populate_default_values.py @@ -1,42 +1,11 @@ -import argparse import logging from importlib.machinery import SourceFileLoader -from utils.pdp import * -from utils.models import * -from utils.policies import * +from utils import parse +from utils import models +from utils import policies +from utils import pdp -parser = argparse.ArgumentParser() -parser.add_argument('filename', help='scenario filename', nargs=1) -parser.add_argument("--verbose", "-v", action='store_true', help="verbose mode") -parser.add_argument("--debug", "-d", action='store_true', help="debug mode") -args = parser.parse_args() - -FORMAT = '%(asctime)-15s %(levelname)s %(message)s' -if args.debug: - logging.basicConfig( - format=FORMAT, - level=logging.DEBUG) -elif args.verbose: - logging.basicConfig( - format=FORMAT, - level=logging.INFO) -else: - logging.basicConfig( - format=FORMAT, - level=logging.WARNING) - -requests_log = logging.getLogger("requests.packages.urllib3") -requests_log.setLevel(logging.WARNING) -requests_log.propagate = True - -logger = logging.getLogger(__name__) - -if args.filename: - print("Loading: {}".format(args.filename[0])) - -m = SourceFileLoader("scenario", args.filename[0]) - -scenario = m.load_module() +logger = None def create_model(model_id=None): @@ -44,16 +13,16 @@ def create_model(model_id=None): logger.info("Creating model {}".format(scenario.model_name)) if not model_id: logger.info("Add model") - model_id = add_model(name=scenario.model_name) + model_id = models.add_model(name=scenario.model_name) logger.info("Add subject categories") for cat in scenario.subject_categories: - scenario.subject_categories[cat] = add_subject_category(name=cat) + scenario.subject_categories[cat] = models.add_subject_category(name=cat) logger.info("Add object categories") for cat in scenario.object_categories: - scenario.object_categories[cat] = add_object_category(name=cat) + scenario.object_categories[cat] = models.add_object_category(name=cat) logger.info("Add action categories") for cat in scenario.action_categories: - scenario.action_categories[cat] = add_action_category(name=cat) + scenario.action_categories[cat] = models.add_action_category(name=cat) sub_cat = [] ob_cat = [] act_cat = [] @@ -66,14 +35,14 @@ def create_model(model_id=None): ob_cat.append(scenario.object_categories[item]) elif item in scenario.action_categories: act_cat.append(scenario.action_categories[item]) - meta_rules = check_meta_rule(meta_rule_id=None) + meta_rules = models.check_meta_rule(meta_rule_id=None) for _meta_rule_id, _meta_rule_value in meta_rules['meta_rules'].items(): if _meta_rule_value['name'] == item_name: meta_rule_id = _meta_rule_id break else: logger.info("Add meta rule") - meta_rule_id = add_meta_rule(item_name, sub_cat, ob_cat, act_cat) + meta_rule_id = models.add_meta_rule(item_name, sub_cat, ob_cat, act_cat) item_value["id"] = meta_rule_id if meta_rule_id not in meta_rule_list: meta_rule_list.append(meta_rule_id) @@ -83,51 +52,51 @@ def create_model(model_id=None): def create_policy(model_id, meta_rule_list): if args.verbose: logger.info("Creating policy {}".format(scenario.policy_name)) - _policies = check_policy() + _policies = policies.check_policy() for _policy_id, _policy_value in _policies["policies"].items(): if _policy_value['name'] == scenario.policy_name: policy_id = _policy_id break else: - policy_id = add_policy(name=scenario.policy_name, genre=scenario.policy_genre) + policy_id = policies.add_policy(name=scenario.policy_name, genre=scenario.policy_genre) - update_policy(policy_id, model_id) + policies.update_policy(policy_id, model_id) for meta_rule_id in meta_rule_list: logger.debug("add_meta_rule_to_model {} {}".format(model_id, meta_rule_id)) - add_meta_rule_to_model(model_id, meta_rule_id) + models.add_meta_rule_to_model(model_id, meta_rule_id) logger.info("Add subject data") for subject_cat_name in scenario.subject_data: for subject_data_name in scenario.subject_data[subject_cat_name]: - data_id = scenario.subject_data[subject_cat_name][subject_data_name] = add_subject_data( + data_id = scenario.subject_data[subject_cat_name][subject_data_name] = policies.add_subject_data( policy_id=policy_id, category_id=scenario.subject_categories[subject_cat_name], name=subject_data_name) scenario.subject_data[subject_cat_name][subject_data_name] = data_id logger.info("Add object data") for object_cat_name in scenario.object_data: for object_data_name in scenario.object_data[object_cat_name]: - data_id = scenario.object_data[object_cat_name][object_data_name] = add_object_data( + data_id = scenario.object_data[object_cat_name][object_data_name] = policies.add_object_data( policy_id=policy_id, category_id=scenario.object_categories[object_cat_name], name=object_data_name) scenario.object_data[object_cat_name][object_data_name] = data_id logger.info("Add action data") for action_cat_name in scenario.action_data: for action_data_name in scenario.action_data[action_cat_name]: - data_id = scenario.action_data[action_cat_name][action_data_name] = add_action_data( + data_id = scenario.action_data[action_cat_name][action_data_name] = policies.add_action_data( policy_id=policy_id, category_id=scenario.action_categories[action_cat_name], name=action_data_name) scenario.action_data[action_cat_name][action_data_name] = data_id logger.info("Add subjects") for name in scenario.subjects: - scenario.subjects[name] = add_subject(policy_id, name=name) + scenario.subjects[name] = policies.add_subject(policy_id, name=name) logger.info("Add objects") for name in scenario.objects: - scenario.objects[name] = add_object(policy_id, name=name) + scenario.objects[name] = policies.add_object(policy_id, name=name) logger.info("Add actions") for name in scenario.actions: - scenario.actions[name] = add_action(policy_id, name=name) + scenario.actions[name] = policies.add_action(policy_id, name=name) logger.info("Add subject assignments") for subject_name in scenario.subject_assignments: @@ -138,14 +107,14 @@ def create_policy(model_id, meta_rule_list): subject_cat_id = scenario.subject_categories[subject_category_name] for data in scenario.subject_assignments[subject_name]: subject_data_id = scenario.subject_data[subject_category_name][data[subject_category_name]] - add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) + policies.add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) else: for subject_category_name in scenario.subject_assignments[subject_name]: subject_id = scenario.subjects[subject_name] subject_cat_id = scenario.subject_categories[subject_category_name] subject_data_id = scenario.subject_data[subject_category_name][scenario.subject_assignments[subject_name][subject_category_name]] - add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) - + policies.add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) + logger.info("Add object assignments") for object_name in scenario.object_assignments: if type(scenario.object_assignments[object_name]) in (list, tuple): @@ -155,13 +124,13 @@ def create_policy(model_id, meta_rule_list): object_cat_id = scenario.object_categories[object_category_name] for data in scenario.object_assignments[object_name]: object_data_id = scenario.object_data[object_category_name][data[object_category_name]] - add_object_assignments(policy_id, object_id, object_cat_id, object_data_id) + policies.add_object_assignments(policy_id, object_id, object_cat_id, object_data_id) else: for object_category_name in scenario.object_assignments[object_name]: object_id = scenario.objects[object_name] object_cat_id = scenario.object_categories[object_category_name] object_data_id = scenario.object_data[object_category_name][scenario.object_assignments[object_name][object_category_name]] - add_object_assignments(policy_id, object_id, object_cat_id, object_data_id) + policies.add_object_assignments(policy_id, object_id, object_cat_id, object_data_id) logger.info("Add action assignments") for action_name in scenario.action_assignments: @@ -172,13 +141,13 @@ def create_policy(model_id, meta_rule_list): action_cat_id = scenario.action_categories[action_category_name] for data in scenario.action_assignments[action_name]: action_data_id = scenario.action_data[action_category_name][data[action_category_name]] - add_action_assignments(policy_id, action_id, action_cat_id, action_data_id) + policies.add_action_assignments(policy_id, action_id, action_cat_id, action_data_id) else: for action_category_name in scenario.action_assignments[action_name]: action_id = scenario.actions[action_name] action_cat_id = scenario.action_categories[action_category_name] action_data_id = scenario.action_data[action_category_name][scenario.action_assignments[action_name][action_category_name]] - add_action_assignments(policy_id, action_id, action_cat_id, action_data_id) + policies.add_action_assignments(policy_id, action_id, action_cat_id, action_data_id) logger.info("Add rules") for meta_rule_name in scenario.rules: @@ -195,30 +164,50 @@ def create_policy(model_id, meta_rule_list): elif category_name in scenario.action_categories: data_list.append(scenario.action_data[category_name][data_name]) instructions = rule["instructions"] - add_rule(policy_id, meta_rule_value["id"], data_list, instructions) + policies.add_rule(policy_id, meta_rule_value["id"], data_list, instructions) return policy_id -def create_pdp(policy_id=None): +def create_pdp(policy_id=None, project_id=None): logger.info("Creating PDP {}".format(scenario.pdp_name)) - projects = get_keystone_projects() - admin_project_id = None - for _project in projects['projects']: - if _project['name'] == "admin": - admin_project_id = _project['id'] - assert admin_project_id - pdps = check_pdp()["pdps"] + projects = pdp.get_keystone_projects() + if not project_id: + for _project in projects['projects']: + if _project['name'] == "admin": + project_id = _project['id'] + assert project_id + pdps = pdp.check_pdp()["pdps"] for pdp_id, pdp_value in pdps.items(): if scenario.pdp_name == pdp_value["name"]: - update_pdp(pdp_id, policy_id=policy_id) + pdp.update_pdp(pdp_id, policy_id=policy_id) logger.debug("Found existing PDP named {} (will add policy {})".format(scenario.pdp_name, policy_id)) return pdp_id - _pdp_id = add_pdp(name=scenario.pdp_name, policy_id=policy_id) - map_to_keystone(pdp_id=_pdp_id, keystone_project_id=admin_project_id) + _pdp_id = pdp.add_pdp(name=scenario.pdp_name, policy_id=policy_id) + pdp.map_to_keystone(pdp_id=_pdp_id, keystone_project_id=project_id) return _pdp_id + if __name__ == "__main__": - _models = check_model() + logger = logging.getLogger("moonforming") + requests_log = logging.getLogger("requests.packages.urllib3") + requests_log.setLevel(logging.WARNING) + requests_log.propagate = True + + args = parse.parse() + consul_host = args.consul_host + consul_port = args.consul_port + project_id = args.keystone_pid + + models.init(consul_host, consul_port) + policies.init(consul_host, consul_port) + pdp.init(consul_host, consul_port) + + if args.filename: + print("Loading: {}".format(args.filename[0])) + m = SourceFileLoader("scenario", args.filename[0]) + scenario = m.load_module() + + _models = models.check_model() for _model_id, _model_value in _models['models'].items(): if _model_value['name'] == scenario.model_name: model_id = _model_id @@ -228,4 +217,4 @@ if __name__ == "__main__": else: model_id, meta_rule_list = create_model() policy_id = create_policy(model_id, meta_rule_list) - pdp_id = create_pdp(policy_id) + pdp_id = create_pdp(policy_id=policy_id, project_id=project_id) diff --git a/moonv4/tests/send_authz.py b/moonv4/tests/send_authz.py new file mode 100644 index 00000000..5766a0ec --- /dev/null +++ b/moonv4/tests/send_authz.py @@ -0,0 +1,243 @@ +import sys +import copy +import logging +import threading +from importlib.machinery import SourceFileLoader +import requests +import time +import json +import random +from uuid import uuid4 +from utils.pdp import check_pdp +from utils.parse import parse +import utils.config + + +logger = None +HOST_MANAGER = None +PORT_MANAGER = None +HOST_AUTHZ = None +PORT_AUTHZ = None +HOST_KEYSTONE = None +PORT_KEYSTONE = None + +lock = threading.Lock() +logger = logging.getLogger(__name__) + + +def get_scenario(args): + m = SourceFileLoader("scenario", args.filename[0]) + return m.load_module() + + +def get_keystone_id(pdp_name): + global HOST_MANAGER, PORT_MANAGER + keystone_project_id = None + for pdp_key, pdp_value in check_pdp(moon_url="http://{}:{}".format(HOST_MANAGER, PORT_MANAGER))["pdps"].items(): + if pdp_name: + if pdp_name != pdp_value["name"]: + continue + if pdp_value['security_pipeline'] and pdp_value["keystone_project_id"]: + logger.debug("Found pdp with keystone_project_id={}".format(pdp_value["keystone_project_id"])) + keystone_project_id = pdp_value["keystone_project_id"] + + if not keystone_project_id: + logger.error("Cannot find PDP with keystone project ID") + sys.exit(1) + return keystone_project_id + + +def _construct_payload(creds, current_rule, enforcer, target): + # Convert instances of object() in target temporarily to + # empty dict to avoid circular reference detection + # errors in jsonutils.dumps(). + temp_target = copy.deepcopy(target) + for key in target.keys(): + element = target.get(key) + if type(element) is object: + temp_target[key] = {} + _data = _json = None + if enforcer: + _data = {'rule': json.dumps(current_rule), + 'target': json.dumps(temp_target), + 'credentials': json.dumps(creds)} + else: + _json = {'rule': current_rule, + 'target': temp_target, + 'credentials': creds} + return _data, _json + + +def _send(url, data=None, stress_test=False): + current_request = dict() + current_request['url'] = url + try: + if stress_test: + current_request['start'] = time.time() + # with lock: + res = requests.get(url) + current_request['end'] = time.time() + current_request['delta'] = current_request["end"] - current_request["start"] + else: + with lock: + current_request['start'] = time.time() + if data: + data, _ = _construct_payload(data['credentials'], data['rule'], True, data['target']) + res = requests.post(url, json=data, + headers={'content-type': "application/x-www-form-urlencode"} + ) + else: + res = requests.get(url) + current_request['end'] = time.time() + current_request['delta'] = current_request["end"] - current_request["start"] + except requests.exceptions.ConnectionError: + logger.warning("Unable to connect to server") + return {} + if not stress_test: + try: + j = res.json() + if res.status_code == 200: + logger.warning("\033[1m{}\033[m \033[32mGrant\033[m".format(url)) + elif res.status_code == 401: + logger.warning("\033[1m{}\033[m \033[31mDeny\033[m".format(url)) + else: + logger.error("\033[1m{}\033[m {} {}".format(url, res.status_code, res.text)) + except Exception as e: + if res.text == "True": + logger.warning("\033[1m{}\033[m \033[32mGrant\033[m".format(url)) + elif res.text == "False": + logger.warning("\033[1m{}\033[m \033[31mDeny\033[m".format(url)) + else: + logger.error("\033[1m{}\033[m {} {}".format(url, res.status_code, res.text)) + logger.exception(e) + logger.error(res.text) + else: + if j.get("result"): + # logger.warning("{} \033[32m{}\033[m".format(url, j.get("result"))) + logger.debug("{}".format(j.get("error", ""))) + current_request['result'] = "Grant" + else: + # logger.warning("{} \033[31m{}\033[m".format(url, "Deny")) + logger.debug("{}".format(j)) + current_request['result'] = "Deny" + return current_request + + +class AsyncGet(threading.Thread): + + def __init__(self, url, semaphore=None, **kwargs): + threading.Thread.__init__(self) + self.url = url + self.kwargs = kwargs + self.sema = semaphore + self.result = dict() + self.uuid = uuid4().hex + self.index = kwargs.get("index", 0) + + def run(self): + self.result = _send(self.url, + data=self.kwargs.get("data"), + stress_test=self.kwargs.get("stress_test", False)) + self.result['index'] = self.index + + +def send_requests(scenario, keystone_project_id, request_second=1, limit=500, + dry_run=None, stress_test=False, destination="wrapper"): + global HOST_AUTHZ, PORT_AUTHZ + backgrounds = [] + time_data = list() + start_timing = time.time() + request_cpt = 0 + SUBJECTS = tuple(scenario.subjects.keys()) + OBJECTS = tuple(scenario.objects.keys()) + ACTIONS = tuple(scenario.actions.keys()) + while request_cpt < limit: + rule = (random.choice(SUBJECTS), random.choice(OBJECTS), random.choice(ACTIONS)) + if destination.lower() == "wrapper": + url = "http://{}:{}/authz".format(HOST_AUTHZ, PORT_AUTHZ) + data = { + 'target': { + "user_id": random.choice(SUBJECTS), + "target": { + "name": random.choice(OBJECTS) + }, + "project_id": keystone_project_id + }, + 'credentials': None, + 'rule': random.choice(ACTIONS) + } + else: + url = "http://{}:{}/authz/{}/{}".format(HOST_AUTHZ, PORT_AUTHZ, keystone_project_id, "/".join(rule)) + data = None + if dry_run: + logger.info(url) + continue + request_cpt += 1 + if stress_test: + time_data.append(copy.deepcopy(_send(url, stress_test=stress_test))) + else: + background = AsyncGet(url, stress_test=stress_test, data=data, + index=request_cpt) + backgrounds.append(background) + background.start() + if request_second > 0: + if request_cpt % request_second == 0: + if time.time()-start_timing < 1: + while True: + if time.time()-start_timing > 1: + break + start_timing = time.time() + if not stress_test: + for background in backgrounds: + background.join() + if background.result: + time_data.append(copy.deepcopy(background.result)) + return time_data + + +def save_data(filename, time_data): + json.dump(time_data, open(filename, "w")) + + +def get_delta(time_data): + time_delta = list() + time_delta_sum1 = 0 + for item in time_data: + time_delta.append(item['delta']) + time_delta_sum1 += item['delta'] + time_delta_average1 = time_delta_sum1 / len(time_data) + return time_delta, time_delta_average1 + + +def main(): + global HOST_MANAGER, PORT_MANAGER, HOST_AUTHZ, PORT_AUTHZ + + args = parse() + consul_host = args.consul_host + consul_port = args.consul_port + conf_data = utils.config.get_config_data(consul_host, consul_port) + + HOST_MANAGER = conf_data['manager_host'] + PORT_MANAGER = conf_data['manager_port'] + HOST_AUTHZ = args.authz_host + PORT_AUTHZ = args.authz_port + # HOST_KEYSTONE = conf_data['keystone_host'] + # PORT_KEYSTONE = conf_data['manager_host'] + + scenario = get_scenario(args) + keystone_project_id = get_keystone_id(args.pdp) + time_data = send_requests( + scenario, + keystone_project_id, + request_second=args.request_second, + limit=args.limit, + dry_run=args.dry_run, + stress_test=args.stress_test, + destination=args.destination + ) + if not args.dry_run: + save_data(args.write, time_data) + + +if __name__ == "__main__": + main() diff --git a/moonv4/tests/utils/config.py b/moonv4/tests/utils/config.py index 30c8ea4f..d6317820 100644 --- a/moonv4/tests/utils/config.py +++ b/moonv4/tests/utils/config.py @@ -1,22 +1,44 @@ -import yaml +import base64 +import json +import requests -def get_config_data(filename="moon.conf"): - data_config = None - for _file in ( - filename, - "conf/moon.conf", - "../moon.conf", - "../conf/moon.conf", - "/etc/moon/moon.conf", - ): - try: - data_config = yaml.safe_load(open(_file)) - except FileNotFoundError: - data_config = None - continue - else: - break - if not data_config: - raise Exception("Configuration file not found...") - return data_config +def get_configuration(consul_host, consul_port, key): + url = "http://{}:{}/v1/kv/{}".format(consul_host, consul_port, key) + req = requests.get(url) + if req.status_code != 200: + raise Exception("xxx") + data = req.json() + if len(data) == 1: + data = data[0] + return {data["Key"]: json.loads(base64.b64decode(data["Value"]).decode("utf-8"))} + else: + return [ + {item["Key"]: json.loads(base64.b64decode(item["Value"]).decode("utf-8"))} + for item in data + ] + + +def get_config_data(consul_host, consul_port): + conf_data = dict() + conf_data['manager_host'] = get_configuration(consul_host, consul_port, + 'components/manager')['components/manager']['external']['hostname'] + conf_data['manager_port'] = get_configuration(consul_host, consul_port, + 'components/manager')['components/manager']['external']['port'] + # conf_data['authz_host'] = get_configuration(consul_host, consul_port, + # 'components/interface')['components/interface']['external']['hostname'] + # conf_data['authz_port'] = get_configuration(consul_host, consul_port, + # 'components/interface')['components/interface']['external']['port'] + conf_data['keystone_host'] = get_configuration(consul_host, consul_port, + 'openstack/keystone')['openstack/keystone']['external']['url'] + # conf_data['keystone_port'] = '5000' + conf_data['keystone_user'] = get_configuration(consul_host, consul_port, + 'openstack/keystone')['openstack/keystone']['user'] + conf_data['keystone_password'] = get_configuration(consul_host, consul_port, + 'openstack/keystone')['openstack/keystone']['password'] + conf_data['keystone_project'] = get_configuration(consul_host, consul_port, + 'openstack/keystone')['openstack/keystone']['project'] + return conf_data + +# get_conf_data('88.88.88.2', '30005') +# get_conf_data('127.0.0.1', 8082) diff --git a/moonv4/tests/utils/models.py b/moonv4/tests/utils/models.py index 3cf31354..61fa6179 100644 --- a/moonv4/tests/utils/models.py +++ b/moonv4/tests/utils/models.py @@ -2,13 +2,8 @@ import requests import copy import utils.config -config = utils.config.get_config_data() - -URL = "http://{}:{}".format( - config['components']['manager']['hostname'], - config['components']['manager']['port']) -URL = URL + "{}" -HEADERS = {"content-type": "application/json"} +URL = None +HEADERS = None model_template = { "name": "test_model", @@ -29,6 +24,16 @@ meta_rule_template = { } +def init(consul_host, consul_port): + conf_data = utils.config.get_config_data(consul_host, consul_port) + global URL, HEADERS + URL = "http://{}:{}".format( + conf_data['manager_host'], + conf_data['manager_port']) + URL = URL + "{}" + HEADERS = {"content-type": "application/json"} + + def check_model(model_id=None, check_model_name=True): req = requests.get(URL.format("/models")) assert req.status_code == 200 diff --git a/moonv4/tests/utils/parse.py b/moonv4/tests/utils/parse.py new file mode 100644 index 00000000..34a4a996 --- /dev/null +++ b/moonv4/tests/utils/parse.py @@ -0,0 +1,83 @@ +import logging +import argparse + + +logger = None + + +def parse(): + global logger + logger = logging.getLogger(__name__) + requests_log = logging.getLogger("requests.packages.urllib3") + requests_log.setLevel(logging.WARNING) + requests_log.propagate = True + + parser = argparse.ArgumentParser() + parser.add_argument('filename', help='scenario filename', nargs=1) + parser.add_argument("--verbose", "-v", action='store_true', + help="verbose mode") + parser.add_argument("--debug", "-d", action='store_true', + help="debug mode") + parser.add_argument("--dry-run", "-n", action='store_true', + help="Dry run", dest="dry_run") + parser.add_argument("--destination", + help="Set the type of output needed " + "(default: wrapper, other possible type: " + "interface).", + default="wrapper") + parser.add_argument("--consul-host", + help="Set the name of the consul server" + "(default: 127.0.0.1).", + default="127.0.0.1") + parser.add_argument("--consul-port", + help="Set the port of the consult server" + "(default: 8082).", + default="8082") + parser.add_argument("--authz-host", + help="Set the name of the authz server to test" + "(default: 127.0.0.1).", + default="127.0.0.1") + parser.add_argument("--authz-port", + help="Set the port of the authz server to test" + "(default: 31002).", + default="31002") + parser.add_argument("--keystone-pid", "--keystone-project-id", + help="Set the Keystone project ID" + "(default: None).", + default=None) + parser.add_argument("--stress-test", "-s", action='store_true', + dest='stress_test', + help="Execute stressing tests (warning delta measures " + "will be false, implies -t)") + parser.add_argument("--write", "-w", help="Write test data to a JSON file", + default="/tmp/data.json") + parser.add_argument("--pdp", help="Test on pdp PDP") + parser.add_argument("--request-per-second", + help="Number of requests per seconds", + type=int, dest="request_second", default=-1) + parser.add_argument("--limit", help="Limit request to LIMIT", type=int, + default=500) + + args = parser.parse_args() + + FORMAT = '%(asctime)-15s %(levelname)s %(message)s' + if args.debug: + logging.basicConfig( + format=FORMAT, + level=logging.DEBUG) + elif args.verbose: + logging.basicConfig( + format=FORMAT, + level=logging.INFO) + else: + logging.basicConfig( + format=FORMAT, + level=logging.WARNING) + + if args.stress_test: + args.testonly = True + + if args.filename: + logger.info("Loading: {}".format(args.filename[0])) + + return args diff --git a/moonv4/tests/utils/pdp.py b/moonv4/tests/utils/pdp.py index 4f513aa6..50998507 100644 --- a/moonv4/tests/utils/pdp.py +++ b/moonv4/tests/utils/pdp.py @@ -1,27 +1,42 @@ +import logging import requests import utils.config -config = utils.config.get_config_data() +logger = logging.getLogger("moonforming.utils.policies") +URL = None +HEADER = None +KEYSTONE_USER = None +KEYSTONE_PASSWORD = None +KEYSTONE_PROJECT = None +KEYSTONE_SERVER = None + +# config = utils.config.get_config_data() -URL = "http://{}:{}".format( - config['components']['manager']['hostname'], - config['components']['manager']['port']) -HEADERS = {"content-type": "application/json"} -KEYSTONE_USER = config['openstack']['keystone']['user'] -KEYSTONE_PASSWORD = config['openstack']['keystone']['password'] -KEYSTONE_PROJECT = config['openstack']['keystone']['project'] -KEYSTONE_SERVER = config['openstack']['keystone']['url'] pdp_template = { "name": "test_pdp", "security_pipeline": [], - "keystone_project_id": "", + "keystone_project_id": None, "description": "test", } -def get_keystone_projects(): +def init(consul_host, consul_port): + conf_data = utils.config.get_config_data(consul_host, consul_port) + global URL, HEADER, KEYSTONE_USER, KEYSTONE_PASSWORD, KEYSTONE_PROJECT, KEYSTONE_SERVER + URL = "http://{}:{}".format( + conf_data['manager_host'], + conf_data['manager_port']) + # URL = URL + "{}" + HEADER = {"content-type": "application/json"} + KEYSTONE_USER = conf_data['keystone_user'] + KEYSTONE_PASSWORD = conf_data['keystone_password'] + KEYSTONE_PROJECT = conf_data['keystone_project'] + KEYSTONE_SERVER = conf_data['keystone_host'] + +def get_keystone_projects(): + global HEADERS HEADERS = { "Content-Type": "application/json" } @@ -46,6 +61,8 @@ def get_keystone_projects(): } req = requests.post("{}/auth/tokens".format(KEYSTONE_SERVER), json=data_auth, headers=HEADERS) + logger.debug("{}/auth/tokens".format(KEYSTONE_SERVER)) + logger.debug(req.text) assert req.status_code in (200, 201) TOKEN = req.headers['X-Subject-Token'] HEADERS['X-Auth-Token'] = TOKEN @@ -95,6 +112,8 @@ def add_pdp(name="test_pdp", policy_id=None): if policy_id: pdp_template['security_pipeline'].append(policy_id) req = requests.post(URL + "/pdp", json=pdp_template, headers=HEADERS) + logger.debug(req.status_code) + logger.debug(req) assert req.status_code == 200 result = req.json() assert type(result) is dict @@ -154,4 +173,3 @@ def delete_pdp(pdp_id): assert type(result) is dict assert "result" in result assert result["result"] - diff --git a/moonv4/tests/utils/policies.py b/moonv4/tests/utils/policies.py index 2180317e..fd4d238f 100644 --- a/moonv4/tests/utils/policies.py +++ b/moonv4/tests/utils/policies.py @@ -1,12 +1,11 @@ +import logging import requests import utils.config -config = utils.config.get_config_data() - -URL = "http://{}:{}".format(config['components']['manager']['hostname'], config['components']['manager']['port']) -URL = URL + "{}" -HEADERS = {"content-type": "application/json"} +URL = None +HEADERS = None FILE = open("/tmp/test.log", "w") +logger = logging.getLogger("utils.policies") policy_template = { "name": "test_policy", @@ -54,8 +53,17 @@ subject_assignment_template = { } +def init(consul_host, consul_port): + conf_data = utils.config.get_config_data(consul_host, consul_port) + global URL, HEADERS + URL = "http://{}:{}".format( + conf_data['manager_host'], + conf_data['manager_port']) + URL = URL + "{}" + HEADERS = {"content-type": "application/json"} + + def check_policy(policy_id=None): - print("URL={}".format(URL.format("/policies"))) req = requests.get(URL.format("/policies")) assert req.status_code == 200 result = req.json() @@ -109,10 +117,13 @@ def delete_policy(policy_id): def add_subject(policy_id=None, name="test_subject"): subject_template['name'] = name if policy_id: + logger.debug(URL.format("/policies/{}/subjects".format(policy_id))) req = requests.post(URL.format("/policies/{}/subjects".format(policy_id)), json=subject_template, headers=HEADERS) else: + logger.debug(URL.format("/subjects")) req = requests.post(URL.format("/subjects"), json=subject_template, headers=HEADERS) + logger.debug(req.text) assert req.status_code == 200 result = req.json() assert "subjects" in result |