Retire repo and note new content in openstack/osops
Change-Id: I44c9ae8142ebfbb720300592d5c4e11c85a275d3 Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com>
This commit is contained in:
parent
da6cbda514
commit
f63b605d96
41
README
41
README
|
@ -1,33 +1,12 @@
|
||||||
Coda
|
This project is no longer maintained. Its content has now moved to the
|
||||||
======
|
https://opendev.org/openstack/osops repo, and further development will
|
||||||
|
continue there.
|
||||||
|
|
||||||
Coda is a Horizon dashboard and panel (both share the name) that facilitates resource clean up of a project once that project is no longer needed http://openstack.org
|
The contents of this repository are still available in the Git
|
||||||
|
source code management system. To see the contents of this
|
||||||
|
repository before it reached its end of life, please check out the
|
||||||
|
previous commit with "git checkout HEAD^1".
|
||||||
|
|
||||||
Coda Dashboard
|
For any further questions, please email
|
||||||
----------------
|
openstack-discuss@lists.openstack.org or join #openstack-dev on
|
||||||
Coda Dashboard is an extension for OpenStack Dashboard that provides a UI for
|
Freenode.
|
||||||
Coda.
|
|
||||||
|
|
||||||
For developer purposes, please place OpenStack Dashboard extension file, located
|
|
||||||
at *local/_42_coda.py* under horizon/openstack_dashboard/local/enabled
|
|
||||||
directory and run horizon as usual.
|
|
||||||
|
|
||||||
You will need to add the following code to the end of your local_settings.py
|
|
||||||
|
|
||||||
def load_coda():
|
|
||||||
import imp
|
|
||||||
|
|
||||||
#Go up a level, coda should be installed there.
|
|
||||||
local_settings_dir = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
|
|
||||||
local_settings_dir+="/dashboards/coda"
|
|
||||||
|
|
||||||
#print local_settings_dir
|
|
||||||
module = imp.load_source("coda", "%s/coda.py" % local_settings_dir)
|
|
||||||
for attr in dir(module):
|
|
||||||
if not attr.startswith('_'):
|
|
||||||
globals()[attr] = getattr(module, attr)
|
|
||||||
|
|
||||||
load_coda()
|
|
||||||
|
|
||||||
This makes sure that the coda.py file containing your settings are imported properly. This is probably a hack
|
|
||||||
but I haven't found a better way to do this yet.
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
"""The coda dashboard package.
|
|
||||||
|
|
||||||
Coda is a Horizon dashboard and panel (both share the name) that
|
|
||||||
facilitates resource clean up of a project once that project is no longer
|
|
||||||
needed http://openstack.org
|
|
||||||
"""
|
|
51
coda.py
51
coda.py
|
@ -1,51 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Settings for the coda panel.
|
|
||||||
|
|
||||||
There may be a better way or place to do this but for now this works
|
|
||||||
so I'm rolling with it.
|
|
||||||
"""
|
|
||||||
|
|
||||||
CODA_USERNAME = "coda_admin"
|
|
||||||
CODA_TENANT_NAME = "coda_admin"
|
|
||||||
CODA_TENANT_ID = "coda_project_id"
|
|
||||||
CODA_PASSWORD = "coda_pw"
|
|
||||||
CODA_AUTH_URL = "http://127.0.0.1:5000/v2.0/"
|
|
||||||
CODA_KEYSTONE_URL = "http://10.23.214.201:35357/v2.0/"
|
|
||||||
|
|
||||||
CODA_AUTH_URL_KEY = "CODA_AUTH_URL"
|
|
||||||
NOVA_ADMIN_URL_KEY = "NOVA_ADMIN_URL"
|
|
||||||
NEUTRON_ADMIN_URL_KEY = "NEUTRON_ADMIN_URL"
|
|
||||||
CINDER_ADMIN_URL_KEY = "CINDER_ADMIN_URL"
|
|
||||||
GLANCE_ADMIN_URL_KEY = "GLANCE_ADMIN_URL"
|
|
||||||
|
|
||||||
CODA_BLACK_LIST = ["00000000001001", "15420898376896"]
|
|
||||||
|
|
||||||
CODA_URL_MAP = {
|
|
||||||
"region-a": {
|
|
||||||
"CODA_AUTH_URL": "http://127.0.0.1:35357/v2.0/",
|
|
||||||
"NOVA_ADMIN_URL": "http://127.0.0.1:8774/v2",
|
|
||||||
"NEUTRON_ADMIN_URL": "http://127.0.0.1:9696/v2.0",
|
|
||||||
"CINDER_ADMIN_URL": "http://127.0.0.1:8776/v2",
|
|
||||||
"GLANCE_ADMIN_URL": "http://127.0.0.1:9292/v2",
|
|
||||||
},
|
|
||||||
# "region-b": {
|
|
||||||
# "CODA_AUTH_URL": "https://127.0.0.1:35357/v2.0/",
|
|
||||||
# "NOVA_ADMIN_URL": "https://127.0.0.1/v2",
|
|
||||||
# "NEUTRON_ADMIN_URL": "https://127.0.0.1/v2.0",
|
|
||||||
# "CINDER_ADMIN_URL": "https://127.0.0.1:8776/v1",
|
|
||||||
# "GLANCE_ADMIN_URL": "https://127.0.0.1:9292/v1.0",
|
|
||||||
# },
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
"""The coda panel package.
|
|
||||||
|
|
||||||
Coda is a Horizon dashboard and panel (both share the name) that
|
|
||||||
facilitates resource clean up of a project once that project is no longer
|
|
||||||
needed http://openstack.org
|
|
||||||
"""
|
|
194
coda/cinder.py
194
coda/cinder.py
|
@ -1,194 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
All cinder interactions go here.
|
|
||||||
|
|
||||||
Not much else to say.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
def list_volumes(auth_token, region, project_id):
|
|
||||||
"""List volumes."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {'all_tenants': '1', 'project_id': project_id}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
response = requests.get(
|
|
||||||
"%s/%s/volumes/detail" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.CINDER_ADMIN_URL_KEY],
|
|
||||||
settings.CODA_TENANT_ID),
|
|
||||||
headers=headers, params=params, verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
volumes_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = volumes_dict['volumes']
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def list_snapshots(auth_token, region, project_id):
|
|
||||||
"""List snapshots."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {'all_tenants': '1', 'project_id': project_id}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
response = requests.get(
|
|
||||||
"%s/%s/snapshots/detail" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.CINDER_ADMIN_URL_KEY],
|
|
||||||
settings.CODA_TENANT_ID),
|
|
||||||
headers=headers, params=params, verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
snapshots_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = snapshots_dict['snapshots']
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def list_backups(auth_token, region, project_id):
|
|
||||||
"""List backups."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json"
|
|
||||||
}
|
|
||||||
# todo (nathan) figure out why this changed
|
|
||||||
# params = {'all_tenants': '1', 'project_id': project_id}
|
|
||||||
params = {}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
response = requests.get(
|
|
||||||
"%s/%s/backups/detail" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.CINDER_ADMIN_URL_KEY],
|
|
||||||
settings.CODA_TENANT_ID),
|
|
||||||
headers=headers, params=params, verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
backups_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = backups_dict['backups']
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def delete_volume(auth_token, region, tenant_id, volume_id):
|
|
||||||
"""Delete volumes."""
|
|
||||||
result = 'Volume Deleted'
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
params = {'all_tenants': '1', 'project_id': tenant_id}
|
|
||||||
|
|
||||||
# todo double check why I used codas tenant id here vs user tenant id
|
|
||||||
response = requests.delete("%s/%s/volumes/%s" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.CINDER_ADMIN_URL_KEY],
|
|
||||||
settings.CODA_TENANT_ID,
|
|
||||||
volume_id), headers=headers, params=params, verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 202:
|
|
||||||
result = repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def delete_snapshot(auth_token, region, tenant_id, snapshot_id):
|
|
||||||
"""Delete snapshots."""
|
|
||||||
result = 'Snapshot Deleted'
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
params = {'all_tenants': '1', 'project_id': tenant_id}
|
|
||||||
|
|
||||||
# todo double check why I used codas tenant id here vs user tenant id
|
|
||||||
response = requests.delete("%s/%s/snapshots/%s" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.CINDER_ADMIN_URL_KEY],
|
|
||||||
settings.CODA_TENANT_ID,
|
|
||||||
snapshot_id), headers=headers, params=params, verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 202:
|
|
||||||
result = repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def delete_backup(auth_token, region, tenant_id, backup_id):
|
|
||||||
"""Delete backups."""
|
|
||||||
result = 'Backup Deleted'
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
params = {'all_tenants': '1', 'project_id': tenant_id}
|
|
||||||
|
|
||||||
# todo double check why I used codas tenant id here vs user tenant id
|
|
||||||
response = requests.delete("%s/%s/backups/%s" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.CINDER_ADMIN_URL_KEY],
|
|
||||||
settings.CODA_TENANT_ID,
|
|
||||||
backup_id), headers=headers, params=params, verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 202:
|
|
||||||
result = repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
90
coda/coda.py
90
coda/coda.py
|
@ -1,90 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Code that is specific to Coda.
|
|
||||||
|
|
||||||
Methods that aren't specific to an OpenStack API go here.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.cache import cache
|
|
||||||
from openstack_dashboard.dashboards.coda.coda import keystone
|
|
||||||
|
|
||||||
CODA_CACHE = 'coda_cache'
|
|
||||||
|
|
||||||
|
|
||||||
def get_coda_regions():
|
|
||||||
"""Return a list of regions for the Coda installation."""
|
|
||||||
return settings.CODA_URL_MAP.keys()
|
|
||||||
|
|
||||||
|
|
||||||
def get_auth_token():
|
|
||||||
"""Abstract getting the Coda auth token from cache or API as needed."""
|
|
||||||
coda_cache = {}
|
|
||||||
|
|
||||||
if cache.get(CODA_CACHE) is not None:
|
|
||||||
coda_cache = cache.get(CODA_CACHE)
|
|
||||||
|
|
||||||
if 'coda_token' not in coda_cache:
|
|
||||||
coda_token = keystone.get_coda_token()
|
|
||||||
coda_cache['coda_token'] = coda_token
|
|
||||||
# keep for an hour
|
|
||||||
cache.set('coda_cache', coda_cache, 3600)
|
|
||||||
else:
|
|
||||||
coda_token = coda_cache['coda_token']
|
|
||||||
|
|
||||||
return coda_token
|
|
||||||
|
|
||||||
|
|
||||||
def fill_image_info(instances, images):
|
|
||||||
"""Use image dict to fill in image name for instances."""
|
|
||||||
for user_id in instances:
|
|
||||||
for instance in instances[user_id]:
|
|
||||||
if images is None:
|
|
||||||
instance['image']['name'] = "Image Info Unavailable"
|
|
||||||
else:
|
|
||||||
for image in images:
|
|
||||||
if image['id'] == instance['image']['id']:
|
|
||||||
instance['image']['name'] = image['name']
|
|
||||||
break
|
|
||||||
|
|
||||||
if 'name' not in instance['image']:
|
|
||||||
instance['image']['name'] = "Error Getting Image Info"
|
|
||||||
|
|
||||||
return instances
|
|
||||||
|
|
||||||
|
|
||||||
def fill_volume_info(volumes, snapshots, backups):
|
|
||||||
"""Unify volume, snapshot, and backup in a single dict."""
|
|
||||||
|
|
||||||
print backups
|
|
||||||
for volume in volumes:
|
|
||||||
volume['snapshots'] = []
|
|
||||||
volume['backups'] = []
|
|
||||||
|
|
||||||
for snapshot in snapshots:
|
|
||||||
if snapshot['volume_id'] == volume['id']:
|
|
||||||
volume['snapshots'].append(snapshot)
|
|
||||||
|
|
||||||
for backup in backups:
|
|
||||||
if backup['volume_id'] == volume['id']:
|
|
||||||
volume['backups'].append(backup)
|
|
||||||
|
|
||||||
return volumes
|
|
||||||
|
|
||||||
|
|
||||||
def is_project_black_listed(project_id):
|
|
||||||
"""Check if a project ID is blacklisted (i.e. shouldn't be cleaned)."""
|
|
||||||
return project_id in settings.CODA_BLACK_LIST
|
|
163
coda/glance.py
163
coda/glance.py
|
@ -1,163 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
All glance interactions go here.
|
|
||||||
|
|
||||||
Not much else to say.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
def list_images(auth_token, region, tenant_id):
|
|
||||||
"""List all images for a project."""
|
|
||||||
result = {}
|
|
||||||
limit = 1000
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
params = {
|
|
||||||
'limit': limit,
|
|
||||||
'is_public': 'None',
|
|
||||||
'property-owner_id': tenant_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
response = requests.get(
|
|
||||||
"%s/images/detail" %
|
|
||||||
settings.CODA_URL_MAP[region][settings.GLANCE_ADMIN_URL_KEY],
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
images_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = images_dict['images']
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def list_all_images(auth_token, region):
|
|
||||||
"""List all images for a region."""
|
|
||||||
result = {'public': []}
|
|
||||||
images = []
|
|
||||||
limit = 1000
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {'limit': limit}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
response = requests.get(
|
|
||||||
"%s/images" %
|
|
||||||
settings.CODA_URL_MAP[region][settings.GLANCE_ADMIN_URL_KEY],
|
|
||||||
headers=headers, params=params, verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
images_dict = json.loads(response.text)
|
|
||||||
count = len(images_dict['images'])
|
|
||||||
|
|
||||||
if count < limit:
|
|
||||||
images.extend(images_dict['images'])
|
|
||||||
else:
|
|
||||||
marker = images_dict['images'][count - 1]['id']
|
|
||||||
images = get_next_images(auth_token, region, limit,
|
|
||||||
images_dict['images'], marker)
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified." % region
|
|
||||||
|
|
||||||
for image in images:
|
|
||||||
if image['owner'] is None and image['is_public'] is True:
|
|
||||||
result['public'].append(image)
|
|
||||||
else:
|
|
||||||
if image['owner'] not in result:
|
|
||||||
result[image['owner']] = []
|
|
||||||
|
|
||||||
result[image['owner']].append(image)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_next_images(auth_token, region, limit, images, marker):
|
|
||||||
"""Recursive method used to list all images for a region."""
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {'limit': limit, 'is_public': 'None', 'marker': marker}
|
|
||||||
|
|
||||||
response = requests.get(
|
|
||||||
"%s/images/detail" %
|
|
||||||
settings.CODA_URL_MAP[region][settings.GLANCE_ADMIN_URL_KEY],
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
images_dict = json.loads(response.text)
|
|
||||||
count = len(images_dict['images'])
|
|
||||||
|
|
||||||
if len(images_dict['images']) < limit:
|
|
||||||
images.extend(images_dict['images'])
|
|
||||||
else:
|
|
||||||
images.extend(images_dict['images'])
|
|
||||||
marker = images_dict['images'][count - 1]['id']
|
|
||||||
images = get_next_images(auth_token, region, limit, images, marker)
|
|
||||||
else:
|
|
||||||
# todo (nathan) throw exception here
|
|
||||||
print("todo throw exception")
|
|
||||||
|
|
||||||
return images
|
|
||||||
|
|
||||||
|
|
||||||
def delete_image(auth_token, region, image_id):
|
|
||||||
"""Delete the image."""
|
|
||||||
result = 'Image Deleted'
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.delete(
|
|
||||||
"%s/images/%s" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.GLANCE_ADMIN_URL_KEY],
|
|
||||||
image_id),
|
|
||||||
headers=headers,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 204:
|
|
||||||
result = repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
117
coda/keystone.py
117
coda/keystone.py
|
@ -1,117 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
All keystone interactions go here.
|
|
||||||
|
|
||||||
Not much else to say.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
|
|
||||||
JSON_HEADERS = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_coda_token():
|
|
||||||
"""Return the auth token for the coda user."""
|
|
||||||
payload = {
|
|
||||||
"auth": {
|
|
||||||
"tenantId": settings.CODA_TENANT_ID,
|
|
||||||
"passwordCredentials": {
|
|
||||||
"username": settings.CODA_USERNAME,
|
|
||||||
"password": settings.CODA_PASSWORD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = 'error'
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = requests.post(
|
|
||||||
"%s/tokens" % settings.CODA_AUTH_URL,
|
|
||||||
data=json.dumps(payload),
|
|
||||||
headers=JSON_HEADERS,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
result = json.loads(response.text)['access']['token']['id']
|
|
||||||
except Exception as ex:
|
|
||||||
print("error in get_coda_token", ex)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_project_users(auth_token, project_id):
|
|
||||||
"""Return a map of user info for a given project."""
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
response = requests.get(
|
|
||||||
"%s/tenants/%s/users" % (settings.CODA_KEYSTONE_URL, project_id),
|
|
||||||
headers=headers,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
return json.loads(response.text)['users']
|
|
||||||
|
|
||||||
|
|
||||||
def user_authenticate(tenant_id, username, password):
|
|
||||||
"""Get the auth token for a user of Coda."""
|
|
||||||
payload = {
|
|
||||||
"auth": {
|
|
||||||
"tenantId": tenant_id,
|
|
||||||
"passwordCredentials": {
|
|
||||||
"username": username,
|
|
||||||
"password": password
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = 'error'
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = requests.post("%s/tokens" % settings.CODA_AUTH_URL,
|
|
||||||
data=json.dumps(payload),
|
|
||||||
headers=JSON_HEADERS,
|
|
||||||
verify=False)
|
|
||||||
result = json.loads(response.text)['access']['token']['id']
|
|
||||||
except Exception as ex:
|
|
||||||
print("error in user_authenticate", ex)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def project_exists(auth_token, project_id):
|
|
||||||
"""Check if the project id is valid / exists.
|
|
||||||
|
|
||||||
Returns true with info if it does and false and empty if not.
|
|
||||||
"""
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
response = requests.get(
|
|
||||||
"%s/tenants/%s" % (settings.CODA_KEYSTONE_URL, project_id),
|
|
||||||
headers=headers,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
return True, json.loads(response.text)
|
|
||||||
else:
|
|
||||||
return False, ''
|
|
359
coda/neutron.py
359
coda/neutron.py
|
@ -1,359 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
All keystone interactions go here.
|
|
||||||
|
|
||||||
Not much else to say.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# import logging
|
|
||||||
# from django.core.cache import cache
|
|
||||||
from django.conf import settings
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
def list_floating_ips(auth_token, region, project_id):
|
|
||||||
"""Return a list of maps with floating ip info."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {'all_tenants': '1', 'tenant_id': project_id}
|
|
||||||
col_filter = "fields=id&fields=floating_ip_address"
|
|
||||||
col_filter += "&fields=fixed_ip_address&fields=port_id"
|
|
||||||
|
|
||||||
response = requests.get(
|
|
||||||
"%s/floatingips?%s" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
col_filter),
|
|
||||||
headers=headers, params=params, verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
floating_ip_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = floating_ip_dict['floatingips']
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def list_security_groups(auth_token, region, project_id):
|
|
||||||
"""Return a list of maps with security group info."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {'all_tenants': '1', 'tenant_id': project_id}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
response = requests.get(
|
|
||||||
"%s/security-groups" %
|
|
||||||
settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
headers=headers,
|
|
||||||
params=params, verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
sec_group_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = sec_group_dict['security_groups']
|
|
||||||
result = remove_default_security_group(result)
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def list_networks(auth_token, region, project_id):
|
|
||||||
"""List networks."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {'all_tenants': '1', 'tenant_id': project_id}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
result[region] = {}
|
|
||||||
|
|
||||||
response = requests.get(
|
|
||||||
"%s/networks" %
|
|
||||||
settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
network_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = network_dict['networks']
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def list_subnets(auth_token, region, project_id):
|
|
||||||
"""List subnets."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {'all_tenants': '1', 'tenant_id': project_id}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
response = requests.get(
|
|
||||||
"%s/subnets" %
|
|
||||||
settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
subnet_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = subnet_dict['subnets']
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def list_routers(auth_token, region, project_id):
|
|
||||||
"""List routers."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {'tenant_id': project_id}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
response = requests.get(
|
|
||||||
"%s/routers" %
|
|
||||||
settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
router_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = router_dict['routers']
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def delete_floating_ip(auth_token, region, tenant_id, floating_ip_id):
|
|
||||||
"""Delete floating ips."""
|
|
||||||
result = 'Floating IP Deleted'
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
params = {'all_tenants': '1', 'tenant_id': tenant_id, 'fields': 'id'}
|
|
||||||
|
|
||||||
response = requests.delete(
|
|
||||||
"%s/floatingips/%s" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
floating_ip_id),
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 204:
|
|
||||||
result = repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def delete_security_group(auth_token, region, tenant_id, security_group_id):
|
|
||||||
"""Delete security groups."""
|
|
||||||
result = 'Security Group Deleted'
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
params = {'all_tenants': '1', 'tenant_id': tenant_id}
|
|
||||||
|
|
||||||
response = requests.delete(
|
|
||||||
"%s/security-groups/%s" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
security_group_id),
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 204:
|
|
||||||
result = repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def delete_network(auth_token, region, tenant_id, network_id):
|
|
||||||
"""Delete networks."""
|
|
||||||
result = 'Network Deleted'
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
params = {'all_tenants': '1', 'tenant_id': tenant_id}
|
|
||||||
|
|
||||||
response = requests.delete(
|
|
||||||
"%s/networks/%s" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
network_id),
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 204:
|
|
||||||
result = repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def delete_router(auth_token, region, tenant_id, router_id):
|
|
||||||
"""Delete routers."""
|
|
||||||
result = 'Router Deleted'
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
ports = list_ports_for_device(
|
|
||||||
auth_token,
|
|
||||||
settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
tenant_id,
|
|
||||||
router_id)
|
|
||||||
port_error = False
|
|
||||||
|
|
||||||
for port in ports:
|
|
||||||
data = {'port_id': port['id']}
|
|
||||||
|
|
||||||
response = requests.put(
|
|
||||||
"%s/routers/%s/remove_router_interface" %
|
|
||||||
(settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
router_id),
|
|
||||||
headers=headers,
|
|
||||||
data=json.dumps(data),
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 200:
|
|
||||||
result = "Couldn't remove port id [%s]. Delete aborted." \
|
|
||||||
% port['id']
|
|
||||||
port_error = True
|
|
||||||
break
|
|
||||||
|
|
||||||
# Remove the router if the interfaces were cleared ok.
|
|
||||||
if not port_error:
|
|
||||||
params = {'all_tenants': '1', 'tenant_id': tenant_id}
|
|
||||||
response = requests.delete(
|
|
||||||
"%s/routers/%s" %
|
|
||||||
(settings.CODA_URL_MAP[region][settings.NEUTRON_ADMIN_URL_KEY],
|
|
||||||
router_id),
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 204:
|
|
||||||
result = repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def list_ports_for_device(auth_token, url_base, tenant_id, device_id):
|
|
||||||
"""Utility method used by delete."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
params = {
|
|
||||||
'all_tenants': '1',
|
|
||||||
'tenant_id': tenant_id,
|
|
||||||
'device_id': device_id,
|
|
||||||
}
|
|
||||||
response = requests.get(
|
|
||||||
"%s/ports" % url_base,
|
|
||||||
headers=headers,
|
|
||||||
params=params,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
ports_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
result = ports_dict['ports']
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def remove_default_security_group(security_groups):
|
|
||||||
"""Utility method to prevent default sec group from displaying."""
|
|
||||||
# todo (nathan) awful, use a list comprehension for this
|
|
||||||
result = []
|
|
||||||
for group in security_groups:
|
|
||||||
if group['name'] != 'default':
|
|
||||||
result.append(group)
|
|
||||||
|
|
||||||
return result
|
|
95
coda/nova.py
95
coda/nova.py
|
@ -1,95 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
All Nova interactions go here.
|
|
||||||
|
|
||||||
Not much else to say.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# import logging
|
|
||||||
# from django.core.cache import cache
|
|
||||||
from django.conf import settings
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
def list_instances(auth_token, region, tenant_id):
|
|
||||||
"""Return a map keyed with user ids to a map with instance info."""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
payload = {'all_tenants': '1', 'tenant_id': tenant_id}
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
response = requests.get(
|
|
||||||
"%s/%s/servers/detail" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.NOVA_ADMIN_URL_KEY],
|
|
||||||
settings.CODA_TENANT_ID),
|
|
||||||
headers=headers,
|
|
||||||
params=payload,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
server_dict = json.loads(response.text)
|
|
||||||
|
|
||||||
if "servers" in server_dict:
|
|
||||||
sorted_instances = \
|
|
||||||
sorted(server_dict['servers'], key=lambda k: k['user_id'])
|
|
||||||
|
|
||||||
for instance in sorted_instances:
|
|
||||||
if instance['user_id'] not in result.keys():
|
|
||||||
result[instance['user_id']] = []
|
|
||||||
|
|
||||||
result[instance['user_id']].append(instance)
|
|
||||||
else:
|
|
||||||
result['error'] = \
|
|
||||||
repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result['error'] = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def delete_instance(auth_token, region, tenant_id, instance_id):
|
|
||||||
"""Delete the instance."""
|
|
||||||
result = 'Instance Deleted'
|
|
||||||
|
|
||||||
if region in settings.CODA_URL_MAP:
|
|
||||||
headers = {
|
|
||||||
"X-Auth-Token": auth_token,
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
payload = {'all_tenants': '1', 'tenant_id': tenant_id}
|
|
||||||
|
|
||||||
response = requests.delete(
|
|
||||||
"%s/%s/servers/%s" % (
|
|
||||||
settings.CODA_URL_MAP[region][settings.NOVA_ADMIN_URL_KEY],
|
|
||||||
settings.CODA_TENANT_ID,
|
|
||||||
instance_id),
|
|
||||||
headers=headers,
|
|
||||||
params=payload,
|
|
||||||
verify=False)
|
|
||||||
|
|
||||||
if response.status_code != 204:
|
|
||||||
result = repr(response.status_code) + " - " + response.text
|
|
||||||
else:
|
|
||||||
result = "Invalid region %s specified.", region
|
|
||||||
|
|
||||||
return result
|
|
|
@ -1,35 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
The Coda panel definition.
|
|
||||||
|
|
||||||
Not much else to say.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
import horizon
|
|
||||||
from openstack_dashboard.dashboards.coda import dashboard
|
|
||||||
|
|
||||||
|
|
||||||
class Coda(horizon.Panel):
|
|
||||||
"""The Coda panel class."""
|
|
||||||
|
|
||||||
name = _("Coda")
|
|
||||||
slug = "coda"
|
|
||||||
|
|
||||||
|
|
||||||
dashboard.Coda.register(Coda)
|
|
|
@ -1,27 +0,0 @@
|
||||||
{% extends 'base.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% block title %}{% trans "Coda - Resource Cleanup" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block page_header %}
|
|
||||||
{% include "horizon/common/_page_header.html" with title=_("Coda - Resource Cleanup") %}
|
|
||||||
{% endblock page_header %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
<div>
|
|
||||||
<form id="coda_form" action="{% url 'horizon:coda:coda:results' %}" method="post" style="width: 655px">
|
|
||||||
{% csrf_token %}
|
|
||||||
<label for="project_id">Project ID:</label>
|
|
||||||
<input id="project_id" type="text" name="project_id" style="width: 400px" value="{% if project_id %}{{ project_id }}{%endif%}" autofocus="true" tabindex="10"/>
|
|
||||||
<input class="btn btn-primary" type="submit" value="Search" tabindex="20"/>
|
|
||||||
<input id="update_cache" type="checkbox" name="update_cache" value="True" tabindex="20" {% ifequal update_cache 'True' %}checked{%endifequal%}/> Update Cache
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{% block results %}{% endblock %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
{{ block.super }}
|
|
||||||
|
|
||||||
<script type="text/javascript" src="{{ STATIC_URL }}/coda/js/js.cookie.js"></script>
|
|
||||||
{% block custom_js %}{% endblock %}
|
|
||||||
{% endblock %}
|
|
|
@ -1,97 +0,0 @@
|
||||||
{% extends "coda/coda/coda_base.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Confirm Delete?{% endblock %}
|
|
||||||
|
|
||||||
{% block custom_js %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
function confirmDelete() {
|
|
||||||
if (confirm("Are you sure you want to delete all resources?")) {
|
|
||||||
document.scrubber_form.submit();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block results %}
|
|
||||||
|
|
||||||
<div id="splash">
|
|
||||||
<div class="sidebar">
|
|
||||||
<h2>Project Info</h2>
|
|
||||||
<p>Project Name: {{ project_info.tenant.name }}</p>
|
|
||||||
<p>Project ID: {{ project_info.tenant.id}}</p>
|
|
||||||
<p>Enabled: {{ project_info.tenant.enabled }}</p>
|
|
||||||
<p>Description: {{ project_info.tenant.description}}</p>
|
|
||||||
<input type="hidden" name="project_id" value="{{ project_id }}">
|
|
||||||
{% if users %}
|
|
||||||
<h4>Users:</h4>
|
|
||||||
{% for user in users %}
|
|
||||||
<p>Name: {{ user.name }}</p>
|
|
||||||
<p>Username: {{ user.username }}</p>
|
|
||||||
<p>ID: {{ user.id }}</p>
|
|
||||||
<p>Enabled: {{ user.enabled }}</p>
|
|
||||||
<p>E-Mail: {{ user.email }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<h4>No Users in this Project</h4>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='content_body'>
|
|
||||||
<div class="warning">
|
|
||||||
<h2 class="warning-text">WARNING!</h2>
|
|
||||||
<h3 class="warning-text"> You are about to delete all resources this project. This action cannot be undone.</h3>
|
|
||||||
</div>
|
|
||||||
<div class="row large-rounded">
|
|
||||||
<div id="login" class="confirm">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h3>Enter Admin Credentials to Continue</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="delete_form" action="{% url 'horizon:coda:coda:delete_resources' %}" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="modal-body clearfix">
|
|
||||||
<div class="messages"></div>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<input type="hidden" name="domainId" value="{{ domain_id }}">
|
|
||||||
<div class="control-group form-field clearfix ">
|
|
||||||
<label for="os_username">OS_USERNAME</label>
|
|
||||||
<div class="input">
|
|
||||||
<input autofocus="true" id="os_username" name="os_username" tabindex="10" type="text">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group form-field clearfix ">
|
|
||||||
<label for="os_password">OS_PASSWORD</label>
|
|
||||||
|
|
||||||
<div class="input">
|
|
||||||
<input id="os_password" name="os_password" tabindex="20" type="password">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group form-field clearfix ">
|
|
||||||
<label for="os_tenant_id">OS_TENANT_ID</label>
|
|
||||||
<div class="input">
|
|
||||||
<input id="os_tenant_id" name="os_tenant_id" tabindex="30" type="text">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="project_id" value="{{ project_id }}">
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-primary pull-right" tabindex="40">Delete Resources</button>
|
|
||||||
<a href="{% url 'horizon:coda:coda:index' %}">
|
|
||||||
<input class="btn pull-right" type="button" value="Cancel" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,78 +0,0 @@
|
||||||
{% load template_utils %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
var backups_{{ region|jsfunc }}_{{ project_id }}_done = false;
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var user_token = "{{ user_token }}";
|
|
||||||
|
|
||||||
$.post('/coda/delete/backups/',
|
|
||||||
{csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, user_token: user_token},
|
|
||||||
function(data, status) {
|
|
||||||
var resultsDiv = $('#backups_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Backups</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Outcome</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.map(data, function (outcome, instanceId) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instanceId + "</td>");
|
|
||||||
tr.append("<td>" + outcome + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='2'>");
|
|
||||||
var span = $("<span colspan='2'>");
|
|
||||||
var footerMessage = "Displaying " + Object.keys(data).length + " item";
|
|
||||||
if (Object.keys(data).length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#backups_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Backups in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#backups_{{ region }}_{{ project_id }}').find('#deleting').hide();
|
|
||||||
$('#backups_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
backups_{{ region|jsfunc }}_{{ project_id }}_done = true;
|
|
||||||
scrub_volumes_{{ region|jsfunc }}_{{ project_id }}();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="backups_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="deleting">
|
|
||||||
<h3>Deleting Backups...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,78 +0,0 @@
|
||||||
{% load template_utils %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
function scrub_floating_ips_{{ region|jsfunc }}_{{ project_id }}(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var user_token = "{{ user_token }}";
|
|
||||||
|
|
||||||
$('#floating_ips_{{ region }}_{{ project_id }}').find('#deleting').find('h3').html("Deleting floating IPs...")
|
|
||||||
|
|
||||||
$.post('/coda/delete/floating_ips/',
|
|
||||||
{csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, user_token: user_token},
|
|
||||||
function(data, status) {
|
|
||||||
var resultsDiv = $('#floating_ips_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Floating IPs</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Outcome</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.map(data, function (outcome, instanceId) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instanceId + "</td>");
|
|
||||||
tr.append("<td>" + outcome + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='2'>");
|
|
||||||
var span = $("<span colspan='2'>");
|
|
||||||
var footerMessage = "Displaying " + Object.keys(data).length + " item";
|
|
||||||
if (Object.keys(data).length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#floating_ips_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Floating IPs in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#floating_ips_{{ region }}_{{ project_id }}').find('#deleting').hide();
|
|
||||||
$('#floating_ips_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
wait_security_groups_{{ region|jsfunc }}_{{ project_id }}();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="floating_ips_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="deleting">
|
|
||||||
<h3>Waiting for instances to delete...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,74 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var user_token = "{{ user_token }}";
|
|
||||||
|
|
||||||
$.post('/coda/delete/images/',
|
|
||||||
{csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, user_token: user_token},
|
|
||||||
function(data, status) {
|
|
||||||
var resultsDiv = $('#images_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Images</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Outcome</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.map(data, function (outcome, instanceId) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instanceId + "</td>");
|
|
||||||
tr.append("<td>" + outcome + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='2'>");
|
|
||||||
var span = $("<span colspan='2'>");
|
|
||||||
var footerMessage = "Displaying " + Object.keys(data).length + " item";
|
|
||||||
if (Object.keys(data).length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#images_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Images in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#images_{{ region }}_{{ project_id }}').find('#deleting').hide();
|
|
||||||
$('#images_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="images_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="deleting">
|
|
||||||
<h3>Deleting Images...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,76 +0,0 @@
|
||||||
{% load template_utils %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var user_token = "{{ user_token }}";
|
|
||||||
|
|
||||||
$.post('/coda/delete/instances/',
|
|
||||||
{csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, user_token: user_token},
|
|
||||||
function(data, status) {
|
|
||||||
var resultsDiv = $('#instances_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Instances</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Outcome</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.map(data, function (outcome, instanceId) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instanceId + "</td>");
|
|
||||||
tr.append("<td>" + outcome + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='2'>");
|
|
||||||
var span = $("<span colspan='2'>");
|
|
||||||
var footerMessage = "Displaying " + Object.keys(data).length + " item";
|
|
||||||
if (Object.keys(data).length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#instances_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Instances in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#instances_{{ region }}_{{ project_id }}').find('#deleting').hide();
|
|
||||||
$('#instances_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
scrub_floating_ips_{{ region|jsfunc }}_{{ project_id }}();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="instances_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="deleting">
|
|
||||||
<h3>Deleting instances...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,77 +0,0 @@
|
||||||
{% load template_utils %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
function scrub_networks_{{ region|jsfunc }}_{{ project_id }}(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var user_token = "{{ user_token }}";
|
|
||||||
|
|
||||||
$('#networks_{{ region }}_{{ project_id }}').find('#deleting').find('h3').html("Deleting Networks...")
|
|
||||||
|
|
||||||
$.post('/coda/delete/networks/',
|
|
||||||
{csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, user_token: user_token},
|
|
||||||
function(data, status) {
|
|
||||||
var resultsDiv = $('#networks_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Networks</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Outcome</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.map(data, function (outcome, instanceId) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instanceId + "</td>");
|
|
||||||
tr.append("<td>" + outcome + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='2'>");
|
|
||||||
var span = $("<span colspan='2'>");
|
|
||||||
var footerMessage = "Displaying " + Object.keys(data).length + " item";
|
|
||||||
if (Object.keys(data).length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#networks_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Networks in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#networks_{{ region }}_{{ project_id }}').find('#deleting').hide();
|
|
||||||
$('#networks_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="networks_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="deleting">
|
|
||||||
<h3>Waiting for Routers to delete...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,51 +0,0 @@
|
||||||
{% extends "coda/coda/coda_base.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Delete Results{% endblock %}
|
|
||||||
|
|
||||||
{% block results %}
|
|
||||||
|
|
||||||
<div id="main_content">
|
|
||||||
<div class="sidebar">
|
|
||||||
<h2>Project Info</h2>
|
|
||||||
<div style="margin-left: 14px">
|
|
||||||
<p>Project Name: {{ project_info.tenant.name }}</p>
|
|
||||||
<p>Project ID: {{ project_info.tenant.id}}</p>
|
|
||||||
<p>Enabled: {{ project_info.tenant.enabled }}</p>
|
|
||||||
<p>Description: {{ project_info.tenant.description}}</p>
|
|
||||||
<input type="hidden" name="project_id" value="{{ project_id }}">
|
|
||||||
{% if users %}
|
|
||||||
<h4>Users:</h4>
|
|
||||||
{% for user in users %}
|
|
||||||
<p>Name: {{ user.name }}</p>
|
|
||||||
<p>Username: {{ user.username }}</p>
|
|
||||||
<p>ID: {{ user.id }}</p>
|
|
||||||
<p>Enabled: {{ user.enabled }}</p>
|
|
||||||
<p>E-Mail: {{ user.email }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<h4>No Users in this Project</h4>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='content_body'>
|
|
||||||
<h1>Coda Results for Project ID: {{ project_id }}</h1>
|
|
||||||
{% for region in regions %}
|
|
||||||
<h2>Region: {{ region }}</h2>
|
|
||||||
{% include "coda/coda/delete/instances.html" %}
|
|
||||||
{% include "coda/coda/delete/floating_ips.html" %}
|
|
||||||
{% include "coda/coda/delete/security_groups.html" %}
|
|
||||||
{% include "coda/coda/delete/routers.html" %}
|
|
||||||
{% include "coda/coda/delete/networks.html" %}
|
|
||||||
{% include "coda/coda/delete/snapshots.html" %}
|
|
||||||
{% include "coda/coda/delete/backups.html" %}
|
|
||||||
{% include "coda/coda/delete/volumes.html" %}
|
|
||||||
{% include "coda/coda/delete/images.html" %}
|
|
||||||
{% endfor %} <!-- END region for loop -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
{% load template_utils %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
function scrub_routers_{{ region|jsfunc }}_{{ project_id }}(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var user_token = "{{ user_token }}";
|
|
||||||
|
|
||||||
$('#routers_{{ region }}_{{ project_id }}').find('#deleting').find('h3').html("Deleting Routers...")
|
|
||||||
|
|
||||||
$.post('/coda/delete/routers/',
|
|
||||||
{csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, user_token: user_token},
|
|
||||||
function(data, status) {
|
|
||||||
var resultsDiv = $('#routers_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Routers</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Outcome</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.map(data, function (outcome, instanceId) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instanceId + "</td>");
|
|
||||||
tr.append("<td>" + outcome + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='2'>");
|
|
||||||
var span = $("<span colspan='2'>");
|
|
||||||
var footerMessage = "Displaying " + Object.keys(data).length + " item";
|
|
||||||
if (Object.keys(data).length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#routers_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Routers in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#routers_{{ region }}_{{ project_id }}').find('#deleting').hide();
|
|
||||||
$('#routers_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
scrub_networks_{{ region|jsfunc }}_{{ project_id }}();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="routers_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="deleting">
|
|
||||||
<h3>Waiting for Security Groups to delete...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,83 +0,0 @@
|
||||||
{% load template_utils %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
function wait_security_groups_{{ region|jsfunc }}_{{ project_id }}(){
|
|
||||||
$('#security_groups_{{ region }}_{{ project_id }}').find('#deleting').find('h3').html("Floating IP's deleted. Waiting a few seconds for ports to clear...")
|
|
||||||
setTimeout(function() { scrub_security_groups_{{ region|jsfunc }}_{{ project_id }}() }, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function scrub_security_groups_{{ region|jsfunc }}_{{ project_id }}(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var user_token = "{{ user_token }}";
|
|
||||||
|
|
||||||
$('#security_groups_{{ region }}_{{ project_id }}').find('#deleting').find('h3').html("Deleting security groups...")
|
|
||||||
|
|
||||||
$.post('/coda/delete/security_groups/',
|
|
||||||
{csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, user_token: user_token},
|
|
||||||
function(data, status) {
|
|
||||||
var resultsDiv = $('#security_groups_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Security Groups</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Outcome</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.map(data, function (outcome, instanceId) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instanceId + "</td>");
|
|
||||||
tr.append("<td>" + outcome + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='2'>");
|
|
||||||
var span = $("<span colspan='2'>");
|
|
||||||
var footerMessage = "Displaying " + Object.keys(data).length + " item";
|
|
||||||
if (Object.keys(data).length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#security_groups_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Security Groups in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#security_groups_{{ region }}_{{ project_id }}').find('#deleting').hide();
|
|
||||||
$('#security_groups_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
scrub_routers_{{ region|jsfunc }}_{{ project_id }}();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="security_groups_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="deleting">
|
|
||||||
<h3>Waiting for Floating IPs to delete...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,79 +0,0 @@
|
||||||
{% load template_utils %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
var snapshots_{{ region|jsfunc }}_{{ project_id }}_done = false;
|
|
||||||
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var user_token = "{{ user_token }}";
|
|
||||||
|
|
||||||
$.post('/coda/delete/snapshots/',
|
|
||||||
{csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, user_token: user_token},
|
|
||||||
function(data, status) {
|
|
||||||
var resultsDiv = $('#snapshots_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Snapshots</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Outcome</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.map(data, function (outcome, instanceId) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instanceId + "</td>");
|
|
||||||
tr.append("<td>" + outcome + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='2'>");
|
|
||||||
var span = $("<span colspan='2'>");
|
|
||||||
var footerMessage = "Displaying " + Object.keys(data).length + " item";
|
|
||||||
if (Object.keys(data).length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#snapshots_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Snapshots in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#snapshots_{{ region }}_{{ project_id }}').find('#deleting').hide();
|
|
||||||
$('#snapshots_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
snapshots_{{ region|jsfunc }}_{{ project_id }}_done = true;
|
|
||||||
scrub_volumes_{{ region|jsfunc }}_{{ project_id }}();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="snapshots_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="deleting">
|
|
||||||
<h3>Deleting Snapshots...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,87 +0,0 @@
|
||||||
{% load template_utils %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
function scrub_volumes_{{ region|jsfunc }}_{{ project_id }}(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var user_token = "{{ user_token }}";
|
|
||||||
|
|
||||||
if (!backups_{{ region|jsfunc }}_{{ project_id }}_done) {
|
|
||||||
$('#volumes_{{ region }}_{{ project_id }}').find('#deleting').find('h3').html("Waiting for Backups to delete...")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!snapshots_{{ region|jsfunc }}_{{ project_id }}_done) {
|
|
||||||
$('#volumes_{{ region }}_{{ project_id }}').find('#deleting').find('h3').html("Waiting for Snapshots to delete...")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#volumes_{{ region }}_{{ project_id }}').find('#deleting').find('h3').html("Deleting Volumes...")
|
|
||||||
|
|
||||||
$.post('/coda/delete/volumes/',
|
|
||||||
{csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, user_token: user_token},
|
|
||||||
function(data, status) {
|
|
||||||
var resultsDiv = $('#volumes_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Volumes</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Outcome</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.map(data, function (outcome, instanceId) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instanceId + "</td>");
|
|
||||||
tr.append("<td>" + outcome + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='2'>");
|
|
||||||
var span = $("<span colspan='2'>");
|
|
||||||
var footerMessage = "Displaying " + Object.keys(data).length + " item";
|
|
||||||
if (Object.keys(data).length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#volumes_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Volumes in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#volumes_{{ region }}_{{ project_id }}').find('#deleting').hide();
|
|
||||||
$('#volumes_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="volumes_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="deleting">
|
|
||||||
<h3>Waiting for Backups and Snapshots to delete...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,11 +0,0 @@
|
||||||
{% extends "coda/coda/coda_base.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Error{% endblock %}
|
|
||||||
|
|
||||||
{% block results %}
|
|
||||||
<div>
|
|
||||||
<h1 style="color: red; text-align: center">Error!</h1>
|
|
||||||
<h2 style="color: red; text-align: center">{{ error_message }}</h2>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,65 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var update_cache = "{{ update_cache }}";
|
|
||||||
|
|
||||||
$.post('/coda/floating_ips/', {csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, update_cache: update_cache}, function(data, status){
|
|
||||||
var tbody = $('#floatingips_{{ region }}_{{ project_id }}').find('tbody');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(data.length > 0) {
|
|
||||||
$.each(data, function (i, floatingip) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + floatingip.id + "</td>");
|
|
||||||
tr.append("<td>" + floatingip.floating_ip_address + "</td>");
|
|
||||||
tr.append("<td>" + floatingip.fixed_ip_address + "</td>");
|
|
||||||
tr.append("<td>" + floatingip.port_id + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var footerMessage = "Displaying " + data.length + " item";
|
|
||||||
if(data.length > 1)
|
|
||||||
footerMessage+="s";
|
|
||||||
|
|
||||||
$('#floatingips_{{ region }}_{{ project_id }}').find('span').text(footerMessage);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#floatingips_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Floating IPs in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#floatingips_{{ region }}_{{ project_id }}').find('#querying').hide();
|
|
||||||
$('#floatingips_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="floatingips_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="querying">
|
|
||||||
<h3>Querying floating IPs for region: {{ region }}...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
<h3 class="table_title">Floating IPs</h3>
|
|
||||||
<table class="table table-bordered datatable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="normal_column">UUID</th>
|
|
||||||
<th class="normal_column">Floating Address</th>
|
|
||||||
<th class="normal_column">Fixed Address</th>
|
|
||||||
<th class="normal_column">Port ID</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="4">
|
|
||||||
<span class="table_count"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,64 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var update_cache = "{{ update_cache }}";
|
|
||||||
|
|
||||||
$.post('/coda/images/', {csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, update_cache: update_cache}, function(data, status){
|
|
||||||
var tbody = $('#images_{{ region }}_{{ project_id }}').find('tbody');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(data.length > 0) {
|
|
||||||
$.each(data, function (i, image) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + image.id + "</td>");
|
|
||||||
tr.append("<td>" + image.name + "</td>");
|
|
||||||
tr.append("<td>" + image.status + "</td>");
|
|
||||||
tr.append("<td>" + image.created_at + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
var footerMessage = "Displaying " + data.length + " item";
|
|
||||||
if (data.length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
$('#images_{{ region }}_{{ project_id }}').find('span').text(footerMessage);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#images_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Images in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#images_{{ region }}_{{ project_id }}').find('#querying').hide();
|
|
||||||
$('#images_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="images_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="querying">
|
|
||||||
<h3>Querying Images for region: {{ region }}...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
<h3 class="table_title">Images</h3>
|
|
||||||
<table class="table table-bordered datatable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="normal_column">UUID</th>
|
|
||||||
<th class="normal_column">Name</th>
|
|
||||||
<th class="normal_column">Status</th>
|
|
||||||
<th class="normal_column">Created</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="4">
|
|
||||||
<span class="table_count"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,4 +0,0 @@
|
||||||
{% extends "coda/coda/coda_base.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var update_cache = "{{ update_cache }}";
|
|
||||||
|
|
||||||
$.post('/coda/instances/', {csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, update_cache: update_cache}, function(data, status) {
|
|
||||||
var resultsDiv = $('#instances_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(Object.keys(data).length > 0) {
|
|
||||||
$.map(data, function (instancesList, userID) {
|
|
||||||
var tableWrapper = $("<div>").addClass("table_wrapper");
|
|
||||||
tableWrapper.append("<h3 class=\"table_title\">Instances for User ID: " + userID + "</h3>");
|
|
||||||
var table = $("<table>");
|
|
||||||
table.addClass("table")
|
|
||||||
table.addClass("table-bordered")
|
|
||||||
table.addClass("datatable")
|
|
||||||
|
|
||||||
var thead = $("<thead>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Name</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Flavor</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Status</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Task</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Power</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Hypervisor</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Image Id</th>").addClass("normal_column"));
|
|
||||||
tr.append($("<th>Image Name</th>").addClass("normal_column"));
|
|
||||||
thead.append(tr);
|
|
||||||
table.append(thead);
|
|
||||||
|
|
||||||
var tbody = $("<tbody>");
|
|
||||||
|
|
||||||
$.each(instancesList, function (i, instance) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + instance.id + "</td>");
|
|
||||||
tr.append("<td>" + instance.name + "</td>");
|
|
||||||
tr.append("<td>" + instance.flavor.id + "</td>");
|
|
||||||
tr.append("<td>" + instance.status + "</td>");
|
|
||||||
tr.append("<td>" + instance["OS-EXT-STS:task_state"] + "</td>");
|
|
||||||
tr.append("<td>" + instance["OS-EXT-STS:power_state"] + "</td>");
|
|
||||||
tr.append("<td>" + instance["OS-EXT-SRV-ATTR:hypervisor_hostname"] + "</td>");
|
|
||||||
tr.append("<td>" + instance.image.id + "</td>");
|
|
||||||
tr.append("<td>" + instance.image.name + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
table.append(tbody);
|
|
||||||
|
|
||||||
var tfoot = $("<tfoot>");
|
|
||||||
var tr = $("<tr>");
|
|
||||||
var td = $("<td colspan='9'>");
|
|
||||||
var span = $("<span colspan='9'>");
|
|
||||||
var footerMessage = "Displaying " + instancesList.length + " item";
|
|
||||||
if (instancesList.length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
span.append(footerMessage);
|
|
||||||
td.append(span);
|
|
||||||
tr.append(td);
|
|
||||||
tfoot.append(tr);
|
|
||||||
table.append(tfoot);
|
|
||||||
|
|
||||||
tableWrapper.append(table);
|
|
||||||
resultsDiv.append(tableWrapper);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#instances_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Instances in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#instances_{{ region }}_{{ project_id }}').find('#querying').hide();
|
|
||||||
$('#instances_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="instances_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="querying">
|
|
||||||
<h3>Querying instances for region: {{ region }}...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,62 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var update_cache = "{{ update_cache }}";
|
|
||||||
|
|
||||||
$.post('/coda/networks/', {csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, update_cache: update_cache}, function(data, status){
|
|
||||||
var tbody = $('#networks_{{ region }}_{{ project_id }}').find('tbody');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(data.length > 0) {
|
|
||||||
$.each(data, function (i, network) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + network.id + "</td>");
|
|
||||||
tr.append("<td>" + network.name + "</td>");
|
|
||||||
tr.append("<td>" + network.status + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
var footerMessage = "Displaying " + data.length + " item";
|
|
||||||
if (data.length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
$('#networks_{{ region }}_{{ project_id }}').find('span').text(footerMessage);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#networks_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Networks in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#networks_{{ region }}_{{ project_id }}').find('#querying').hide();
|
|
||||||
$('#networks_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="networks_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="querying">
|
|
||||||
<h3>Querying networks for region: {{ region }}...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
<h3 class="table_title">Networks</h3>
|
|
||||||
<table class="table table-bordered datatable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="normal_column">UUID</th>
|
|
||||||
<th class="normal_column">Name</th>
|
|
||||||
<th class="normal_column">Status</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="3">
|
|
||||||
<span class="table_count"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,11 +0,0 @@
|
||||||
{% extends "coda/coda/coda_base.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}No Project Found{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block results %}
|
|
||||||
<div>
|
|
||||||
<h2 style="text-align: center">No records found that match Project ID {{ project_id }}.</h2>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,54 +0,0 @@
|
||||||
{% extends "coda/coda/coda_base.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block results %}
|
|
||||||
<div id="main_content">
|
|
||||||
<div class="sidebar">
|
|
||||||
<h2>Project Info</h2>
|
|
||||||
<form id="coda_form" action="{% url 'horizon:coda:coda:confirm_delete' %}" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<p>Project Name: {{ project_info.tenant.name }}</p>
|
|
||||||
<p>Project ID: {{ project_info.tenant.id}}</p>
|
|
||||||
<p>Enabled: {{ project_info.tenant.enabled }}</p>
|
|
||||||
<p>Description: {{ project_info.tenant.description}}</p>
|
|
||||||
<input type="hidden" name="project_id" value="{{ project_id }}">
|
|
||||||
{% if users %}
|
|
||||||
<h4>Users:</h4>
|
|
||||||
{% for user in users %}
|
|
||||||
<p>Name: {{ user.name }}</p>
|
|
||||||
<p>Username: {{ user.username }}</p>
|
|
||||||
<p>ID: {{ user.id }}</p>
|
|
||||||
<p>Enabled: {{ user.enabled }}</p>
|
|
||||||
<p>E-Mail: {{ user.email }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<h4>No Users in this Project</h4>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div style="text-align: right; margin-right: 14px; margin-bottom: 10px;">
|
|
||||||
<a href="{% url 'horizon:coda:coda:index' %}">
|
|
||||||
<input class="btn" type="button" value="Cancel" />
|
|
||||||
</a>
|
|
||||||
<input class="btn btn-primary" type="submit" value="Delete Resources">
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='content_body'>
|
|
||||||
<div class="tenant-header">
|
|
||||||
<h1>Resources for {{ project_id }}</h1>
|
|
||||||
</div>
|
|
||||||
{% for region in regions %}
|
|
||||||
<h2>Region: {{ region }}</h2>
|
|
||||||
{% include "coda/coda/instances.html" %}
|
|
||||||
{% include "coda/coda/floating_ips.html" %}
|
|
||||||
{% include "coda/coda/security_groups.html" %}
|
|
||||||
{% include "coda/coda/networks.html" %}
|
|
||||||
{% include "coda/coda/subnets.html" %}
|
|
||||||
{% include "coda/coda/routers.html" %}
|
|
||||||
{% include "coda/coda/volumes.html" %}
|
|
||||||
{% include "coda/coda/images.html" %}
|
|
||||||
{% endfor %} <!-- END region for loop -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,68 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var update_cache = "{{ update_cache }}";
|
|
||||||
|
|
||||||
$.post('/coda/routers/', {csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, update_cache: update_cache}, function(data, status){
|
|
||||||
var tbody = $('#routers_{{ region }}_{{ project_id }}').find('tbody');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(data.length > 0) {
|
|
||||||
$.each(data, function (i, router) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + router.id + "</td>");
|
|
||||||
tr.append("<td>" + router.name + "</td>");
|
|
||||||
tr.append("<td>" + router.status + "</td>");
|
|
||||||
if (router.external_gateway_info != null)
|
|
||||||
tr.append("<td>" + router.external_gateway_info.network_id + "</td>");
|
|
||||||
else
|
|
||||||
tr.append("<td>null</td>");
|
|
||||||
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
var footerMessage = "Displaying " + data.length + " item";
|
|
||||||
if (data.length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
$('#routers_{{ region }}_{{ project_id }}').find('span').text(footerMessage);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#routers_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Routers in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#routers_{{ region }}_{{ project_id }}').find('#querying').hide();
|
|
||||||
$('#routers_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="routers_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="querying">
|
|
||||||
<h3>Querying Routers for region: {{ region }}...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
<h3 class="table_title">Routers</h3>
|
|
||||||
<table class="table table-bordered datatable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="normal_column">UUID</th>
|
|
||||||
<th class="normal_column">Name</th>
|
|
||||||
<th class="normal_column">Status</th>
|
|
||||||
<th class="normal_column">Gateway</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="4">
|
|
||||||
<span class="table_count"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,95 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var update_cache = "{{ update_cache }}";
|
|
||||||
|
|
||||||
$.post('/coda/security_groups/', {csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, update_cache: update_cache}, function(data, status){
|
|
||||||
var tbody = $('#securitygroups_{{ region }}_{{ project_id }}').find('tbody');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(data.length > 0) {
|
|
||||||
$.each(data, function (i, secgroup) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
var rulesBody = $("<tbody>");
|
|
||||||
tr.append("<td>" + secgroup.name + "</td>");
|
|
||||||
tr.append("<td>" + secgroup.description + "</td>");
|
|
||||||
tr.append("<td>" + secgroup.id + "</td>");
|
|
||||||
|
|
||||||
$.each(secgroup.security_group_rules, function (i, rule) {
|
|
||||||
var rulesRow = $("<tr>");
|
|
||||||
rulesRow.append("<td>" + rule.id + "</td>");
|
|
||||||
rulesRow.append("<td>" + rule.direction + "</td>");
|
|
||||||
rulesRow.append("<td>" + rule.protocol + "</td>");
|
|
||||||
rulesRow.append("<td>" + rule.port_range_min + "</td>");
|
|
||||||
rulesRow.append("<td>" + rule.port_range_max + "</td>");
|
|
||||||
rulesRow.append("<td>" + rule.remote_ip_prefix + "</td>");
|
|
||||||
rulesBody.append(rulesRow);
|
|
||||||
});
|
|
||||||
|
|
||||||
var ruleTable = $("<table>");
|
|
||||||
var ruleHeaderRow = $("<tr>");
|
|
||||||
ruleTable.addClass("table")
|
|
||||||
ruleTable.addClass("table-bordered")
|
|
||||||
ruleTable.addClass("datatable")
|
|
||||||
|
|
||||||
ruleHeaderRow.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
ruleHeaderRow.append($("<th>Direction</th>").addClass("normal_column"));
|
|
||||||
ruleHeaderRow.append($("<th>Protocol</th>").addClass("normal_column"));
|
|
||||||
ruleHeaderRow.append($("<th>Min Port</th>").addClass("normal_column"));
|
|
||||||
ruleHeaderRow.append($("<th>Max Port</th>").addClass("normal_column"));
|
|
||||||
ruleHeaderRow.append($("<th>CIDR</th>").addClass("normal_column"));
|
|
||||||
|
|
||||||
ruleTable.append($("<thead>").append(ruleHeaderRow));
|
|
||||||
ruleTable.append(rulesBody);
|
|
||||||
ruleTable.append($("<tfoot>").append($("<tr>").append($("<td colspan='6'>"))));
|
|
||||||
|
|
||||||
tr.append($("<td>").append(ruleTable));
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
var footerMessage = "Displaying " + data.length + " item";
|
|
||||||
if (data.length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
$('#securitygroups_{{ region }}_{{ project_id }}').find('span').text(footerMessage);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#securitygroups_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Security Groups in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#securitygroups_{{ region }}_{{ project_id }}').find('#querying').hide();
|
|
||||||
$('#securitygroups_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="securitygroups_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="querying">
|
|
||||||
<h3>Querying Security Groups for region: {{ region }}...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
<h3 class="table_title">Security Groups</h3>
|
|
||||||
<table class="table table-bordered datatable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="normal_column">Name</th>
|
|
||||||
<th class="normal_column">Description</th>
|
|
||||||
<th class="normal_column">UUID</th>
|
|
||||||
<th class="normal_column">Rules</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="4">
|
|
||||||
<span class="table_count"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,62 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var update_cache = "{{ update_cache }}";
|
|
||||||
|
|
||||||
$.post('/coda/subnets/', {csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, update_cache: update_cache}, function(data, status){
|
|
||||||
var tbody = $('#subnets_{{ region }}_{{ project_id }}').find('tbody');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(data.length > 0) {
|
|
||||||
$.each(data, function (i, subnet) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
tr.append("<td>" + subnet.id + "</td>");
|
|
||||||
tr.append("<td>" + subnet.name + "</td>");
|
|
||||||
tr.append("<td>" + subnet.cidr + "</td>");
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
var footerMessage = "Displaying " + data.length + " item";
|
|
||||||
if (data.length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
$('#subnets_{{ region }}_{{ project_id }}').find('span').text(footerMessage);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#subnets_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Subnets in region.</h4>")
|
|
||||||
}
|
|
||||||
$('#subnets_{{ region }}_{{ project_id }}').find('#querying').hide();
|
|
||||||
$('#subnets_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="subnets_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="querying">
|
|
||||||
<h3>Querying Subnets for region: {{ region }}...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
<h3 class="table_title">Subnets</h3>
|
|
||||||
<table class="table table-bordered datatable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="normal_column">UUID</th>
|
|
||||||
<th class="normal_column">Name</th>
|
|
||||||
<th class="normal_column">CIDR</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="3">
|
|
||||||
<span class="table_count"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,146 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
var csrftoken = Cookies.get('csrftoken');
|
|
||||||
var project_id = "{{ project_id }}";
|
|
||||||
var region = "{{ region }}";
|
|
||||||
var update_cache = "{{ update_cache }}";
|
|
||||||
|
|
||||||
$.post('/coda/volumes/', {csrfmiddlewaretoken: csrftoken, project_id: project_id, region: region, update_cache: update_cache}, function(data, status){
|
|
||||||
var tbody = $('#volumes_{{ region }}_{{ project_id }}').find('tbody');
|
|
||||||
data = JSON.parse(data);
|
|
||||||
|
|
||||||
if(data.length > 0) {
|
|
||||||
$.each(data, function (i, volume) {
|
|
||||||
var tr = $("<tr>");
|
|
||||||
|
|
||||||
tr.append("<td>" + volume.id + "</td>");
|
|
||||||
tr.append("<td>" + volume.display_name + "</td>");
|
|
||||||
tr.append("<td>" + volume.display_description + "</td>");
|
|
||||||
tr.append("<td>" + volume.created_at + "</td>");
|
|
||||||
tr.append("<td>" + volume.status + "</td>");
|
|
||||||
tr.append("<td>" + volume.size + "</td>");
|
|
||||||
tr.append("<td>" + volume.availability_zone + "</td>");
|
|
||||||
|
|
||||||
if (volume.snapshots.length > 0) {
|
|
||||||
var snapshotsBody = $("<tbody>");
|
|
||||||
|
|
||||||
$.each(volume.snapshots, function (i, snapshot) {
|
|
||||||
var snapshotsRow = $("<tr>");
|
|
||||||
snapshotsRow.append("<td>" + snapshot.id + "</td>");
|
|
||||||
snapshotsRow.append("<td>" + snapshot.display_name + "</td>");
|
|
||||||
snapshotsRow.append("<td>" + snapshot.display_description + "</td>");
|
|
||||||
snapshotsRow.append("<td>" + snapshot.created_at + "</td>");
|
|
||||||
snapshotsRow.append("<td>" + snapshot.status + "</td>");
|
|
||||||
snapshotsRow.append("<td>" + snapshot.size + "</td>");
|
|
||||||
snapshotsBody.append(snapshotsRow);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var snapshotTable = $("<table>");
|
|
||||||
var snapshotHeaderRow = $("<tr>");
|
|
||||||
snapshotTable.addClass("table");
|
|
||||||
snapshotTable.addClass("table-bordered");
|
|
||||||
snapshotTable.addClass("datatable");
|
|
||||||
|
|
||||||
snapshotHeaderRow.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
snapshotHeaderRow.append($("<th>Name</th>").addClass("normal_column"));
|
|
||||||
snapshotHeaderRow.append($("<th>Description</th>").addClass("normal_column"));
|
|
||||||
snapshotHeaderRow.append($("<th>Created</th>").addClass("normal_column"));
|
|
||||||
snapshotHeaderRow.append($("<th>Status</th>").addClass("normal_column"));
|
|
||||||
snapshotHeaderRow.append($("<th>Size</th>").addClass("normal_column"));
|
|
||||||
|
|
||||||
snapshotTable.append($("<thead>").append(snapshotHeaderRow));
|
|
||||||
snapshotTable.append(snapshotsBody);
|
|
||||||
snapshotTable.append($("<tfoot>").append($("<tr>").append($("<td colspan='6'>"))));
|
|
||||||
|
|
||||||
tr.append($("<td>").append(snapshotTable));
|
|
||||||
} else {
|
|
||||||
tr.append($("<td>").append($("<h4>No Snapshots</h4>")));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (volume.backups.length > 0) {
|
|
||||||
var backupsBody = $("<tbody>");
|
|
||||||
|
|
||||||
$.each(volume.backups, function (i, backup) {
|
|
||||||
var backupRow = $("<tr>");
|
|
||||||
backupRow.append("<td>" + backup.id + "</td>");
|
|
||||||
backupRow.append("<td>" + backup.display_name + "</td>");
|
|
||||||
backupRow.append("<td>" + backup.display_description + "</td>");
|
|
||||||
backupRow.append("<td>" + backup.created_at + "</td>");
|
|
||||||
backupRow.append("<td>" + backup.status + "</td>");
|
|
||||||
backupRow.append("<td>" + backup.size + "</td>");
|
|
||||||
backupsBody.append(backupRow);
|
|
||||||
});
|
|
||||||
|
|
||||||
var backupTable = $("<table>");
|
|
||||||
var backupHeaderRow = $("<tr>");
|
|
||||||
backupTable.addClass("table");
|
|
||||||
backupTable.addClass("table-bordered");
|
|
||||||
backupTable.addClass("datatable");
|
|
||||||
|
|
||||||
backupHeaderRow.append($("<th>UUID</th>").addClass("normal_column"));
|
|
||||||
backupHeaderRow.append($("<th>Name</th>").addClass("normal_column"));
|
|
||||||
backupHeaderRow.append($("<th>Description</th>").addClass("normal_column"));
|
|
||||||
backupHeaderRow.append($("<th>Created</th>").addClass("normal_column"));
|
|
||||||
backupHeaderRow.append($("<th>Status</th>").addClass("normal_column"));
|
|
||||||
backupHeaderRow.append($("<th>Size</th>").addClass("normal_column"));
|
|
||||||
|
|
||||||
backupTable.append($("<thead>").append(backupHeaderRow));
|
|
||||||
backupTable.append(backupsBody);
|
|
||||||
backupTable.append($("<tfoot>").append($("<tr>").append($("<td colspan='6'>"))));
|
|
||||||
|
|
||||||
tr.append($("<td>").append(backupTable));
|
|
||||||
} else {
|
|
||||||
tr.append($("<td>").append($("<h4>No Backups</h4>")));
|
|
||||||
}
|
|
||||||
tbody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
var footerMessage = "Displaying " + data.length + " item";
|
|
||||||
if (data.length > 1)
|
|
||||||
footerMessage += "s";
|
|
||||||
|
|
||||||
$('#volumes_{{ region }}_{{ project_id }}').find('span').text(footerMessage);
|
|
||||||
} else {
|
|
||||||
var resultsDiv = $('#volumes_{{ region }}_{{ project_id }}').find('#results');
|
|
||||||
resultsDiv.html("<h4>No Volumes in region.</h4>");
|
|
||||||
}
|
|
||||||
$('#volumes_{{ region }}_{{ project_id }}').find('#querying').hide();
|
|
||||||
$('#volumes_{{ region }}_{{ project_id }}').find('#results').show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="volumes_{{ region }}_{{ project_id }}" class="table_wrapper">
|
|
||||||
<div id="querying">
|
|
||||||
<h3>Querying Volumes for region: {{ region }}...</h3>
|
|
||||||
</div>
|
|
||||||
<div id="results" style="display: none">
|
|
||||||
<h3 class="table_title">Volumes</h3>
|
|
||||||
<table class="table table-bordered datatable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="normal_column">UUID</th>
|
|
||||||
<th class="normal_column">Name</th>
|
|
||||||
<th class="normal_column">Description</th>
|
|
||||||
<th class="normal_column">Created</th>
|
|
||||||
<th class="normal_column">Status</th>
|
|
||||||
<th class="normal_column">Size</th>
|
|
||||||
<th class="normal_column">Zone</th>
|
|
||||||
<th class="normal_column">Snapshots</th>
|
|
||||||
<th class="normal_column">Backups</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="9">
|
|
||||||
<span class="table_count"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,30 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Tests go here.
|
|
||||||
|
|
||||||
Not much else to say.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from horizon.test import helpers as test
|
|
||||||
|
|
||||||
|
|
||||||
class CodaTests(test.TestCase):
|
|
||||||
"""Moar tests."""
|
|
||||||
|
|
||||||
def test_me(self):
|
|
||||||
"""Test me."""
|
|
||||||
self.assertTrue(1 + 1 == 2)
|
|
58
coda/urls.py
58
coda/urls.py
|
@ -1,58 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Url patterns for Coda.
|
|
||||||
|
|
||||||
Not much else to say.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from django.conf.urls import patterns
|
|
||||||
from django.conf.urls import url
|
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.coda.coda import views
|
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns(
|
|
||||||
'',
|
|
||||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
|
||||||
url(r'^results/$', views.results, name='results'),
|
|
||||||
url(r'^instances/$', views.instances, name='instances'),
|
|
||||||
url(r'^floating_ips/$', views.floating_ips, name='floating_ips'),
|
|
||||||
url(r'^security_groups/$', views.security_groups, name='security_groups'),
|
|
||||||
url(r'^networks/$', views.networks, name='networks'),
|
|
||||||
url(r'^subnets/$', views.subnets, name='subnets'),
|
|
||||||
url(r'^routers/$', views.routers, name='routers'),
|
|
||||||
url(r'^volumes/$', views.volumes, name='volumes'),
|
|
||||||
url(r'^images/$', views.images, name='images'),
|
|
||||||
url(r'^confirm_delete/$', views.confirm_delete, name='confirm_delete'),
|
|
||||||
url(r'^delete/results/$', views.delete_resources, name='delete_resources'),
|
|
||||||
url(r'^delete/instances/$',
|
|
||||||
views.delete_instances,
|
|
||||||
name='delete_instances'),
|
|
||||||
url(r'^delete/floating_ips/$',
|
|
||||||
views.delete_floating_ips,
|
|
||||||
name='delete_floating_ips'),
|
|
||||||
url(r'^delete/security_groups/$',
|
|
||||||
views.delete_security_groups,
|
|
||||||
name='delete_security_groups'),
|
|
||||||
url(r'^delete/networks/$', views.delete_networks, name='delete_networks'),
|
|
||||||
url(r'^delete/routers/$', views.delete_routers, name='delete_routers'),
|
|
||||||
url(r'^delete/snapshots/$', views.delete_snapshots,
|
|
||||||
name='delete_snapshots'),
|
|
||||||
url(r'^delete/backups/$', views.delete_backups, name='delete_backups'),
|
|
||||||
url(r'^delete/volumes/$', views.delete_volumes, name='delete_volumes'),
|
|
||||||
url(r'^delete/images/$', views.delete_images, name='delete_images'),
|
|
||||||
)
|
|
574
coda/views.py
574
coda/views.py
|
@ -1,574 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
The Coda views.
|
|
||||||
|
|
||||||
Not much else to say right now.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from django.core.cache import cache
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.shortcuts import render
|
|
||||||
# from django.conf import settings
|
|
||||||
from horizon import views
|
|
||||||
import json
|
|
||||||
from openstack_dashboard.dashboards.coda.coda import cinder
|
|
||||||
from openstack_dashboard.dashboards.coda.coda import coda
|
|
||||||
from openstack_dashboard.dashboards.coda.coda import glance
|
|
||||||
from openstack_dashboard.dashboards.coda.coda import keystone
|
|
||||||
from openstack_dashboard.dashboards.coda.coda import neutron
|
|
||||||
from openstack_dashboard.dashboards.coda.coda import nova
|
|
||||||
|
|
||||||
DISPATCH_MAP = {
|
|
||||||
'instances': nova.list_instances,
|
|
||||||
'floating_ips': neutron.list_floating_ips,
|
|
||||||
'security_groups': neutron.list_security_groups,
|
|
||||||
'networks': neutron.list_networks,
|
|
||||||
'subnets': neutron.list_subnets,
|
|
||||||
'routers': neutron.list_routers,
|
|
||||||
'volumes': cinder.list_volumes,
|
|
||||||
'snapshots': cinder.list_snapshots,
|
|
||||||
'backups': cinder.list_backups,
|
|
||||||
'images': glance.list_images
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class IndexView(views.APIView):
|
|
||||||
"""Class based definition of the index view."""
|
|
||||||
|
|
||||||
template_name = 'coda/coda/index.html'
|
|
||||||
|
|
||||||
def get_data(self, request, context, *args, **kwargs):
|
|
||||||
"""No context needed."""
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
def results(request):
|
|
||||||
"""The results view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
update_cache = request.POST.get('update_cache', 'False')
|
|
||||||
|
|
||||||
auth_token = coda.get_auth_token()
|
|
||||||
|
|
||||||
if auth_token == 'error':
|
|
||||||
msg = "Coda User failed to authenticate with the Identity Service."
|
|
||||||
context = {
|
|
||||||
'project_id': project_id,
|
|
||||||
'error_message': msg
|
|
||||||
}
|
|
||||||
return render(request, 'coda/coda/error.html', context)
|
|
||||||
|
|
||||||
project_exists, project_info = keystone.project_exists(
|
|
||||||
auth_token,
|
|
||||||
project_id)
|
|
||||||
|
|
||||||
if project_exists:
|
|
||||||
users = keystone.get_project_users(auth_token, project_id)
|
|
||||||
regions = coda.get_coda_regions()
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'project_id': project_id,
|
|
||||||
'project_info': project_info,
|
|
||||||
'users': users,
|
|
||||||
'regions': regions,
|
|
||||||
'update_cache': update_cache,
|
|
||||||
}
|
|
||||||
|
|
||||||
return render(request, 'coda/coda/results.html', context)
|
|
||||||
else:
|
|
||||||
context = {
|
|
||||||
'project_id': project_id
|
|
||||||
}
|
|
||||||
return render(request, 'coda/coda/no_project.html', context)
|
|
||||||
|
|
||||||
|
|
||||||
def instances(request):
|
|
||||||
"""The instances view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
region = request.POST['region']
|
|
||||||
update_cache = request.POST.get('update_cache', 'True')
|
|
||||||
|
|
||||||
instances_dict = get_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'instances',
|
|
||||||
update_cache)
|
|
||||||
|
|
||||||
# todo (nathan) fix this later broken during port from hp pub cloud
|
|
||||||
# images_key = region + '_coda_images'
|
|
||||||
# coda_images = cache.get(images_key)
|
|
||||||
coda_images = None
|
|
||||||
|
|
||||||
if coda_images is not None:
|
|
||||||
image_list = []
|
|
||||||
|
|
||||||
if 'public' in coda_images:
|
|
||||||
image_list.extend(coda_images['public'])
|
|
||||||
|
|
||||||
if project_id in coda_images:
|
|
||||||
image_list.extend(coda_images[project_id])
|
|
||||||
|
|
||||||
coda.fill_image_info(instances_dict, image_list)
|
|
||||||
else:
|
|
||||||
coda.fill_image_info(instances_dict, None)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(instances_dict))
|
|
||||||
|
|
||||||
|
|
||||||
def floating_ips(request):
|
|
||||||
"""The floating ips view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
region = request.POST['region']
|
|
||||||
update_cache = request.POST['update_cache']
|
|
||||||
floating_ips_dict = get_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'floating_ips',
|
|
||||||
update_cache)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(floating_ips_dict))
|
|
||||||
|
|
||||||
|
|
||||||
def security_groups(request):
|
|
||||||
"""The security groups view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
region = request.POST['region']
|
|
||||||
update_cache = request.POST['update_cache']
|
|
||||||
|
|
||||||
security_groups_dict = get_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'security_groups',
|
|
||||||
update_cache)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(security_groups_dict))
|
|
||||||
|
|
||||||
|
|
||||||
def networks(request):
|
|
||||||
"""The networks view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
region = request.POST['region']
|
|
||||||
update_cache = request.POST['update_cache']
|
|
||||||
networks_dict = get_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'networks',
|
|
||||||
update_cache)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(networks_dict))
|
|
||||||
|
|
||||||
|
|
||||||
def subnets(request):
|
|
||||||
"""The subnets view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
region = request.POST['region']
|
|
||||||
update_cache = request.POST['update_cache']
|
|
||||||
subnets_dict = get_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'subnets',
|
|
||||||
update_cache)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(subnets_dict))
|
|
||||||
|
|
||||||
|
|
||||||
def routers(request):
|
|
||||||
"""The routers view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
region = request.POST['region']
|
|
||||||
update_cache = request.POST['update_cache']
|
|
||||||
routers_dict = get_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'routers',
|
|
||||||
update_cache)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(routers_dict))
|
|
||||||
|
|
||||||
|
|
||||||
def volumes(request):
|
|
||||||
"""The volumes view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
region = request.POST['region']
|
|
||||||
update_cache = request.POST['update_cache']
|
|
||||||
volumes_dict = get_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'volumes',
|
|
||||||
update_cache)
|
|
||||||
snapshots_dict = get_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'snapshots',
|
|
||||||
update_cache)
|
|
||||||
backups_dict = get_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'backups',
|
|
||||||
update_cache)
|
|
||||||
|
|
||||||
volumes_dict = coda.fill_volume_info(
|
|
||||||
volumes_dict,
|
|
||||||
snapshots_dict,
|
|
||||||
backups_dict)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(volumes_dict))
|
|
||||||
|
|
||||||
|
|
||||||
def images(request):
|
|
||||||
"""The images view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
region = request.POST['region']
|
|
||||||
update_cache = request.POST['update_cache']
|
|
||||||
|
|
||||||
images_dict = None
|
|
||||||
images_key = region + '_' + project_id + '_images'
|
|
||||||
project_images = cache.get(images_key)
|
|
||||||
|
|
||||||
if update_cache == 'True':
|
|
||||||
images_dict = get_all_images(region, True)
|
|
||||||
elif project_images is None:
|
|
||||||
images_dict = get_all_images(region, False)
|
|
||||||
|
|
||||||
if images_dict is not None:
|
|
||||||
if project_id in images_dict:
|
|
||||||
project_images = images_dict[project_id]
|
|
||||||
else:
|
|
||||||
project_images = {}
|
|
||||||
cache.set(images_key, project_images, 600)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(project_images))
|
|
||||||
|
|
||||||
|
|
||||||
def get_all_images(region, reload_cache=False):
|
|
||||||
"""Utility method, might belong elsewhere."""
|
|
||||||
images_key = region + '_coda_images'
|
|
||||||
coda_images = cache.get(images_key)
|
|
||||||
|
|
||||||
if reload_cache is True or coda_images is None or len(coda_images) == 0:
|
|
||||||
auth_token = coda.get_auth_token()
|
|
||||||
images_dict = glance.list_all_images(auth_token, region)
|
|
||||||
coda_images = images_dict
|
|
||||||
cache.set(images_key, coda_images, 3600)
|
|
||||||
|
|
||||||
return coda_images
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_delete(request):
|
|
||||||
"""The confirm delete view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
auth_token = coda.get_auth_token()
|
|
||||||
|
|
||||||
project_exists, project_info = keystone.project_exists(
|
|
||||||
auth_token,
|
|
||||||
project_id)
|
|
||||||
users = keystone.get_project_users(auth_token, project_id)
|
|
||||||
regions = coda.get_coda_regions()
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'project_id': project_id,
|
|
||||||
'project_info': project_info,
|
|
||||||
'users': users,
|
|
||||||
'regions': regions,
|
|
||||||
}
|
|
||||||
|
|
||||||
return render(request, 'coda/coda/confirm_delete.html', context)
|
|
||||||
|
|
||||||
|
|
||||||
def delete_resources(request):
|
|
||||||
"""The deleting resources view."""
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
os_tenant_id = request.POST['os_tenant_id']
|
|
||||||
os_username = request.POST['os_username']
|
|
||||||
os_password = request.POST['os_password']
|
|
||||||
|
|
||||||
user_token = keystone.user_authenticate(
|
|
||||||
os_tenant_id,
|
|
||||||
os_username,
|
|
||||||
os_password)
|
|
||||||
project_exists, project_info = keystone.project_exists(
|
|
||||||
user_token,
|
|
||||||
project_id)
|
|
||||||
users = keystone.get_project_users(user_token, project_id)
|
|
||||||
regions = coda.get_coda_regions()
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'project_id': project_id,
|
|
||||||
'project_info': project_info,
|
|
||||||
'users': users,
|
|
||||||
'regions': regions,
|
|
||||||
'user_token': user_token
|
|
||||||
}
|
|
||||||
|
|
||||||
return render(request, 'coda/coda/delete/results.html', context)
|
|
||||||
|
|
||||||
|
|
||||||
def delete_instances(request):
|
|
||||||
"""The deleting instances view."""
|
|
||||||
result = {}
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
user_token = request.POST['user_token']
|
|
||||||
region = request.POST['region']
|
|
||||||
|
|
||||||
instance_dict = remove_project_resource(region, project_id, 'instances')
|
|
||||||
|
|
||||||
if instance_dict is not None:
|
|
||||||
for user_id, instance_list in instance_dict.iteritems():
|
|
||||||
for instance in instance_list:
|
|
||||||
result[instance['id']] = nova.delete_instance(
|
|
||||||
user_token,
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
instance['id'])
|
|
||||||
else:
|
|
||||||
result = 'ERROR'
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_floating_ips(request):
|
|
||||||
"""The deleting floating ips view."""
|
|
||||||
result = {}
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
user_token = request.POST['user_token']
|
|
||||||
region = request.POST['region']
|
|
||||||
|
|
||||||
floating_ips_dict = remove_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'floating_ips')
|
|
||||||
|
|
||||||
if floating_ips_dict is not None:
|
|
||||||
for floating_ip in floating_ips_dict:
|
|
||||||
result[floating_ip['id']] = neutron.delete_floating_ip(
|
|
||||||
user_token,
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
floating_ip['id'])
|
|
||||||
else:
|
|
||||||
result = 'ERROR'
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_security_groups(request):
|
|
||||||
"""The deleting security groups view."""
|
|
||||||
result = {}
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
user_token = request.POST['user_token']
|
|
||||||
region = request.POST['region']
|
|
||||||
|
|
||||||
security_groups_dict = remove_project_resource(
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
'security_groups')
|
|
||||||
|
|
||||||
if security_groups_dict is not None:
|
|
||||||
for sec_group in security_groups_dict:
|
|
||||||
result[sec_group['id']] = neutron.delete_security_group(
|
|
||||||
user_token,
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
sec_group['id'])
|
|
||||||
else:
|
|
||||||
result = 'ERROR'
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_networks(request):
|
|
||||||
"""The deleting networks view."""
|
|
||||||
result = {}
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
user_token = request.POST['user_token']
|
|
||||||
region = request.POST['region']
|
|
||||||
|
|
||||||
networks_dict = remove_project_resource(region, project_id, 'networks')
|
|
||||||
remove_project_resource(region, project_id, 'subnets')
|
|
||||||
|
|
||||||
if networks_dict is not None:
|
|
||||||
for network in networks_dict:
|
|
||||||
result[network['id']] = neutron.delete_network(
|
|
||||||
user_token,
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
network['id'])
|
|
||||||
else:
|
|
||||||
result = 'ERROR'
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_routers(request):
|
|
||||||
"""The deleting routers view."""
|
|
||||||
result = {}
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
user_token = request.POST['user_token']
|
|
||||||
region = request.POST['region']
|
|
||||||
|
|
||||||
routers_dict = remove_project_resource(region, project_id, 'routers')
|
|
||||||
|
|
||||||
if routers_dict is not None:
|
|
||||||
for router in routers_dict:
|
|
||||||
result[router['id']] = neutron.delete_router(
|
|
||||||
user_token,
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
router['id'])
|
|
||||||
else:
|
|
||||||
result = 'ERROR'
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_volumes(request):
|
|
||||||
"""The deleting volumes view."""
|
|
||||||
result = {}
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
user_token = request.POST['user_token']
|
|
||||||
region = request.POST['region']
|
|
||||||
|
|
||||||
volumes_dict = remove_project_resource(region, project_id, 'volumes')
|
|
||||||
|
|
||||||
if volumes_dict is not None:
|
|
||||||
for volume in volumes_dict:
|
|
||||||
result[volume['id']] = cinder.delete_volume(
|
|
||||||
user_token,
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
volume['id'])
|
|
||||||
else:
|
|
||||||
result = 'ERROR'
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_snapshots(request):
|
|
||||||
"""The deleting snapshots view."""
|
|
||||||
result = {}
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
user_token = request.POST['user_token']
|
|
||||||
region = request.POST['region']
|
|
||||||
|
|
||||||
snapshots_dict = remove_project_resource(region, project_id, 'snapshots')
|
|
||||||
|
|
||||||
if snapshots_dict is not None:
|
|
||||||
for snapshot in snapshots_dict:
|
|
||||||
result[snapshot['id']] = cinder.delete_snapshot(
|
|
||||||
user_token,
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
snapshot['id'])
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_backups(request):
|
|
||||||
"""The deleting backups view."""
|
|
||||||
result = {}
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
user_token = request.POST['user_token']
|
|
||||||
region = request.POST['region']
|
|
||||||
|
|
||||||
backups_dict = remove_project_resource(region, project_id, 'backups')
|
|
||||||
|
|
||||||
if backups_dict is not None:
|
|
||||||
for backup in backups_dict:
|
|
||||||
result[backup['id']] = cinder.delete_backup(
|
|
||||||
user_token,
|
|
||||||
region,
|
|
||||||
project_id,
|
|
||||||
backup['id'])
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_images(request):
|
|
||||||
"""The deleting images view."""
|
|
||||||
result = {}
|
|
||||||
project_id = request.POST['project_id']
|
|
||||||
user_token = request.POST['user_token']
|
|
||||||
region = request.POST['region']
|
|
||||||
|
|
||||||
images_key = region + '_' + project_id + '_images'
|
|
||||||
tenant_images = cache.get(images_key)
|
|
||||||
error_images = []
|
|
||||||
|
|
||||||
if tenant_images is not None:
|
|
||||||
# todo (nathan) improve this
|
|
||||||
# remove the tenant image cached
|
|
||||||
# cache.delete(images_key)
|
|
||||||
# scrubber_images = get_all_images(region)
|
|
||||||
# scrubber_images.pop(tenant_id, None)
|
|
||||||
# cache.set('scrubber_images', scrubber_images, 3600)
|
|
||||||
|
|
||||||
for image in tenant_images:
|
|
||||||
result[image['id']] = glance.delete_image(
|
|
||||||
user_token,
|
|
||||||
region,
|
|
||||||
image['id'])
|
|
||||||
|
|
||||||
if result[image['id']] != 'Image Deleted':
|
|
||||||
error_images.append(image)
|
|
||||||
else:
|
|
||||||
# todo (nathan) log that there were no images to delete
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
# related to above, this is hackish, but it works for now
|
|
||||||
if len(error_images) > 0:
|
|
||||||
cache.set(images_key, error_images, 600)
|
|
||||||
else:
|
|
||||||
cache.set(images_key, {}, 600)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result))
|
|
||||||
|
|
||||||
|
|
||||||
def get_project_resource(region, project_id, resource, update_cache='True'):
|
|
||||||
"""Utility method to get resource map from cache."""
|
|
||||||
resource_map = 'ERROR'
|
|
||||||
resource_key = region + '_' + project_id + '_' + resource
|
|
||||||
|
|
||||||
if resource in DISPATCH_MAP:
|
|
||||||
if update_cache == 'True':
|
|
||||||
coda_token = coda.get_auth_token()
|
|
||||||
resource_map = DISPATCH_MAP[resource](
|
|
||||||
coda_token,
|
|
||||||
region,
|
|
||||||
project_id)
|
|
||||||
else:
|
|
||||||
resource_map = cache.get(resource_key)
|
|
||||||
|
|
||||||
if resource_map is None:
|
|
||||||
coda_token = coda.get_auth_token()
|
|
||||||
resource_map = DISPATCH_MAP[resource](
|
|
||||||
coda_token,
|
|
||||||
region,
|
|
||||||
project_id)
|
|
||||||
|
|
||||||
cache.set(resource_key, resource_map, 600)
|
|
||||||
|
|
||||||
return resource_map
|
|
||||||
|
|
||||||
|
|
||||||
def remove_project_resource(region, tenant_id, resource):
|
|
||||||
"""Utility method to remove resource map from cache."""
|
|
||||||
resource_key = region + '_' + tenant_id + '_' + resource
|
|
||||||
resource_map = cache.get(resource_key)
|
|
||||||
|
|
||||||
if resource_map is not None:
|
|
||||||
cache.delete(resource_key)
|
|
||||||
|
|
||||||
return resource_map
|
|
|
@ -1,290 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# TODO add how to use this
|
|
||||||
|
|
||||||
source set_coda_env.sh
|
|
||||||
|
|
||||||
function hasNetwork {
|
|
||||||
networks=`neutron net-list | awk '{if ($2 != "id" && $2 != "|" && NF>1) print $2 " " $4}' | grep -v "ext-net"`
|
|
||||||
|
|
||||||
if [ ${#networks} -eq 0 ]
|
|
||||||
then
|
|
||||||
CODA_NETWORK_ID=""
|
|
||||||
return -1
|
|
||||||
else
|
|
||||||
parts=($networks)
|
|
||||||
CODA_NETWORK_ID=${parts[0]}
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasSecGroups {
|
|
||||||
expectedCount=$1
|
|
||||||
groups=`neutron security-group-list | awk '{if ($2 != "id" && NF>1) print $4}' | grep -v default`
|
|
||||||
|
|
||||||
if [ ${#groups} -eq 0 ]
|
|
||||||
then
|
|
||||||
echo "No Security Groups"
|
|
||||||
return -1
|
|
||||||
else
|
|
||||||
parts=($groups)
|
|
||||||
if [ ${#parts[@]} -ne $expectedCount ]
|
|
||||||
then
|
|
||||||
echo "WARNING: Unexpected Number of Security Groups."
|
|
||||||
return -1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSecurityGroup {
|
|
||||||
groupName=$1
|
|
||||||
description=$2
|
|
||||||
exists=`neutron security-group-show $groupName`
|
|
||||||
|
|
||||||
if [[ ${exists:0:1} == "+" ]]
|
|
||||||
then
|
|
||||||
echo "Group $groupName already exists."
|
|
||||||
return -1
|
|
||||||
else
|
|
||||||
neutron security-group-create $groupName --description "$description"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFloatingIPs {
|
|
||||||
count=$1
|
|
||||||
floatingIPs=`neutron floatingip-list | awk '{if ($2 != "id" && NF>1) print $2}'`
|
|
||||||
|
|
||||||
if [ ${#floatingIPs} -eq 0 ]
|
|
||||||
then
|
|
||||||
echo "Creating $count floating IP's."
|
|
||||||
for x in $(seq 1 $count)
|
|
||||||
do
|
|
||||||
neutron floatingip-create Ext-Net
|
|
||||||
done
|
|
||||||
else
|
|
||||||
parts=($floatingIPs)
|
|
||||||
if [ ${#parts[@]} -gt $count ]
|
|
||||||
then
|
|
||||||
echo "WARNING: Too many floating IP's."
|
|
||||||
elif [ ${#parts[@]} -lt $count ]
|
|
||||||
then
|
|
||||||
diff=`expr $count - ${#parts[@]}`
|
|
||||||
echo "Not enough floating IP's, creating $diff more."
|
|
||||||
for x in $(seq 1 $diff)
|
|
||||||
do
|
|
||||||
neutron floatingip-create Ext-Net
|
|
||||||
done
|
|
||||||
else
|
|
||||||
echo "Floating IP's already created."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
function assignAllFloatingIPs {
|
|
||||||
for x in `nova list | awk '{if ($2 != "ID" && NF>1 && $13 == "|") print $2}'`;
|
|
||||||
do port=`neutron port-list -- --device_id $x | awk '{if ($2 != "id" && NF>1) print $2}'`;
|
|
||||||
fip=`neutron floatingip-list | grep '| *|' | head -1 | awk '{print $2}'`;
|
|
||||||
neutron floatingip-associate $fip $port;
|
|
||||||
done;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasInstances {
|
|
||||||
expectedCount=$1
|
|
||||||
instances=`nova list | awk '{if ($2 != "ID" && NF>1) print $4}'`
|
|
||||||
|
|
||||||
if [ ${#instances} -eq 0 ]
|
|
||||||
then
|
|
||||||
echo "No Instances"
|
|
||||||
return -1
|
|
||||||
else
|
|
||||||
parts=($instances)
|
|
||||||
if [ ${#parts[@]} -ne $expectedCount ]
|
|
||||||
then
|
|
||||||
echo "WARNING: Unexpected Number of instances."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
function createVolumes {
|
|
||||||
count=$1
|
|
||||||
name=$2
|
|
||||||
volumes=`cinder list | awk '{if ($2 != "ID" && NF>1) print $2}'`
|
|
||||||
|
|
||||||
if [ ${#volumes} -eq 0 ]
|
|
||||||
then
|
|
||||||
echo "Creating $count Volumes."
|
|
||||||
for x in $(seq 1 $count)
|
|
||||||
do
|
|
||||||
cinder create --display-name "$name-0$x" --display-description "Testing a volume $x" 5
|
|
||||||
done
|
|
||||||
else
|
|
||||||
parts=($volumes)
|
|
||||||
if [ ${#parts[@]} -gt $count ]
|
|
||||||
then
|
|
||||||
echo "WARNING: Too many Volumes."
|
|
||||||
elif [ ${#parts[@]} -lt $count ]
|
|
||||||
then
|
|
||||||
diff=`expr $count - ${#parts[@]}`
|
|
||||||
echo "Not enough Volumes, creating $diff more."
|
|
||||||
for x in $(seq 1 $diff)
|
|
||||||
do
|
|
||||||
cinder create --display-name "$name-0$x" --display-description "Testing a volume $x" 5
|
|
||||||
done
|
|
||||||
else
|
|
||||||
echo "Volumes already created."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSnapshots {
|
|
||||||
volumes=`cinder list | awk '{if ($2 != "ID" && NF>1) print $2}'`
|
|
||||||
snapshots=`cinder snapshot-list | awk '{if ($2 != "ID" && NF>1) print $4}'`
|
|
||||||
|
|
||||||
for vol in $volumes
|
|
||||||
do
|
|
||||||
exists=`echo $snapshots | grep $vol`
|
|
||||||
echo $exists
|
|
||||||
if [ ${#exists} -eq 0 ]
|
|
||||||
then
|
|
||||||
echo "Creating Snapshot of $vol."
|
|
||||||
cinder snapshot-create --display-name "snapshot_$vol" --display-description 'Testing a snapshot' $vol
|
|
||||||
else
|
|
||||||
echo "Snapshot for Volume: $vol already exists."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
function createBackups {
|
|
||||||
volumes=`cinder list | awk '{if ($2 != "ID" && NF>1) print $2}'`
|
|
||||||
backups=`cinder backup-list | awk '{if ($2 != "ID" && NF>1) print $4}'`
|
|
||||||
|
|
||||||
for vol in $volumes
|
|
||||||
do
|
|
||||||
exists=`echo $backups | grep $vol`
|
|
||||||
echo $exists
|
|
||||||
if [ ${#exists} -eq 0 ]
|
|
||||||
then
|
|
||||||
echo "Creating Backup of $vol."
|
|
||||||
cinder backup-create --display-name "backup_$vol" --display-description 'Testing a backup.' $vol
|
|
||||||
else
|
|
||||||
echo "Backup for Volume: $vol already exists."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
function createImages {
|
|
||||||
instances=`nova list | awk '{if ($2 != "ID" && NF>1) print $4}'`
|
|
||||||
images=`glance -k image-list --property-filter owner_id=$OS_TENANT_ID | awk '{if ($2 != "ID" && NF>1) print $4}'`
|
|
||||||
|
|
||||||
for i in $instances
|
|
||||||
do
|
|
||||||
exists=`echo $images | grep "$i-image"`
|
|
||||||
echo $exists
|
|
||||||
if [ ${#exists} -eq 0 ]
|
|
||||||
then
|
|
||||||
echo "Creating Image of $i."
|
|
||||||
nova image-create $i "$i-image"
|
|
||||||
else
|
|
||||||
echo "Image of Instance: $i already exists."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#==============================================================================================================================================================
|
|
||||||
|
|
||||||
# Create Resources for Project 1
|
|
||||||
echo "Creating Resources for Project 1"
|
|
||||||
export OS_USERNAME=$CODA_USER_1
|
|
||||||
export OS_TENANT_NAME=$CODA_PROJECT_NAME_1
|
|
||||||
export OS_TENANT_ID=$CODA_PROJECT_ID_1
|
|
||||||
|
|
||||||
# Network for Project 1
|
|
||||||
hasNetwork
|
|
||||||
|
|
||||||
if [ ${#CODA_NETWORK_ID} -eq 0 ]
|
|
||||||
then
|
|
||||||
echo "creating coda-network"
|
|
||||||
neutron net-create coda-network
|
|
||||||
neutron subnet-create coda-network 10.0.0.0/24 --name coda-subnet
|
|
||||||
neutron net-create coda2-net
|
|
||||||
neutron subnet-create coda2-net 10.10.0.0/16 --name coda2-subnet
|
|
||||||
neutron router-create coda-router
|
|
||||||
neutron router-interface-add coda-router coda-subnet
|
|
||||||
neutron router-interface-add coda-router coda2-subnet
|
|
||||||
neutron router-gateway-set coda-router Ext-Net
|
|
||||||
hasNetwork #Make sure we get the variable set when done.
|
|
||||||
else
|
|
||||||
echo "coda-network already created."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Security Groups for Project 1
|
|
||||||
echo "Creating Security Groups."
|
|
||||||
if createSecurityGroup basenode 'The base security group for all nodes.'
|
|
||||||
then
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 22 --port_range_max 22 --remote-ip-prefix 10.0.0.0/8 basenode
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 9182 --port_range_max 9182 --remote-ip-prefix 10.0.0.0/8 basenode
|
|
||||||
fi
|
|
||||||
|
|
||||||
if createSecurityGroup chef-server 'Opens Chef ports'
|
|
||||||
then
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 4000 --port_range_max 4000 --remote-ip-prefix 10.0.0.0/8 chef-server
|
|
||||||
fi
|
|
||||||
|
|
||||||
if createSecurityGroup web-server 'Good for a web server'
|
|
||||||
then
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 80 --port_range_max 80 --remote-ip-prefix 10.0.0.0/8 web-server
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 81 --port_range_max 81 --remote-ip-prefix 10.0.0.0/8 web-server
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 443 --port_range_max 443 --remote-ip-prefix 10.0.0.0/8 web-server
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 8080 --port_range_max 8080 --remote-ip-prefix 10.0.0.0/8 web-server
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 8081 --port_range_max 8081 --remote-ip-prefix 10.0.0.0/8 web-server
|
|
||||||
fi
|
|
||||||
|
|
||||||
if createSecurityGroup email 'email ports'
|
|
||||||
then
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 25 --port_range_max 25 --remote-ip-prefix 10.0.0.0/8 email
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 110 --port_range_max 110 --remote-ip-prefix 10.0.0.0/8 email
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 143 --port_range_max 143 --remote-ip-prefix 10.0.0.0/8 email
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 465 --port_range_max 465 --remote-ip-prefix 10.0.0.0/8 email
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 993 --port_range_max 993 --remote-ip-prefix 10.0.0.0/8 email
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 995 --port_range_max 995 --remote-ip-prefix 10.0.0.0/8 email
|
|
||||||
neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 2525 --port_range_max 2525 --remote-ip-prefix 10.0.0.0/8 email
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Instances for Project 1
|
|
||||||
if hasInstances 4
|
|
||||||
then
|
|
||||||
echo "Instances already created."
|
|
||||||
else
|
|
||||||
echo "Creating instances."
|
|
||||||
# Two for user trumpetsherald
|
|
||||||
nova boot --flavor $CODA_FLAVOR --image $CODA_IMAGE_1 --key_name $CODA_KEY --availability-zone $CODA_AZ1 --security-groups basenode,web-server --nic net-id=$CODA_NETWORK_ID blogs;
|
|
||||||
nova boot --flavor $CODA_FLAVOR --image $CODA_IMAGE_2 --key_name $CODA_KEY --availability-zone $CODA_AZ2 --security-groups basenode,chef-server --nic net-id=$CODA_NETWORK_ID chef-server;
|
|
||||||
|
|
||||||
# Two for user nkimball
|
|
||||||
export OS_USERNAME=$CODA_USER_2
|
|
||||||
nova boot --flavor $CODA_FLAVOR --image $CODA_IMAGE_3 --key_name $CODA_KEY --availability-zone $CODA_AZ1 --security-groups basenode,email --nic net-id=$CODA_NETWORK_ID email;
|
|
||||||
nova boot --flavor $CODA_FLAVOR --image $CODA_IMAGE_4 --key_name $CODA_KEY --availability-zone $CODA_AZ2 --security-groups basenode,web-server --nic net-id=$CODA_NETWORK_ID web-server;
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Floating IP's for Project 1
|
|
||||||
createFloatingIPs 4
|
|
||||||
|
|
||||||
sleep 10
|
|
||||||
|
|
||||||
# Assign All the Floating IP's
|
|
||||||
assignAllFloatingIPs
|
|
||||||
|
|
||||||
# Create Volumes for Project 1
|
|
||||||
createVolumes 2 'test'
|
|
||||||
echo "I'm sleeping for 30 seconds to allow the instances to build before creating images of them."
|
|
||||||
sleep 30
|
|
||||||
#createSnapshots
|
|
||||||
#createBackups
|
|
||||||
createImages
|
|
||||||
#==============================================================================================================================================================
|
|
45
dashboard.py
45
dashboard.py
|
@ -1,45 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""The coda dashboard module.
|
|
||||||
|
|
||||||
Coda is a Horizon dashboard and panel (both share the name) that
|
|
||||||
facilitates resource clean up of a project once that project is no longer
|
|
||||||
needed http://openstack.org
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
import horizon
|
|
||||||
|
|
||||||
|
|
||||||
class Codagroup(horizon.PanelGroup):
|
|
||||||
"""Defines the coda group, currently not used."""
|
|
||||||
|
|
||||||
slug = "codagroup"
|
|
||||||
name = _("Coda Group")
|
|
||||||
panels = ('coda',)
|
|
||||||
|
|
||||||
|
|
||||||
class Coda(horizon.Dashboard):
|
|
||||||
"""The coda panel."""
|
|
||||||
|
|
||||||
name = _("Coda")
|
|
||||||
slug = "coda"
|
|
||||||
panels = ('coda',)
|
|
||||||
default_panel = 'coda'
|
|
||||||
|
|
||||||
|
|
||||||
horizon.register(Coda)
|
|
19
models.py
19
models.py
|
@ -1,19 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
This is a stub file.
|
|
||||||
|
|
||||||
Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
|
|
||||||
"""
|
|
|
@ -1,29 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
export CODA_USER_1=coda_user
|
|
||||||
export CODA_USER_2=coda_user2
|
|
||||||
|
|
||||||
export OS_PASSWORD=hpinvent
|
|
||||||
|
|
||||||
export CODA_PROJECT_NAME_1="coda_project"
|
|
||||||
export CODA_PROJECT_ID_1=8a8b30b83aab4b0d9044b883ab95cd46
|
|
||||||
|
|
||||||
#export CODA_TENANT_NAME_2="Kimballs-Project"
|
|
||||||
#export CODA_TENANT_ID_2=10100821657591
|
|
||||||
|
|
||||||
export OS_AUTH_URL=http://10.23.201.133:5000/v2.0/
|
|
||||||
#export OS_REGION_NAME=region-a.geo-1
|
|
||||||
|
|
||||||
export NOVACLIENT_INSECURE=True
|
|
||||||
export NEUTRONCLIENT_INSECURE=True
|
|
||||||
export CINDERCLIENT_INSECURE=True
|
|
||||||
|
|
||||||
export CODA_KEY=hpcloud
|
|
||||||
|
|
||||||
export CODA_IMAGE_1=983ceae5-046e-46b1-a6ca-22fce45c3d15
|
|
||||||
export CODA_IMAGE_2=983ceae5-046e-46b1-a6ca-22fce45c3d15
|
|
||||||
export CODA_IMAGE_3=983ceae5-046e-46b1-a6ca-22fce45c3d15
|
|
||||||
export CODA_IMAGE_4=983ceae5-046e-46b1-a6ca-22fce45c3d15
|
|
||||||
|
|
||||||
export CODA_FLAVOR=2
|
|
||||||
export CODA_AZ1=nova
|
|
||||||
export CODA_AZ2=nova
|
|
|
@ -1,27 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
export CODA_USER_1=coda_user
|
|
||||||
export CODA_USER_2=coda_user2
|
|
||||||
|
|
||||||
export OS_PASSWORD=coda_p@ssw0rd
|
|
||||||
|
|
||||||
export CODA_PROJECT_NAME_1="coda_project"
|
|
||||||
export CODA_PROJECT_ID_1=project_guid
|
|
||||||
|
|
||||||
|
|
||||||
export OS_AUTH_URL=http://127.0.0.1:5000/v2.0/
|
|
||||||
#export OS_REGION_NAME=region-a.geo-1
|
|
||||||
|
|
||||||
export NOVACLIENT_INSECURE=True
|
|
||||||
export NEUTRONCLIENT_INSECURE=True
|
|
||||||
export CINDERCLIENT_INSECURE=True
|
|
||||||
|
|
||||||
export CODA_KEY=hpcloud
|
|
||||||
|
|
||||||
export CODA_IMAGE_1=imgae_guid
|
|
||||||
export CODA_IMAGE_2=imgae_guid
|
|
||||||
export CODA_IMAGE_3=imgae_guid
|
|
||||||
export CODA_IMAGE_4=imgae_guid
|
|
||||||
|
|
||||||
export CODA_FLAVOR=2
|
|
||||||
export CODA_AZ1=nova
|
|
||||||
export CODA_AZ2=nova
|
|
|
@ -1 +0,0 @@
|
||||||
/* Additional JavaScript for coda. */
|
|
|
@ -1,137 +0,0 @@
|
||||||
/*!
|
|
||||||
* JavaScript Cookie v2.0.0-pre
|
|
||||||
* https://github.com/js-cookie/js-cookie
|
|
||||||
*
|
|
||||||
* Copyright 2006, 2015 Klaus Hartl
|
|
||||||
* Released under the MIT license
|
|
||||||
*/
|
|
||||||
(function (factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
define(factory);
|
|
||||||
} else if (typeof exports === 'object') {
|
|
||||||
module.exports = factory();
|
|
||||||
} else {
|
|
||||||
var _OldCookies = window.Cookies;
|
|
||||||
var api = window.Cookies = factory(window.jQuery);
|
|
||||||
api.noConflict = function () {
|
|
||||||
window.Cookies = _OldCookies;
|
|
||||||
return api;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}(function () {
|
|
||||||
function extend () {
|
|
||||||
var i = 0;
|
|
||||||
var result = {};
|
|
||||||
for (; i < arguments.length; i++) {
|
|
||||||
var attributes = arguments[ i ];
|
|
||||||
for (var key in attributes) {
|
|
||||||
result[key] = attributes[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function init (converter) {
|
|
||||||
function api (key, value, attributes) {
|
|
||||||
var result;
|
|
||||||
|
|
||||||
// Write
|
|
||||||
|
|
||||||
if (arguments.length > 1) {
|
|
||||||
attributes = extend({
|
|
||||||
path: '/'
|
|
||||||
}, api.defaults, attributes);
|
|
||||||
|
|
||||||
if (typeof attributes.expires === 'number') {
|
|
||||||
var expires = new Date();
|
|
||||||
expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
|
|
||||||
attributes.expires = expires;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
result = JSON.stringify(value);
|
|
||||||
if (/^[\{\[]/.test(result)) {
|
|
||||||
value = result;
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
value = encodeURIComponent(String(value));
|
|
||||||
value = value.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
|
|
||||||
|
|
||||||
key = encodeURIComponent(String(key));
|
|
||||||
key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
|
|
||||||
key = key.replace(/[\(\)]/g, escape);
|
|
||||||
|
|
||||||
return (document.cookie = [
|
|
||||||
key, '=', value,
|
|
||||||
attributes.expires && '; expires=' + attributes.expires.toUTCString(), // use expires attribute, max-age is not supported by IE
|
|
||||||
attributes.path && '; path=' + attributes.path,
|
|
||||||
attributes.domain && '; domain=' + attributes.domain,
|
|
||||||
attributes.secure && '; secure'
|
|
||||||
].join(''));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read
|
|
||||||
|
|
||||||
if (!key) {
|
|
||||||
result = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// To prevent the for loop in the first place assign an empty array
|
|
||||||
// in case there are no cookies at all. Also prevents odd result when
|
|
||||||
// calling "get()"
|
|
||||||
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
|
||||||
var rdecode = /(%[0-9A-Z]{2})+/g;
|
|
||||||
var i = 0;
|
|
||||||
|
|
||||||
for (; i < cookies.length; i++) {
|
|
||||||
var parts = cookies[i].split('=');
|
|
||||||
var name = parts[0].replace(rdecode, decodeURIComponent);
|
|
||||||
var cookie = parts.slice(1).join('=');
|
|
||||||
|
|
||||||
if (cookie.charAt(0) === '"') {
|
|
||||||
cookie = cookie.slice(1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cookie = converter && converter(cookie, name) || cookie.replace(rdecode, decodeURIComponent);
|
|
||||||
|
|
||||||
if (this.json) {
|
|
||||||
try {
|
|
||||||
cookie = JSON.parse(cookie);
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key === name) {
|
|
||||||
result = cookie;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!key) {
|
|
||||||
result[name] = cookie;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
api.get = api.set = api;
|
|
||||||
api.getJSON = function () {
|
|
||||||
return api.apply({
|
|
||||||
json: true
|
|
||||||
}, [].slice.call(arguments));
|
|
||||||
};
|
|
||||||
api.defaults = {};
|
|
||||||
|
|
||||||
api.remove = function (key, attributes) {
|
|
||||||
api(key, '', extend(attributes, {
|
|
||||||
expires: -1
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
api.withConverter = init;
|
|
||||||
|
|
||||||
return api;
|
|
||||||
}
|
|
||||||
|
|
||||||
return init();
|
|
||||||
}));
|
|
|
@ -1 +0,0 @@
|
||||||
/* Additional SCSS for {{ dash_name }}. */
|
|
|
@ -1,11 +0,0 @@
|
||||||
{% extends 'base.html' %}
|
|
||||||
|
|
||||||
{% block sidebar %}
|
|
||||||
{% include 'horizon/common/_sidebar.html' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
{% include "horizon/_messages.html" %}
|
|
||||||
{% block coda_main %}{% endblock %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
"""Utilities for use in templates.
|
|
||||||
|
|
||||||
The jsfunc method replaces - with _ to allow for proper java script
|
|
||||||
function names.
|
|
||||||
"""
|
|
|
@ -1,38 +0,0 @@
|
||||||
# Copyright [2015] Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
|
|
||||||
"""Utilities for use in templates.
|
|
||||||
|
|
||||||
The jsfunc method replaces - with _ to allow for proper java script
|
|
||||||
function names.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django import template
|
|
||||||
from django.template.defaultfilters import stringfilter
|
|
||||||
|
|
||||||
register = template.Library()
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def get(mapping, key):
|
|
||||||
"""Safe way to get a value from a dict."""
|
|
||||||
return mapping.get(key, '')
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
|
||||||
@stringfilter
|
|
||||||
def jsfunc(value):
|
|
||||||
"""Create a safe javascript function name."""
|
|
||||||
return value.replace('-', '_')
|
|
Loading…
Reference in New Issue