Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add namespaces for database objects #115

Merged
merged 18 commits into from
Nov 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ python:
- '3.6'
service:
- docker


notifications:
slack:
secure: imXU/zt9IjKk5OvjZkTICTmxOTKGaZIej2kf7m5iSAKrdM7Lsjhj1m464qOViH3AMjMMZeprC1SL/jFF5azu2DNkQe5j1UlUu1ZxQpwnpmXJaLyTznDZSa76LPoY/R4sqJYozZLzfMQivnIUe6NGTP5vDX8CXpndaOgfAulDzks6xXDTw8q1dyKTtqFx8aPbAFAYRPagaNpy62j09aeNXDY8OVUSJsx8xylRmbHY+t1AH5AMkDPY5AeI0D/CJH1Hnbq88MmvdgUn8OqjvWMgiXsrDFAPZ4WdZCgJZuP2D4jrDuAsnchrOrVi6wKJWA9rNqJD8TqqF8Q8JhdeVAJ098GXAyhkJlDtfeEbh8TYIkLNgpW7e/auh5rzHk5MvH7kTVzyZjGMb7Vo+7c7nypFoWeom1m8Pg5rCT7vx7+0NhQjg1moMQ2kPWzaZkITDdblxuf6rpraEx2ydqPh6pAAto+VWXRrdbJJTGSTVIfPFDHYeqkCq+QVGfdCi2BucnnQVZJLUqEdGxnn86ICwhjJ5uC4Ah7Czd/pZOrdgFMWTT6DS9fjRiIHOnAAp1wKYzAoRBKQkhltDFMrayDxN5dp+IXDnnlQWPm14mwAyNd/zt8pWCue5hT2oK7oeuQsNfSemSPg92DCZRZNZ684UbJGKn0RJlSpXLyQRjja0IjA+Kk=
on_success: change
on_failure: change
on_pull_requests: false
stages:
- name: test
- name: publish
if: tag =~ ^v.*
- name: verify
if: branch = master AND type = push

jobs:
include:
- stage: test
Expand All @@ -25,15 +28,13 @@ jobs:
- python3 -m flake8
- python3 -m pytest --cov=. --cov-report=term-missing:skip-covered
- coveralls

- pip3 install --editable .
- python3 -m kqueen &
- sleep 2
- wget -O - http://localhost:5000/api/v1/health

- stage: publish
script:
- /bin/true
- "/bin/true"
deploy:
provider: pypi
user: tomkukral
Expand All @@ -42,13 +43,12 @@ jobs:
on:
tags: true
repo: Mirantis/kqueen

- stage: verify
before_install:
- docker-compose -f docker-compose.yml -f docker-compose.kubernetes.yml up -d
install:
- pip3 install --upgrade kqueen
script:
- ./entrypoint.sh &
- "./entrypoint.sh &"
- sleep 2
- wget -O - http://localhost:5000/api/v1/health
6 changes: 6 additions & 0 deletions devenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

try:
user = User(
None,
username='admin',
password='default',
organization=organization,
Expand All @@ -46,6 +47,7 @@
# AWS + Jenkins
try:
provisioner = Provisioner(
user.namespace,
id=uuid_provisioner_jenkins,
name='Jenkins provisioner to AWS',
state='OK',
Expand All @@ -62,6 +64,7 @@

try:
cluster = Cluster(
user.namespace,
id=uuid_jenkins,
name='AWS Calico SM 33',
state='OK',
Expand All @@ -76,6 +79,7 @@
# Local cluster
try:
provisioner = Provisioner(
user.namespace,
id=uuid_provisioner_local,
name='Manual provisioner',
state='OK',
Expand All @@ -89,6 +93,7 @@

try:
cluster = Cluster(
user.namespace,
id=uuid_local,
name='local_cluster',
state='OK',
Expand All @@ -102,6 +107,7 @@
# Dummy Kubespray provisioner
try:
provisioner = Provisioner(
user.namespace,
id=uuid_provisioner_kubespray,
name='Kubespray',
state='OK',
Expand Down
4 changes: 4 additions & 0 deletions docs/kqueen.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ Example configuration files are located in `config/` directory. Default configur
* - ETCD_PORT
- 4001
- Port for etcd server
* - ETCD_PREFIX
- /kqueen
- Prefix URL for objects in etcd


* - JWT_DEFAULT_REALM
- Login Required
Expand Down
6 changes: 3 additions & 3 deletions kqueen/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ def authenticate(username, password):
user: authenticated user

"""
users = list(User.list(return_objects=True).values())
users = list(User.list(None, return_objects=True).values())
username_table = {u.username: u for u in users}
user = username_table.get(username, None)
user = username_table.get(username)
if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')):
return user

Expand All @@ -36,7 +36,7 @@ def identity(payload):
"""
user_id = payload['identity']
try:
user = User.load(user_id)
user = User.load(None, user_id)
except:
user = None
return user
29 changes: 21 additions & 8 deletions kqueen/blueprints/api/generic_views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from flask import jsonify
from flask.views import View
from flask import abort
from flask_jwt import _jwt_required
from flask_jwt import _jwt_required, current_identity
from flask import current_app
from flask import request
from .helpers import get_object
Expand All @@ -22,7 +22,6 @@ def check_access(self):

def dispatch_request(self, *args, **kwargs):
self.check_access()

output = self.get_content(*args, **kwargs)

return jsonify(output)
Expand All @@ -32,7 +31,7 @@ class GetView(GenericView):
methods = ['GET']

def get_content(self, *args, **kwargs):
return get_object(self.get_class(), kwargs['pk'])
return get_object(self.get_class(), kwargs['pk'], current_identity)


class DeleteView(GenericView):
Expand All @@ -41,7 +40,7 @@ class DeleteView(GenericView):
def dispatch_request(self, *args, **kwargs):
self.check_access()

obj = get_object(self.get_class(), kwargs['pk'])
obj = get_object(self.get_class(), kwargs['pk'], current_identity)

try:
obj.delete()
Expand All @@ -55,17 +54,19 @@ class UpdateView(GenericView):
methods = ['PATCH']

def get_content(self, *args, **kwargs):
return get_object(self.get_class(), kwargs['pk'])
return get_object(self.get_class(), kwargs['pk'], current_identity)

def dispatch_request(self, *args, **kwargs):
self.check_access()

if not request.json:
abort(400)

data = request.json
if not isinstance(data, dict):
abort(400)

obj = get_object(self.get_class(), kwargs['pk'])
obj = get_object(self.get_class(), kwargs['pk'], current_identity)
for key, value in data.items():
setattr(obj, key, value)

Expand All @@ -81,7 +82,12 @@ class ListView(GenericView):
methods = ['GET']

def get_content(self, *args, **kwargs):
return list(self.get_class().list(return_objects=True).values())
try:
namespace = current_identity.namespace
except AttributeError:
namespace = None

return list(self.get_class().list(namespace, return_objects=True).values())


class CreateView(GenericView):
Expand All @@ -97,12 +103,19 @@ def get_content(self, *args, **kwargs):
return self.obj.get_dict(expand=True)

def dispatch_request(self, *args, **kwargs):
self.check_access()

if not request.json:
abort(400)
else:
cls = self.get_class()
self.obj = cls(**request.json)

try:
namespace = current_identity.namespace
except AttributeError:
namespace = None

self.obj = cls(namespace, **request.json)
try:
self.save_object()
self.after_save()
Expand Down
11 changes: 8 additions & 3 deletions kqueen/blueprints/api/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from uuid import UUID


def get_object(object_class, pk):

def get_object(object_class, pk, user=None):
# read uuid
if isinstance(pk, UUID):
object_id = pk
Expand All @@ -13,9 +12,15 @@ def get_object(object_class, pk):
except ValueError:
abort(400)

# read namespace for user
try:
namespace = user.namespace
except AttributeError:
namespace = None

# load object
try:
obj = object_class.load(object_id)
obj = object_class.load(namespace, object_id)
except NameError:
abort(404)

Expand Down
12 changes: 4 additions & 8 deletions kqueen/blueprints/api/test_cluster.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from flask import url_for
from uuid import uuid4
from kqueen.conftest import cluster
from kqueen.conftest import provisioner
from .test_crud import BaseTestCRUD

import pytest
Expand All @@ -10,13 +9,9 @@

class TestClusterCRUD(BaseTestCRUD):
def get_object(self):
clu = cluster()
prov = provisioner()
prov.save()
obj = cluster()

clu.provisioner = prov

return clu
return obj

def get_edit_data(self):
return {'name': 'patched cluster'}
Expand All @@ -34,6 +29,7 @@ def test_get_dict_expanded(self):
assert dicted['provisioner']['id'] == self.obj.provisioner.id

def test_cluster_get(self):

cluster_id = self.obj.id

response = self.client.get(
Expand Down Expand Up @@ -150,7 +146,7 @@ def fake_provision(self, *args, **kwargs):
)

object_id = response.json['id']
obj = self.obj.__class__.load(object_id)
obj = self.obj.__class__.load(self.namespace, object_id)

assert response.status_code == 200
assert obj.name == 'Provisioned'
Expand Down
Loading