diff options
author | Jacob Hodgdon <jhodgdon@iol.unh.edu> | 2021-08-24 15:48:36 -0400 |
---|---|---|
committer | Raven Hodgdon <jhodgdon@iol.unh.edu> | 2021-09-14 16:57:19 -0400 |
commit | eb75b380a32c65dc8d0857bae093c7a96f30f024 (patch) | |
tree | c23c61a3e16a5d946fd0743748065767b5256fa7 | |
parent | 4e8c162a104a46f7625b0ad624285ed39568d3a1 (diff) |
removal of jira
Change-Id: I1b1da49147219d94837cdd50b908ba30f8cf961c
Signed-off-by: Jacob Hodgdon <jhodgdon@iol.unh.edu>
Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu>
Signed-off-by: Raven Hodgdon <jhodgdon@iol.unh.edu>
29 files changed, 184 insertions, 440 deletions
diff --git a/config.env.sample b/config.env.sample index 5b34217..c47f2bf 100644 --- a/config.env.sample +++ b/config.env.sample @@ -34,13 +34,6 @@ SECRET_KEY=http://www.miniwebtool.com/django-secret-key-generator/ OAUTH_CONSUMER_KEY=sample_key OAUTH_CONSUMER_SECRET=sample_secret -# access information for Jira -# In addition to this, the rsa keys from your jira admin -# need to go into src/account -JIRA_URL=sample_url -JIRA_USER_NAME=sample_jira_user -JIRA_USER_PASSWORD=sample_jira_pass - # LFID OIDC_CLIENT_ID=sample_id OIDC_CLIENT_SECRET=sample_secret @@ -55,8 +48,8 @@ OIDC_RP_SIGN_ALGO=RS256 OIDC_OP_JWKS_ENDPOINT=https://sso.linuxfoundation.org/.well-known/jwks.json # Rabbitmq -RABBITMQ_DEFAULT_USER=opnfv -RABBITMQ_DEFAULT_PASS=opnfvopnfv +DEFAULT_USER=opnfv +DEFAULT_PASS=opnfvopnfv # Jenkins Build Server JENKINS_URL=https://build.opnfv.org/ci diff --git a/config/rabbitmq/rabbitmq.conf b/config/rabbitmq/rabbitmq.conf new file mode 100644 index 0000000..39c222c --- /dev/null +++ b/config/rabbitmq/rabbitmq.conf @@ -0,0 +1,2 @@ +default_user=opnfv +default_pass=opnfvopnfv diff --git a/docker-compose.yml b/docker-compose.yml index ee8de2c..f0de7b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,7 +50,9 @@ services: restart: always image: rabbitmq container_name: rm01 - env_file: config.env + #env_file: config.env + volumes: + - ./config/rabbitmq:/etc/rabbitmq ports: - "5672:5672" diff --git a/requirements.txt b/requirements.txt index b34dd1e..72afbfa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,18 +1,17 @@ -celery==3.1.23 -cryptography==2.6.1 +celery==5.1.2 +cryptography==3.4.7 Django==2.2 django-bootstrap4==0.0.8 django-filter==2.0.0 djangorestframework==3.8.2 -gunicorn==19.6.0 -jira==1.0.7 +gunicorn==20.1.0 oauth2==1.9.0.post1 -oauthlib==1.1.2 -pika==0.10.0 -psycopg2==2.8.4 -PyJWT==1.4.2 -requests==2.22.0 +oauthlib==3.1.1 +pika==1.2.0 +psycopg2==2.8.6 +PyJWT==2.1.0 +requests==2.26.0 django-fernet-fields==0.6 -pyyaml==3.13 -pytz==2018.5 -mozilla-django-oidc==1.2.3 +pyyaml==5.4.1 +pytz==2021.1 +mozilla-django-oidc==2.0.0
\ No newline at end of file diff --git a/src/account/jira_util.py b/src/account/jira_util.py deleted file mode 100644 index a522594..0000000 --- a/src/account/jira_util.py +++ /dev/null @@ -1,65 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -import base64 -import os - -import oauth2 as oauth -from django.conf import settings -from jira import JIRA -from tlslite.utils import keyfactory - - -class SignatureMethod_RSA_SHA1(oauth.SignatureMethod): - name = 'RSA-SHA1' - - def signing_base(self, request, consumer, token): - if not hasattr(request, 'normalized_url') or request.normalized_url is None: - raise ValueError("Base URL for request is not set.") - - sig = ( - oauth.escape(request.method), - oauth.escape(request.normalized_url), - oauth.escape(request.get_normalized_parameters()), - ) - - key = '%s&' % oauth.escape(consumer.secret) - if token: - key += oauth.escape(token.secret) - raw = '&'.join(sig) - return key, raw - - def sign(self, request, consumer, token): - """Build the base signature string.""" - key, raw = self.signing_base(request, consumer, token) - - module_dir = os.path.dirname(__file__) # get current directory - with open(module_dir + '/rsa.pem', 'r') as f: - data = f.read() - privateKeyString = data.strip() - privatekey = keyfactory.parsePrivateKey(privateKeyString) - raw = str.encode(raw) - signature = privatekey.hashAndSign(raw) - return base64.b64encode(signature) - - -def get_jira(user): - module_dir = os.path.dirname(__file__) # get current directory - with open(module_dir + '/rsa.pem', 'r') as f: - key_cert = f.read() - - oauth_dict = { - 'access_token': user.userprofile.oauth_token, - 'access_token_secret': user.userprofile.oauth_secret, - 'consumer_key': settings.OAUTH_CONSUMER_KEY, - 'key_cert': key_cert - } - - return JIRA(server=settings.JIRA_URL, oauth=oauth_dict) diff --git a/src/account/models.py b/src/account/models.py index b71f0ac..210025e 100644 --- a/src/account/models.py +++ b/src/account/models.py @@ -51,6 +51,7 @@ class UserProfile(models.Model): oauth_secret = models.CharField(max_length=1024, blank=False) jira_url = models.CharField(max_length=100, null=True, blank=True, default='') + full_name = models.CharField(max_length=100, null=True, blank=True, default='') booking_privledge = models.BooleanField(default=False) diff --git a/src/account/tasks.py b/src/account/tasks.py deleted file mode 100644 index df98c73..0000000 --- a/src/account/tasks.py +++ /dev/null @@ -1,37 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from celery import shared_task -from django.contrib.auth.models import User -from jira import JIRAError - -from account.jira_util import get_jira - - -@shared_task -def sync_jira_accounts(): - users = User.objects.all() - for user in users: - jira = get_jira(user) - try: - user_dict = jira.myself() - except JIRAError: - # User can be anonymous (local django admin account) - continue - try: - user.email = user_dict['emailAddress'] - except KeyError: - pass - user.userprofile.url = user_dict['self'] - user.userprofile.full_name = user_dict['displayName'] - - user.userprofile.save() - user.save() diff --git a/src/account/urls.py b/src/account/urls.py index 97d8c77..804c133 100644 --- a/src/account/urls.py +++ b/src/account/urls.py @@ -30,46 +30,30 @@ from django.urls import path from account.views import ( AccountSettingsView, - JiraAuthenticatedView, - JiraLoginView, OIDCLoginView, - JiraLogoutView, + LogoutView, UserListView, account_resource_view, account_booking_view, account_images_view, - account_configuration_view, account_detail_view, - resource_delete_view, + template_delete_view, booking_cancel_view, image_delete_view, - configuration_delete_view ) -from laas_dashboard import settings +app_name = 'account' - -def get_login_view(): - if (settings.AUTH_SETTING == 'LFID'): - return OIDCLoginView.as_view() - else: - return JiraLoginView.as_view() - - -app_name = "account" urlpatterns = [ url(r'^settings/', AccountSettingsView.as_view(), name='settings'), - url(r'^authenticated/$', JiraAuthenticatedView.as_view(), name='authenticated'), - url(r'^login/$', get_login_view(), name='login'), - url(r'^logout/$', JiraLogoutView.as_view(), name='logout'), + url(r'^login/$', OIDCLoginView.as_view(), name='login'), + url(r'^logout/$', LogoutView.as_view(), name='logout'), url(r'^users/$', UserListView.as_view(), name='users'), - url(r'^my/resources/$', account_resource_view, name="my-resources"), - path('my/resources/delete/<int:resource_id>', resource_delete_view), - url(r'^my/bookings/$', account_booking_view, name="my-bookings"), + url(r'^my/resources/$', account_resource_view, name='my-resources'), + path('my/resources/delete/<int:resource_id>', template_delete_view), + url(r'^my/bookings/$', account_booking_view, name='my-bookings'), path('my/bookings/cancel/<int:booking_id>', booking_cancel_view), - url(r'^my/images/$', account_images_view, name="my-images"), + url(r'^my/images/$', account_images_view, name='my-images'), path('my/images/delete/<int:image_id>', image_delete_view), - url(r'^my/configurations/$', account_configuration_view, name="my-configurations"), - path('my/configurations/delete/<int:config_id>', configuration_delete_view), - url(r'^my/$', account_detail_view, name="my-account"), -] + url(r'^my/$', account_detail_view, name='my-account'), +]
\ No newline at end of file diff --git a/src/account/views.py b/src/account/views.py index b74126e..167b5c4 100644 --- a/src/account/views.py +++ b/src/account/views.py @@ -26,13 +26,11 @@ from django.shortcuts import get_object_or_404 from django.utils.decorators import method_decorator from django.views.generic import RedirectView, TemplateView, UpdateView from django.shortcuts import render -from jira import JIRA from rest_framework.authtoken.models import Token from mozilla_django_oidc.auth import OIDCAuthenticationBackend from account.forms import AccountSettingsForm -from account.jira_util import SignatureMethod_RSA_SHA1 from account.models import UserProfile from booking.models import Booking from resource_inventory.models import ResourceTemplate, Image @@ -69,7 +67,7 @@ class MyOIDCAB(OIDCAuthenticationBackend): If this changes we will need to match users based on some other criterea. """ - username = claims.get(os.environ['CLAIMS_ENDPOINT'] + 'username') + username = claims.get(os.environ.get('CLAIMS_ENDPOINT') + 'username') if not username: return HttpResponse('No username provided, contact support.') @@ -101,109 +99,17 @@ class MyOIDCAB(OIDCAuthenticationBackend): return user -class JiraLoginView(RedirectView): - def get_redirect_url(self, *args, **kwargs): - consumer = oauth.Consumer(settings.OAUTH_CONSUMER_KEY, settings.OAUTH_CONSUMER_SECRET) - client = oauth.Client(consumer) - client.set_signature_method(SignatureMethod_RSA_SHA1()) - - # Step 1. Get a request token from Jira. - try: - resp, content = client.request(settings.OAUTH_REQUEST_TOKEN_URL, "POST") - except Exception: - messages.add_message(self.request, messages.ERROR, - 'Error: Connection to Jira failed. Please contact an Administrator') - return '/' - if resp['status'] != '200': - messages.add_message(self.request, messages.ERROR, - 'Error: Connection to Jira failed. Please contact an Administrator') - return '/' - - # Step 2. Store the request token in a session for later use. - self.request.session['request_token'] = dict(urllib.parse.parse_qsl(content.decode())) - # Step 3. Redirect the user to the authentication URL. - url = settings.OAUTH_AUTHORIZE_URL + '?oauth_token=' + \ - self.request.session['request_token']['oauth_token'] + \ - '&oauth_callback=' + settings.OAUTH_CALLBACK_URL - return url - - class OIDCLoginView(RedirectView): def get_redirect_url(self, *args, **kwargs): return reverse('oidc_authentication_init') -class JiraLogoutView(LoginRequiredMixin, RedirectView): +class LogoutView(LoginRequiredMixin, RedirectView): def get_redirect_url(self, *args, **kwargs): logout(self.request) return '/' -class JiraAuthenticatedView(RedirectView): - def get_redirect_url(self, *args, **kwargs): - # Step 1. Use the request token in the session to build a new client. - consumer = oauth.Consumer(settings.OAUTH_CONSUMER_KEY, settings.OAUTH_CONSUMER_SECRET) - token = oauth.Token(self.request.session['request_token']['oauth_token'], - self.request.session['request_token']['oauth_token_secret']) - client = oauth.Client(consumer, token) - client.set_signature_method(SignatureMethod_RSA_SHA1()) - - # Step 2. Request the authorized access token from Jira. - try: - resp, content = client.request(settings.OAUTH_ACCESS_TOKEN_URL, "POST") - except Exception: - messages.add_message(self.request, messages.ERROR, - 'Error: Connection to Jira failed. Please contact an Administrator') - return '/' - if resp['status'] != '200': - messages.add_message(self.request, messages.ERROR, - 'Error: Connection to Jira failed. Please contact an Administrator') - return '/' - - access_token = dict(urllib.parse.parse_qsl(content.decode())) - - module_dir = os.path.dirname(__file__) # get current directory - with open(module_dir + '/rsa.pem', 'r') as f: - key_cert = f.read() - - oauth_dict = { - 'access_token': access_token['oauth_token'], - 'access_token_secret': access_token['oauth_token_secret'], - 'consumer_key': settings.OAUTH_CONSUMER_KEY, - 'key_cert': key_cert - } - - jira = JIRA(server=settings.JIRA_URL, oauth=oauth_dict) - username = jira.current_user() - email = "" - try: - email = jira.user(username).emailAddress - except AttributeError: - email = "" - url = '/' - # Step 3. Lookup the user or create them if they don't exist. - try: - user = User.objects.get(username=username) - except User.DoesNotExist: - # Save our permanent token and secret for later. - user = User.objects.create_user(username=username, - password=access_token['oauth_token_secret']) - profile = UserProfile() - profile.user = user - profile.save() - user.userprofile.email_addr = email - url = reverse('account:settings') - user.userprofile.oauth_token = access_token['oauth_token'] - user.userprofile.oauth_secret = access_token['oauth_token_secret'] - user.userprofile.save() - user.set_password(access_token['oauth_token_secret']) - user.save() - user = authenticate(username=username, password=access_token['oauth_token_secret']) - login(self.request, user) - # redirect user to settings page to complete profile - return url - - @method_decorator(login_required, name='dispatch') class UserListView(TemplateView): template_name = "account/user_list.html" @@ -232,9 +138,9 @@ def account_resource_view(request): template = "account/resource_list.html" active_bundles = [book.resource for book in Booking.objects.filter( - owner=request.user, end__gte=timezone.now())] + owner=request.user, end__gte=timezone.now(), resource__template__temporary=False)] active_resources = [bundle.template.id for bundle in active_bundles] - resource_list = list(ResourceTemplate.objects.filter(owner=request.user)) + resource_list = list(ResourceTemplate.objects.filter(owner=request.user, temporary=False)) context = { "resources": resource_list, @@ -262,14 +168,6 @@ def account_booking_view(request): return render(request, template, context=context) -def account_configuration_view(request): - if not request.user.is_authenticated: - return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) - template = "account/configuration_list.html" - configs = list(ResourceTemplate.objects.filter(owner=request.user)) - context = {"title": "Configuration List", "configurations": configs} - return render(request, template, context=context) - def account_images_view(request): if not request.user.is_authenticated: @@ -290,28 +188,19 @@ def account_images_view(request): return render(request, template, context=context) -def resource_delete_view(request, resource_id=None): +def template_delete_view(request, resource_id=None): if not request.user.is_authenticated: - return HttpResponse('no') # 403? - grb = get_object_or_404(ResourceTemplate, pk=resource_id) - if not request.user.id == grb.owner.id: - return HttpResponse('no') # 403? - if Booking.objects.filter(resource__template=grb, end__gt=timezone.now()).exists(): - return HttpResponse('no') # 403? - grb.delete() - return HttpResponse('') - - -def configuration_delete_view(request, config_id=None): - if not request.user.is_authenticated: - return HttpResponse('no') # 403? - config = get_object_or_404(ResourceTemplate, pk=config_id) - if not request.user.id == config.owner.id: - return HttpResponse('no') # 403? - if Booking.objects.filter(resource__template=config, end__gt=timezone.now()).exists(): - return HttpResponse('no') - config.delete() - return HttpResponse('') + return HttpResponse(status=403) + template = get_object_or_404(ResourceTemplate, pk=resource_id) + if not request.user.id == template.owner.id: + return HttpResponse(status=403) + if Booking.objects.filter(resource__template=template, end__gt=timezone.now()).exists(): + return HttpResponse(status=403) + #grb.delete() + template.public = False + template.temporary = True + template.save() + return HttpResponse(status=200) def booking_cancel_view(request, booking_id=None): diff --git a/src/api/views.py b/src/api/views.py index 1793c79..c0da1bc 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -391,7 +391,7 @@ def available_templates(request): # mirrors MultipleSelectFilter Widget avt = [] for lab in Lab.objects.all(): - for template in ResourceTemplate.objects.filter(Q(lab=lab), Q(owner=token.user) | Q(public=True)): + for template in ResourceTemplate.objects.filter(Q(owner=token.user) | Q(public=True), lab=lab, temporary=False): available_resources = lab.get_available_resources() required_resources = template.get_required_resources() least_available = 100 diff --git a/src/booking/quick_deployer.py b/src/booking/quick_deployer.py index 5e5bc8b..9806348 100644 --- a/src/booking/quick_deployer.py +++ b/src/booking/quick_deployer.py @@ -227,7 +227,6 @@ def create_from_API(body, user): data['scenario'] = None data['image'] = Image.objects.get(pk=booking_info['imageLabID']) - data['resource_template'] = ResourceTemplate.objects.get(pk=booking_info['templateID']) data['lab'] = data['resource_template'].lab data['owner'] = user diff --git a/src/booking/stats.py b/src/booking/stats.py index 626ed79..70f91fa 100644 --- a/src/booking/stats.py +++ b/src/booking/stats.py @@ -104,5 +104,5 @@ class StatisticsManager(object): "user": [x, users], "utils": [in_use, not_in_use, maintenance], "projects": [project_keys, project_counts], - "colors": anuket_colors if os.environ['TEMPLATE_OVERRIDE_DIR'] == 'laas' else lfedge_colors + "colors": anuket_colors if os.environ.get('TEMPLATE_OVERRIDE_DIR') == 'laas' else lfedge_colors } diff --git a/src/booking/urls.py b/src/booking/urls.py index cdf18ae..0b60351 100644 --- a/src/booking/urls.py +++ b/src/booking/urls.py @@ -38,7 +38,7 @@ from booking.views import ( booking_modify_image ) -app_name = "booking" +app_name = 'booking' urlpatterns = [ url(r'^detail/(?P<booking_id>[0-9]+)/$', booking_detail_view, name='detail'), url(r'^(?P<booking_id>[0-9]+)/$', booking_detail_view, name='booking_detail'), diff --git a/src/booking/views.py b/src/booking/views.py index 2b910e7..a418c82 100644 --- a/src/booking/views.py +++ b/src/booking/views.py @@ -127,7 +127,6 @@ class ResourceBookingsJSON(View): 'start', 'end', 'purpose', - 'jira_issue_status', 'config_bundle__name' ) return JsonResponse({'bookings': list(bookings)}) diff --git a/src/dashboard/templatetags/jira_filters.py b/src/dashboard/templatetags/jira_filters.py deleted file mode 100644 index 9a97c1d..0000000 --- a/src/dashboard/templatetags/jira_filters.py +++ /dev/null @@ -1,17 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from django.conf import settings -from django.template.defaultfilters import register - - -@register.filter -def jira_issue_url(issue): - return settings.JIRA_URL + '/browse/' + str(issue) diff --git a/src/dashboard/urls.py b/src/dashboard/urls.py index d5dad57..c87dacc 100644 --- a/src/dashboard/urls.py +++ b/src/dashboard/urls.py @@ -33,7 +33,7 @@ from dashboard.views import ( host_profile_detail_view ) -app_name = "dashboard" +app_name = 'dashboard' urlpatterns = [ url(r'^$', landing_view, name='index'), url(r'^lab/$', lab_list_view, name='all_labs'), diff --git a/src/laas_dashboard/settings.py b/src/laas_dashboard/settings.py index 6b3ed09..010ffde 100644 --- a/src/laas_dashboard/settings.py +++ b/src/laas_dashboard/settings.py @@ -15,8 +15,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # SECURITY WARNING: don't run with debug turned on in production! # NOTE: os.environ only returns strings, so making a comparison to # 'True' here will convert it to the correct Boolean value. -DEBUG = os.environ['DEBUG'] == 'True' -TESTING = os.environ['TEST'] == 'True' +DEBUG = os.environ.get('DEBUG') == 'True' +TESTING = os.environ.get('TEST') == 'True' # Application definition @@ -53,29 +53,35 @@ MIDDLEWARE = [ 'account.middleware.TimezoneMiddleware', ] -AUTH_SETTING = os.environ.get('AUTH_SETTING', 'JIRA') -if AUTH_SETTING == 'LFID': - AUTHENTICATION_BACKENDS = ['account.views.MyOIDCAB'] +#AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend', 'account.views.MyOIDCAB'] +AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend'] + +AUTH_SETTING = os.environ.get('AUTH_SETTING') +if AUTH_SETTING == 'LFID': # OpenID Authentications - OIDC_RP_CLIENT_ID = os.environ['OIDC_CLIENT_ID'] - OIDC_RP_CLIENT_SECRET = os.environ['OIDC_CLIENT_SECRET'] + AUTHENTICATION_BACKENDS.append('account.views.MyOIDCAB') + OIDC_RP_CLIENT_ID = os.environ.get('OIDC_CLIENT_ID') + OIDC_RP_CLIENT_SECRET = os.environ.get('OIDC_CLIENT_SECRET') - OIDC_OP_AUTHORIZATION_ENDPOINT = os.environ['OIDC_AUTHORIZATION_ENDPOINT'] - OIDC_OP_TOKEN_ENDPOINT = os.environ['OIDC_TOKEN_ENDPOINT'] - OIDC_OP_USER_ENDPOINT = os.environ['OIDC_USER_ENDPOINT'] + OIDC_OP_AUTHORIZATION_ENDPOINT = os.environ.get('OIDC_AUTHORIZATION_ENDPOINT') + OIDC_OP_TOKEN_ENDPOINT = os.environ.get('OIDC_TOKEN_ENDPOINT') + OIDC_OP_USER_ENDPOINT = os.environ.get('OIDC_USER_ENDPOINT') - LOGIN_REDIRECT_URL = os.environ['DASHBOARD_URL'] - LOGOUT_REDIRECT_URL = os.environ['DASHBOARD_URL'] + LOGIN_REDIRECT_URL = os.environ.get('DASHBOARD_URL') + LOGOUT_REDIRECT_URL = os.environ.get('DASHBOARD_URL') - OIDC_RP_SIGN_ALGO = os.environ["OIDC_RP_SIGN_ALGO"] + OIDC_RP_SIGN_ALGO = os.environ.get("OIDC_RP_SIGN_ALGO") + #raise Exception("OIDC rp sign algo is: ", OIDC_RP_SIGN_ALGO) if OIDC_RP_SIGN_ALGO == "RS256": - OIDC_OP_JWKS_ENDPOINT = os.environ["OIDC_OP_JWKS_ENDPOINT"] + OIDC_OP_JWKS_ENDPOINT = os.environ.get("OIDC_OP_JWKS_ENDPOINT") +else: + raise Exception('AUTH_SETTING set to invalid value') # This is for LFID auth setups w/ an HTTPS proxy -if os.environ['EXPECT_HOST_FORWARDING'] == 'True': +if os.environ.get('EXPECT_HOST_FORWARDING') == 'True': SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', "https") USE_X_FORWARDED_HOST = True @@ -162,7 +168,7 @@ STATICFILES_DIRS = [ LOGIN_REDIRECT_URL = '/' # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = os.environ['SECRET_KEY'] +SECRET_KEY = os.environ.get('SECRET_KEY') BOOTSTRAP3 = { 'set_placeholder': False, @@ -175,11 +181,11 @@ ALLOWED_HOSTS = ['*'] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'NAME': os.environ['DB_NAME'], - 'USER': os.environ['DB_USER'], - 'PASSWORD': os.environ['DB_PASS'], - 'HOST': os.environ['DB_SERVICE'], - 'PORT': os.environ['DB_PORT'] + 'NAME': os.environ.get('DB_NAME'), + 'USER': os.environ.get('DB_USER'), + 'PASSWORD': os.environ.get('DB_PASS'), + 'HOST': os.environ.get('DB_SERVICE'), + 'PORT': os.environ.get('DB_PORT') } } @@ -198,27 +204,17 @@ REST_FRAMEWORK = { MEDIA_ROOT = '/media' STATIC_ROOT = '/static' -# Jira Settings -CREATE_JIRA_TICKET = False - -JIRA_URL = os.environ['JIRA_URL'] - -JIRA_USER_NAME = os.environ['JIRA_USER_NAME'] -JIRA_USER_PASSWORD = os.environ['JIRA_USER_PASSWORD'] - -OAUTH_CONSUMER_KEY = os.environ['OAUTH_CONSUMER_KEY'] -OAUTH_CONSUMER_SECRET = os.environ['OAUTH_CONSUMER_SECRET'] - -OAUTH_REQUEST_TOKEN_URL = JIRA_URL + '/plugins/servlet/oauth/request-token' -OAUTH_ACCESS_TOKEN_URL = JIRA_URL + '/plugins/servlet/oauth/access-token' -OAUTH_AUTHORIZE_URL = JIRA_URL + '/plugins/servlet/oauth/authorize' +OAUTH_CONSUMER_KEY = os.environ.get('OAUTH_CONSUMER_KEY') +OAUTH_CONSUMER_SECRET = os.environ.get('OAUTH_CONSUMER_SECRET') -OAUTH_CALLBACK_URL = os.environ['DASHBOARD_URL'] + '/accounts/authenticated' +OAUTH_CALLBACK_URL = os.environ.get('DASHBOARD_URL') + '/accounts/authenticated' # Celery Settings CELERY_TIMEZONE = 'UTC' RABBITMQ_URL = 'rabbitmq' +#RABBITMQ_DEFAULT_USER = os.environ['DEFAULT_USER'] +#RABBITMQ_DEFAULT_PASS = os.environ['DEFAULT_PASS'] RABBITMQ_DEFAULT_USER = os.environ['RABBITMQ_DEFAULT_USER'] RABBITMQ_DEFAULT_PASS = os.environ['RABBITMQ_DEFAULT_PASS'] @@ -248,10 +244,10 @@ CELERYBEAT_SCHEDULE = { } # Notifier Settings -EMAIL_HOST = os.environ['EMAIL_HOST'] -EMAIL_PORT = os.environ['EMAIL_PORT'] -EMAIL_HOST_USER = os.environ['EMAIL_HOST_USER'] -EMAIL_HOST_PASSWORD = os.environ['EMAIL_HOST_PASSWORD'] +EMAIL_HOST = os.environ.get('EMAIL_HOST') +EMAIL_PORT = os.environ.get('EMAIL_PORT') +EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER') +EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD') EMAIL_USE_TLS = True DEFAULT_EMAIL_FROM = os.environ.get('DEFAULT_EMAIL_FROM', 'webmaster@localhost') SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" diff --git a/src/notifier/urls.py b/src/notifier/urls.py index fedb9e8..923cc33 100644 --- a/src/notifier/urls.py +++ b/src/notifier/urls.py @@ -12,7 +12,7 @@ from django.conf.urls import url from notifier.views import InboxView, NotificationView -app_name = "notifier" +app_name = 'notifier' urlpatterns = [ url(r'^$', InboxView, name='messages'), url(r'^notification/(?P<notification_id>[0-9]+)/$', NotificationView, name='notifier_single') diff --git a/src/resource_inventory/urls.py b/src/resource_inventory/urls.py index a008176..a9a4d43 100644 --- a/src/resource_inventory/urls.py +++ b/src/resource_inventory/urls.py @@ -29,7 +29,7 @@ from django.conf.urls import url from resource_inventory.views import HostView, hostprofile_detail_view -app_name = "resource" +app_name = 'resource' urlpatterns = [ url(r'^hosts$', HostView.as_view(), name='hosts'), url(r'^profiles/(?P<hostprofile_id>.+)/$', hostprofile_detail_view, name='host_detail'), diff --git a/src/static/package-lock.json b/src/static/package-lock.json index f8eabe4..89a26db 100644 --- a/src/static/package-lock.json +++ b/src/static/package-lock.json @@ -1,8 +1,97 @@ { "name": "laas", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "laas", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@fortawesome/fontawesome-free": "^5.12.0", + "bootstrap": "^4.4.1", + "datatables.net-bs4": "^1.10.20", + "datatables.net-responsive-bs4": "^2.2.3", + "jquery": "^3.4.1", + "mxgraph": "^4.0.6", + "plotly.js-dist": "^1.51.3", + "popper.js": "^1.16.0" + } + }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.12.0.tgz", + "integrity": "sha512-vKDJUuE2GAdBERaQWmmtsciAMzjwNrROXA5KTGSZvayAsmuTGjam5z6QNqNPCwDfVljLWuov1nEC3mEQf/n6fQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/bootstrap": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.4.1.tgz", + "integrity": "sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/datatables.net": { + "version": "1.10.20", + "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.20.tgz", + "integrity": "sha512-4E4S7tTU607N3h0fZPkGmAtr9mwy462u+VJ6gxYZ8MxcRIjZqHy3Dv1GNry7i3zQCktTdWbULVKBbkAJkuHEnQ==", + "dependencies": { + "jquery": "3.4.1" + } + }, + "node_modules/datatables.net-bs4": { + "version": "1.10.20", + "resolved": "https://registry.npmjs.org/datatables.net-bs4/-/datatables.net-bs4-1.10.20.tgz", + "integrity": "sha512-kQmMUMsHMOlAW96ztdoFqjSbLnlGZQ63iIM82kHbmldsfYdzuyhbb4hTx6YNBi481WCO3iPSvI6YodNec46ZAw==", + "dependencies": { + "datatables.net": "1.10.20", + "jquery": "3.4.1" + } + }, + "node_modules/datatables.net-responsive": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/datatables.net-responsive/-/datatables.net-responsive-2.2.3.tgz", + "integrity": "sha512-8D6VtZcyuH3FG0Hn5A4LPZQEOX3+HrRFM7HjpmsQc/nQDBbdeBLkJX4Sh/o1nzFTSneuT1Wh/lYZHVPpjcN+Sw==", + "dependencies": { + "datatables.net": "1.10.20", + "jquery": "3.4.1" + } + }, + "node_modules/datatables.net-responsive-bs4": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/datatables.net-responsive-bs4/-/datatables.net-responsive-bs4-2.2.3.tgz", + "integrity": "sha512-SQaWI0uLuPcaiBBin9zX+MuQfTSIkK1bYxbXqUV6NLkHCVa6PMQK7Rvftj0ywG4R7uOtjbzY8nSVqxEKvQI0Vg==", + "dependencies": { + "datatables.net-bs4": "1.10.20", + "datatables.net-responsive": "2.2.3", + "jquery": "3.4.1" + } + }, + "node_modules/jquery": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", + "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==" + }, + "node_modules/mxgraph": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/mxgraph/-/mxgraph-4.0.6.tgz", + "integrity": "sha512-5XZXeAkA4k6n4BS05Fxd2cNhMw+3dnlRqAaLtsuXdT0g8BvvEa1VT4jjuGtUW4QTt38Q+I2Dr/3EWiAaGRfAXw==" + }, + "node_modules/plotly.js-dist": { + "version": "1.51.3", + "resolved": "https://registry.npmjs.org/plotly.js-dist/-/plotly.js-dist-1.51.3.tgz", + "integrity": "sha512-Bxz0XBg963gpnbt7FVPEhYvT33JsaKa0hEozXBnQZkiKtsiM2M1lZN6tkEHmq6o1N2K6qJXFtdzCXbZ/hLGV0Q==" + }, + "node_modules/popper.js": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.0.tgz", + "integrity": "sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw==" + } + }, "dependencies": { "@fortawesome/fontawesome-free": { "version": "5.12.0", diff --git a/src/templates/base/account/configuration_list.html b/src/templates/base/account/configuration_list.html deleted file mode 100644 index fee6e83..0000000 --- a/src/templates/base/account/configuration_list.html +++ /dev/null @@ -1,85 +0,0 @@ -{% extends "base.html" %} -{% block content %} -<div class="row"> -{% for config in configurations %} - <div class="col-12 col-md-6 col-lg-4 col-xl-3 mb-3"> - <div class="card h-100"> - <div class="card-header"> - <h3>Configuration {{config.id}}</h3> - </div> - <ul class="list-group list-group-flush h-100"> - <li class="list-group-item">id: {{config.id}}</li> - <li class="list-group-item">name: {{config.name}}</li> - <li class="list-group-item">description: {{config.description}}</li> - <li class="list-group-item">resource: {{config.bundle}}</li> - </ul> - <div class="card-footer"> - <button - class="btn btn-danger w-100" - onclick='delete_config({{config.id}});' - data-toggle="modal" - data-target="#configModal" - >Delete</button> - </div> - </div> - </div> -{% empty %} - <div class="col"> - <p>You don't have any configurations. You can create a configuration by configuring a pod.</p> - </div> -{% endfor %} -</div> - -<script> - var current_config_id = -1; - function delete_config(config_id) { - current_config_id = config_id; - } - - function submit_delete_form() { - var ajaxForm = $("#config_delete_form"); - var formData = ajaxForm.serialize(); - req = new XMLHttpRequest(); - var url = "delete/" + current_config_id; - req.onreadystatechange = function() { - if (this.readyState == 4 && this.status == 200) { - location.reload(); - } - }; - req.open("POST", url, true); - req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); - req.onerror = function() { alert("problem submitting form"); } - req.send(formData); - } -</script> - -<div class="modal fade" id="configModal" tabindex="-1" role="dialog" aria-hidden="true"> - <div class="modal-dialog" role="document"> - <div class="modal-content"> - <div class="modal-header"> - <h4 class="modal-title d-inline float-left">Delete Configuration?</h4> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"> - <span aria-hidden="true">×</span> - </button> - </div> - <form id="config_delete_form"> - {% csrf_token %} - </form> - <div class="modal-footer d-flex flex-column"> - <div class="mb-2"> - <button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Close</button> - <button type="button" class="btn btn-danger" data-toggle="collapse" data-target="#warning">Delete</button> - </div> - <div class="collapse w-100 text-center border-top" id="warning"> - <div class="p-4"> - <h3>Are You Sure?</h3> - <p>This cannot be undone</p> - <button class="btn btn-outline-secondary" data-dismiss="modal">Nevermind</button> - <button class="btn btn-danger" data-dismiss="modal" onclick="submit_delete_form();">I'm Sure</button> - </div> - </div> - </div> - </div> - </div> -</div> -{% endblock %} diff --git a/src/templates/base/account/details.html b/src/templates/base/account/details.html index 3092ad0..ad59c9a 100644 --- a/src/templates/base/account/details.html +++ b/src/templates/base/account/details.html @@ -4,6 +4,5 @@ <h1>Account Details</h1> <a class="btn btn-primary" href="{% url 'account:my-resources' %}">My Resources</a> <a class="btn btn-primary" href="{% url 'account:my-bookings' %}">My Bookings</a> -<a class="btn btn-primary" href="{% url 'account:my-configurations' %}">My Configurations</a> <a class="btn btn-primary" href="{% url 'account:my-images' %}">My Snapshots</a> {% endblock content %} diff --git a/src/templates/base/base.html b/src/templates/base/base.html index 394ddec..f334a63 100644 --- a/src/templates/base/base.html +++ b/src/templates/base/base.html @@ -87,7 +87,7 @@ {% else %} <a href="{% url 'account:login' %}" class="text-dark dropdown-item"> <i class="fas fa-sign-in-alt"></i> - Login with Jira + Login </a> {% endif %} {% endif %} @@ -156,9 +156,6 @@ <a href="{% url 'account:my-bookings' %}" class="list-group-item list-group-item-action list-group-item-secondary"> My Bookings </a> - <a href="{% url 'account:my-configurations' %}" class="list-group-item list-group-item-action list-group-item-secondary"> - My Configurations - </a> <a href="{% url 'account:my-images' %}" class="list-group-item list-group-item-action list-group-item-secondary"> My Snapshots </a> diff --git a/src/templates/base/booking/booking_delete.html b/src/templates/base/booking/booking_delete.html index b89eb15..4afa370 100644 --- a/src/templates/base/booking/booking_delete.html +++ b/src/templates/base/booking/booking_delete.html @@ -1,4 +1,3 @@ -{% load jira_filters %} {% load bootstrap4 %} <p> diff --git a/src/templates/base/booking/booking_table.html b/src/templates/base/booking/booking_table.html index 32a0146..9c8341c 100644 --- a/src/templates/base/booking/booking_table.html +++ b/src/templates/base/booking/booking_table.html @@ -1,4 +1,4 @@ -{% load jira_filters %} + <thead> diff --git a/src/templates/lfedge/booking/booking_table.html b/src/templates/lfedge/booking/booking_table.html index 4afb4d2..4020b5e 100644 --- a/src/templates/lfedge/booking/booking_table.html +++ b/src/templates/lfedge/booking/booking_table.html @@ -1,4 +1,4 @@ -{% load jira_filters %} + <thead> diff --git a/src/workflow/models.py b/src/workflow/models.py index f550a38..91a216c 100644 --- a/src/workflow/models.py +++ b/src/workflow/models.py @@ -160,7 +160,7 @@ class BookingAuthManager(): return True # admin override for this user if Booking.objects.filter(owner=booking.owner, end__gt=timezone.now()).count() >= 3: return False - if len(booking.resource.template.getResources()) < 2: + if len(booking.resource.template.get_required_resources()) < 2: return True # if they only have one server, we dont care if repo.BOOKING_INFO_FILE not in repo.el: return False # INFO file not provided diff --git a/web/Dockerfile b/web/Dockerfile index 40ab8f0..c05193a 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -6,7 +6,7 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -FROM python:3.5 +FROM python:3.9 ENV PYTHONUNBUFFERED 1 RUN apt-get update && apt-get install -y npm diff --git a/worker/Dockerfile b/worker/Dockerfile index 5e24bed..edf86d1 100644 --- a/worker/Dockerfile +++ b/worker/Dockerfile @@ -6,7 +6,7 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -FROM python:3.5 +FROM python:3.9 ENV PYTHONUNBUFFERED 1 ADD requirements.txt /requirements.txt |