Skip to content
Snippets Groups Projects
Commit 6dfd4f47 authored by Tim Fechner's avatar Tim Fechner
Browse files

Refactor api module, introduce tornato bindings

parent 73d0a586
No related branches found
No related tags found
No related merge requests found
Pipeline #
...@@ -12,3 +12,17 @@ Issues and further documentation can be found there. ...@@ -12,3 +12,17 @@ Issues and further documentation can be found there.
## Development ## Development
A complete list of the `Minion.data` json structure can be found [here](https://lab.it.hs-hannover.de/django/salt-observer/wikis/minion-data-structure) in the wiki. A complete list of the `Minion.data` json structure can be found [here](https://lab.it.hs-hannover.de/django/salt-observer/wikis/minion-data-structure) in the wiki.
```python
# get output of 'w' command of all 'tgt' minions
request('token', {'tgt': '*', 'fun': 'cmd.run', 'arg': 'w'})
# get all grains of 'tgt' minions
request('token', {'tgt': '*', 'fun': 'grains.items'})
# execute some state and apply custom pillars to it
request('token', {'tgt': '*', 'fun': 'state.sls', 'kwarg': {
'mods': 'name_of_state', 'pillar': {'some': 'pillar_data'}
}})
```
from django.contrib.auth.backends import ModelBackend from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User from django.contrib.auth.models import User
from salt_observer.cherry import SaltCherrypyApi from salt_observer.saltapis import SaltCherrypy, SaltTornado
class RestBackend(ModelBackend): class RestBackend(ModelBackend):
''' Authenticate against salt-api-permissions ''' ''' Authenticate against salt-api-permissions '''
def authenticate(self, username=None, password=None): def authenticate(self, username=None, password=None, request=None):
try: try:
valid = SaltCherrypyApi.obtain_auth_token(username, password) cherrypy_token = SaltCherrypy(username, password).token
except: tornado_token = SaltTornado(username, password).token
valid = False except Exception as e:
cherrypy_token = False
tornado_token = False
if valid: if cherrypy_token and tornado_token:
try: try:
user = User.objects.get(username=username) user = User.objects.get(username=username)
except User.DoesNotExist: except User.DoesNotExist:
user = User.objects.create_user(username=username, email='', password=password) user = User.objects.create_user(username=username, email='', password=password)
request.session['salt_cherrypy_token'] = cherrypy_token
request.session['salt_tornado_token'] = tornado_token
return user return user
return None return None
from django import forms from django import forms
from django.contrib.auth import authenticate
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import ugettext, ugettext_lazy as _ from django.utils.translation import ugettext, ugettext_lazy as _
...@@ -74,6 +75,31 @@ class LoginForm(AuthenticationForm): ...@@ -74,6 +75,31 @@ class LoginForm(AuthenticationForm):
username = forms.CharField(label='', max_length=255) username = forms.CharField(label='', max_length=255)
password = forms.CharField(label='', widget=forms.PasswordInput) password = forms.CharField(label='', widget=forms.PasswordInput)
def clean(self):
'''
Overwriting this method to pass the current request down to the
backends via authenticate([...])
'''
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username and password:
self.user_cache = authenticate(
username=username,
password=password,
request=self.request
)
if self.user_cache is None:
raise forms.ValidationError(
self.error_messages['invalid_login'],
code='invalid_login',
params={'username': self.username_field.verbose_name},
)
else:
self.confirm_login_allowed(self.user_cache)
return self.cleaned_data
class MinionEditForm(MarkdownFormMixin): class MinionEditForm(MarkdownFormMixin):
class Meta: class Meta:
......
from salt_observer.cherry import SaltCherrypyApi from salt_observer.saltapis import SaltCherrypy
from getpass import getpass from getpass import getpass
...@@ -20,4 +20,4 @@ class ApiCommand(object): ...@@ -20,4 +20,4 @@ class ApiCommand(object):
else: else:
password = kwargs.get('password') password = kwargs.get('password')
return SaltCherrypyApi(username, password) return SaltCherrypy(username, password)
...@@ -26,9 +26,16 @@ DATABASES = { ...@@ -26,9 +26,16 @@ DATABASES = {
# Salt observer configuration # Salt observer configuration
SALT_API = { SALT_API = {
'cherrypy': {
'host': 'localhost', 'host': 'localhost',
'port': 8989, 'port': 8989,
'protocol': 'http', 'protocol': 'http',
},
'tornado': {
'host': 'localhost',
'port': 8002,
'protocol': 'http'
}
} }
# specify your salt network here to disable it in network visualization # specify your salt network here to disable it in network visualization
......
...@@ -4,17 +4,33 @@ import requests ...@@ -4,17 +4,33 @@ import requests
from getpass import getpass from getpass import getpass
class SaltCherrypyApi(object): class AbstractApi(object):
'''
Defines an abstract api to inherit from.
You MUST specify a BASE_URL for your api to build a proper request url.
'''
BASE_URL = '{protocol}://{host}:{port}'.format(**settings.SALT_API) BASE_URL = ''
def __init__(self, username, password): def __init__(self, username='', password='', token=''):
''' Log in every time an instance is created ''' ''' Set a token to work with '''
if not self.BASE_URL:
raise NotImplementedError('Please provide an BASE_URL')
if token:
self.token = token
else:
self.token = self.obtain_auth_token(username, password) self.token = self.obtain_auth_token(username, password)
@classmethod def request(self, method='get', resource='/', headers={}, data={}):
def obtain_auth_token(cls, username, password): return getattr(requests, method)(
res = requests.post(cls.BASE_URL+'/login', headers={'Accept': 'application/json'}, data={ self.BASE_URL + resource,
headers=headers,
data=data
)
def obtain_auth_token(self, username, password):
res = self.request('post', '/login', headers={'Accept': 'application/json'}, data={
'username': username, 'username': username,
'password': password, 'password': password,
'eauth': 'pam' 'eauth': 'pam'
...@@ -25,45 +41,34 @@ class SaltCherrypyApi(object): ...@@ -25,45 +41,34 @@ class SaltCherrypyApi(object):
return res.json().get('return')[0].get('token') return res.json().get('return')[0].get('token')
def request(self, data, api_point=''):
data.update({'client': 'local'}) class SaltCherrypy(AbstractApi):
return requests.post(
'{}/{}'.format(self.BASE_URL, api_point), BASE_URL = '{protocol}://{host}:{port}'.format(**settings.SALT_API['cherrypy'])
headers={
'Accept': 'application/json',
'X-Auth-Token': self.token
},
data=data
)
def logout(self): def logout(self):
return requests.post( return self.request('post', '/logout', headers={
self.BASE_URL+'/logout',
headers={
'Accept': 'application/json', 'Accept': 'application/json',
'X-Auth-Token': self.token 'X-Auth-Token': self.token
} })
)
def get(self, module, target='*', api_args=[], api_kwargs={}): def get(self, module, target='*', api_args=[], api_kwargs={}):
return self.request({ return self.request(
'post',
data={
'client': 'local',
'fun': module, 'fun': module,
'tgt': target, 'tgt': target,
'arg': api_args, 'arg': api_args,
'kwarg': api_kwargs 'kwarg': api_kwargs
}).json().get('return')[0] },
headers={
'Accept': 'application/json',
# experimental: 'X-Auth-Token': self.token
# --- }
# ).json().get('return')[0]
# get output of 'w' command of all 'tgt' minions
# request('token', {'tgt': '*', 'fun': 'cmd.run', 'arg': 'w'})
# class SaltTornado(AbstractApi):
# get all grains of 'tgt' minions
# request('token', {'tgt': '*', 'fun': 'grains.items'}) BASE_URL = '{protocol}://{host}:{port}'.format(**settings.SALT_API['tornado'])
#
# execute some state and apply custom pillars to it
# request('token', {'tgt': '*', 'fun': 'state.sls', 'kwarg': {
# 'mods': 'name_of_state', 'pillar': {'some': 'pillar_data'}
# }})
...@@ -49,6 +49,12 @@ class Login(FormView): ...@@ -49,6 +49,12 @@ class Login(FormView):
login(self.request, form.get_user()) login(self.request, form.get_user())
return super().form_valid(form, *args, **kwargs) return super().form_valid(form, *args, **kwargs)
def get_form_kwargs(self, *args, **kwargs):
'''dirty hack to pass the current request down to the backends'''
kwargs = super().get_form_kwargs(*args, **kwargs)
kwargs['request'] = self.request
return kwargs
def get_success_url(self): def get_success_url(self):
return self.request.GET.get('next', reverse_lazy('dashboard')) return self.request.GET.get('next', reverse_lazy('dashboard'))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment