Use zunclient instead of stub
Use python-zunclient instead of stub client in skeleton. Then Zun-UI interacts with Zun API. This patch enable CRUD operation of containers. Change-Id: Idc869c0d4d40895e42ccf941f7fcb9d6d1dfb662 Implements: blueprint use-zunclient
This commit is contained in:
parent
325380b7b2
commit
543a2a02f4
@ -8,8 +8,8 @@
|
|||||||
#
|
#
|
||||||
# PBR should always appear first
|
# PBR should always appear first
|
||||||
pbr>=1.6 # Apache-2.0
|
pbr>=1.6 # Apache-2.0
|
||||||
# If python-higginsclient will be created, we will use it.
|
# If python-zunclient will be released, we will use it.
|
||||||
#python-higginsclient>=0.1.0 # Apache-2.0
|
#python-zunclient>=0.0.1 # Apache-2.0
|
||||||
Babel>=2.3.4 # BSD
|
Babel>=2.3.4 # BSD
|
||||||
Django<1.9,>=1.8 # BSD
|
Django<1.9,>=1.8 # BSD
|
||||||
django-babel>=0.5.1 # BSD
|
django-babel>=0.5.1 # BSD
|
||||||
|
7
tox.ini
7
tox.ini
@ -16,6 +16,13 @@ deps = -r{toxinidir}/requirements.txt
|
|||||||
-r{toxinidir}/test-requirements.txt
|
-r{toxinidir}/test-requirements.txt
|
||||||
commands = python manage.py test {posargs} --settings=zun_ui.test.settings
|
commands = python manage.py test {posargs} --settings=zun_ui.test.settings
|
||||||
|
|
||||||
|
# Until python-zunclient released, install from github temporary.
|
||||||
|
[testenv:py27]
|
||||||
|
basepython = python2.7
|
||||||
|
commands =
|
||||||
|
pip install git+https://github.com/openstack/python-zunclient.git
|
||||||
|
python manage.py test {posargs} --settings=zun_ui.test.settings
|
||||||
|
|
||||||
[testenv:pep8]
|
[testenv:pep8]
|
||||||
commands = flake8 {posargs}
|
commands = flake8 {posargs}
|
||||||
|
|
||||||
|
@ -11,45 +11,20 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
import logging
|
|
||||||
# from zunclient.v1 import client as zun_client
|
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from horizon.utils.memoized import memoized
|
from horizon.utils.memoized import memoized
|
||||||
# from openstack_dashboard.api import base
|
import logging
|
||||||
|
from openstack_dashboard.api import base
|
||||||
# for stab, should remove when use CLI API
|
from zunclient.v1 import client as zun_client
|
||||||
import copy
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
CONTAINER_CREATE_ATTRS = ['name']
|
CONTAINER_CREATE_ATTRS = ['name', 'image', 'command', 'memory', 'environment']
|
||||||
|
|
||||||
STUB_DATA = {}
|
|
||||||
|
|
||||||
|
|
||||||
# for stab, should be removed when use CLI API
|
|
||||||
class StubResponse(object):
|
|
||||||
|
|
||||||
def __init__(self, info):
|
|
||||||
self._info = info
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_')
|
|
||||||
info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
|
|
||||||
return "<%s %s>" % (self.__class__.__name__, info)
|
|
||||||
|
|
||||||
def to_dict(self):
|
|
||||||
return copy.deepcopy(self._info)
|
|
||||||
|
|
||||||
|
|
||||||
@memoized
|
@memoized
|
||||||
def zunclient(request):
|
def zunclient(request):
|
||||||
pass
|
|
||||||
""""
|
|
||||||
zun_url = ""
|
zun_url = ""
|
||||||
try:
|
try:
|
||||||
zun_url = base.url_for(request, 'container')
|
zun_url = base.url_for(request, 'container')
|
||||||
@ -64,7 +39,6 @@ def zunclient(request):
|
|||||||
input_auth_token=request.user.token.id,
|
input_auth_token=request.user.token.id,
|
||||||
zun_url=zun_url)
|
zun_url=zun_url)
|
||||||
return c
|
return c
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def container_create(request, **kwargs):
|
def container_create(request, **kwargs):
|
||||||
@ -75,41 +49,28 @@ def container_create(request, **kwargs):
|
|||||||
else:
|
else:
|
||||||
raise exceptions.BadRequest(
|
raise exceptions.BadRequest(
|
||||||
"Key must be in %s" % ",".join(CONTAINER_CREATE_ATTRS))
|
"Key must be in %s" % ",".join(CONTAINER_CREATE_ATTRS))
|
||||||
if key == "labels":
|
if key == "environment":
|
||||||
labels = {}
|
envs = {}
|
||||||
vals = value.split(",")
|
vals = value.split(",")
|
||||||
for v in vals:
|
for v in vals:
|
||||||
kv = v.split("=", 1)
|
kv = v.split("=", 1)
|
||||||
labels[kv[0]] = kv[1]
|
envs[kv[0]] = kv[1]
|
||||||
args["labels"] = labels
|
args["environment"] = envs
|
||||||
# created = zunclient(request).containers.create(**args)
|
return zunclient(request).containers.create(**args)
|
||||||
|
|
||||||
# create dummy response
|
|
||||||
args["uuid"] = uuid.uuid1().hex
|
|
||||||
created = StubResponse(args)
|
|
||||||
for k in args:
|
|
||||||
setattr(created, k, args[k])
|
|
||||||
STUB_DATA[created.uuid] = created
|
|
||||||
|
|
||||||
return created
|
|
||||||
|
|
||||||
|
|
||||||
def container_delete(request, id):
|
def container_delete(request, id, force=False):
|
||||||
# deleted = zunclient(request).containers.delete(id)
|
# TODO(shu-mutou): force option should be provided by user.
|
||||||
deleted = STUB_DATA.pop(id)
|
return zunclient(request).containers.delete(id, force)
|
||||||
|
|
||||||
return deleted
|
|
||||||
|
|
||||||
|
|
||||||
def container_list(request, limit=None, marker=None, sort_key=None,
|
def container_list(request, limit=None, marker=None, sort_key=None,
|
||||||
sort_dir=None, detail=True):
|
sort_dir=None, detail=True):
|
||||||
# list = zunclient(request).containers.list(limit, marker, sort_key,
|
# TODO(shu-mutou): detail option should be added, if it is
|
||||||
# sort_dir, detail)
|
# implemented in Zun API
|
||||||
list = [STUB_DATA[data] for data in STUB_DATA]
|
return zunclient(request).containers.list(limit, marker, sort_key,
|
||||||
return list
|
sort_dir)
|
||||||
|
|
||||||
|
|
||||||
def container_show(request, id):
|
def container_show(request, id):
|
||||||
# show = zunclient(request).containers.get(id)
|
return zunclient(request).containers.get(id)
|
||||||
show = STUB_DATA.get(id)
|
|
||||||
return show
|
|
||||||
|
@ -65,6 +65,12 @@
|
|||||||
.setProperty('id', {
|
.setProperty('id', {
|
||||||
label: gettext('ID')
|
label: gettext('ID')
|
||||||
})
|
})
|
||||||
|
.setProperty('image', {
|
||||||
|
label: gettext('Image')
|
||||||
|
})
|
||||||
|
.setProperty('status', {
|
||||||
|
label: gettext('Status')
|
||||||
|
})
|
||||||
.setListFunction(listFunction)
|
.setListFunction(listFunction)
|
||||||
.tableColumns
|
.tableColumns
|
||||||
.append({
|
.append({
|
||||||
@ -77,6 +83,14 @@
|
|||||||
.append({
|
.append({
|
||||||
id: 'id',
|
id: 'id',
|
||||||
priority: 2
|
priority: 2
|
||||||
|
})
|
||||||
|
.append({
|
||||||
|
id: 'image',
|
||||||
|
priority: 2
|
||||||
|
})
|
||||||
|
.append({
|
||||||
|
id: 'status',
|
||||||
|
priority: 2
|
||||||
});
|
});
|
||||||
// for magic-search
|
// for magic-search
|
||||||
registry.getResourceType(resourceType).filterFacets
|
registry.getResourceType(resourceType).filterFacets
|
||||||
@ -89,6 +103,16 @@
|
|||||||
'label': gettext('ID'),
|
'label': gettext('ID'),
|
||||||
'name': 'id',
|
'name': 'id',
|
||||||
'singleton': true
|
'singleton': true
|
||||||
|
})
|
||||||
|
.append({
|
||||||
|
'label': gettext('Image'),
|
||||||
|
'name': 'image',
|
||||||
|
'singleton': true
|
||||||
|
})
|
||||||
|
.append({
|
||||||
|
'label': gettext('Status'),
|
||||||
|
'name': 'status',
|
||||||
|
'singleton': true
|
||||||
});
|
});
|
||||||
|
|
||||||
function listFunction(params) {
|
function listFunction(params) {
|
||||||
|
@ -34,7 +34,14 @@
|
|||||||
|
|
||||||
function initNewContainerSpec() {
|
function initNewContainerSpec() {
|
||||||
model.newContainerSpec = {
|
model.newContainerSpec = {
|
||||||
|
uuid: null,
|
||||||
name: null,
|
name: null,
|
||||||
|
image: null,
|
||||||
|
command: null,
|
||||||
|
memory: null,
|
||||||
|
memory_size: null,
|
||||||
|
memory_unit: "m",
|
||||||
|
environment: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +63,8 @@
|
|||||||
// Not only "null", blank too.
|
// Not only "null", blank too.
|
||||||
for (var key in finalSpec) {
|
for (var key in finalSpec) {
|
||||||
if (finalSpec.hasOwnProperty(key) && finalSpec[key] === null
|
if (finalSpec.hasOwnProperty(key) && finalSpec[key] === null
|
||||||
|| finalSpec[key] === "") {
|
|| finalSpec[key] === ""
|
||||||
|
|| key === "memory_size" || key === "memory_unit") {
|
||||||
delete finalSpec[key];
|
delete finalSpec[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,5 +36,23 @@
|
|||||||
|
|
||||||
function createContainerInfoController($q, $scope, basePath, zun, gettext) {
|
function createContainerInfoController($q, $scope, basePath, zun, gettext) {
|
||||||
var ctrl = this;
|
var ctrl = this;
|
||||||
|
ctrl.memory_units = [{unit: "b", label: gettext("bytes")},
|
||||||
|
{unit: "k", label: gettext("KB")},
|
||||||
|
{unit: "m", label: gettext("MB")},
|
||||||
|
{unit: "g", label: gettext("GB")}];
|
||||||
|
|
||||||
|
$scope.changeMemory = function(){
|
||||||
|
if($scope.model.newContainerSpec.memory_size > 0){
|
||||||
|
$scope.model.newContainerSpec.memory = $scope.model.newContainerSpec.memory_size + $scope.model.newContainerSpec.memory_unit;
|
||||||
|
}else{
|
||||||
|
$scope.model.newContainerSpec.memory = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
$scope.changeMemoryUnit = function(){
|
||||||
|
$scope.changeMemory();
|
||||||
|
};
|
||||||
|
$scope.changeMemorySize = function(){
|
||||||
|
$scope.changeMemory();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
<dl>
|
<dl>
|
||||||
|
<!-- TODO(shu-mutou): descript more! -->
|
||||||
<dt translate>Container Name</dt>
|
<dt translate>Container Name</dt>
|
||||||
<dd translate>An arbitrary human-readable name</dd>
|
<dd translate>An arbitrary human-readable name</dd>
|
||||||
|
<dt translate>Image</dt>
|
||||||
|
<dd translate>Name or ID of container image</dd>
|
||||||
|
<dt translate>Command</dt>
|
||||||
|
<dd translate>Command sent to the container</dd>
|
||||||
|
<dt translate>Memory</dt>
|
||||||
|
<dd translate>The container memory size</dd>
|
||||||
|
<dt translate>Environment Variables</dt>
|
||||||
|
<dd translate>The environment variables in comma separated KEY=VALUE pairs</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<div ng-controller="createContainerInfoController as ctrl">
|
<div ng-controller="createContainerInfoController as ctrl">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label" for="container-name" translate>Container Name</label>
|
<label class="control-label" for="container-name" translate>Container Name</label>
|
||||||
<input name="container-name" type="text" class="form-control" id="container-name"
|
<input name="container-name" type="text" class="form-control" id="container-name"
|
||||||
@ -8,5 +8,51 @@
|
|||||||
placeholder="{$ 'Name of the container to create.'|translate $}">
|
placeholder="{$ 'Name of the container to create.'|translate $}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="container-image">
|
||||||
|
<translate>Image</translate>
|
||||||
|
<span class="hz-icon-required fa fa-asterisk"></span>
|
||||||
|
</label>
|
||||||
|
<input name="container-image" type="text" class="form-control" id="container-image"
|
||||||
|
ng-model="model.newContainerSpec.image"
|
||||||
|
ng-required="true"
|
||||||
|
placeholder="{$ 'Name or ID of the container image.'|translate $}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="container-command" translate>Command</label>
|
||||||
|
<input name="container-command" type="text" class="form-control" id="container-command"
|
||||||
|
ng-model="model.newContainerSpec.command"
|
||||||
|
placeholder="{$ 'A command that will be sent to the container.'|translate $}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="container-memory-size" translate>Memory Size</label>
|
||||||
|
<input name="container-memory-size" type="number" min="1"
|
||||||
|
class="form-control" ng-model="model.newContainerSpec.memory_size"
|
||||||
|
placeholder="{$ 'The container memory size.'|translate $}"
|
||||||
|
ng-change="changeMemorySize()" id="container-memory-size">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="container-memory-unit" translate>Memory Unit</label>
|
||||||
|
<select name="container-memory-unit" id="container-memory-unit"
|
||||||
|
class="form-control" ng-options="mu.unit as mu.label for mu in ctrl.memory_units"
|
||||||
|
ng-model="model.newContainerSpec.memory_unit" ng-change="changeMemoryUnit()">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="container-environment" translate>Environment Variables</label>
|
||||||
|
<input name="container-environment" type="text" class="form-control" id="container-environment"
|
||||||
|
ng-model="model.newContainerSpec.environment"
|
||||||
|
placeholder="{$ 'KEY1=VALUE1,KEY2=VALUE2...'|translate $}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,12 +28,9 @@
|
|||||||
.controller('horizon.dashboard.container.containers.DrawerController', controller);
|
.controller('horizon.dashboard.container.containers.DrawerController', controller);
|
||||||
|
|
||||||
controller.$inject = [
|
controller.$inject = [
|
||||||
'horizon.app.core.openstack-service-api.zun',
|
|
||||||
'horizon.dashboard.container.containers.resourceType'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function controller(zun, resourceType) {
|
function controller() {
|
||||||
var ctrl = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -5,12 +5,24 @@
|
|||||||
<dt translate>ID</dt>
|
<dt translate>ID</dt>
|
||||||
<dd>{$ item.id $}</dd>
|
<dd>{$ item.id $}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
<dl class="col-md-4">
|
||||||
|
<dt translate>Image</dt>
|
||||||
|
<dd>{$ item.image $}</dd>
|
||||||
|
</dl>
|
||||||
|
<dl class="col-md-3">
|
||||||
|
<dt translate>Status</dt>
|
||||||
|
<dd>{$ item.status $}</dd>
|
||||||
|
</dl>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<dl class="col-md-5">
|
<dl class="col-md-9">
|
||||||
<dt translate>Name</dt>
|
<dt translate>Command</dt>
|
||||||
<dd>{$ item.name $}</dd>
|
<dd>{$ item.command $}</dd>
|
||||||
|
</dl>
|
||||||
|
<dl class="col-md-3">
|
||||||
|
<dt translate>Memory</dt>
|
||||||
|
<dd>{$ item.memory $}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,6 +6,24 @@
|
|||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt translate>Name</dt>
|
<dt translate>Name</dt>
|
||||||
<dd>{$ ctrl.container.name|noName $}</dd>
|
<dd>{$ ctrl.container.name|noName $}</dd>
|
||||||
|
<dt translate>Status</dt>
|
||||||
|
<dd>{$ ctrl.container.status $}</dd>
|
||||||
|
<dt translate>Image</dt>
|
||||||
|
<dd>{$ ctrl.container.image $}</dd>
|
||||||
|
<dt translate>Command</dt>
|
||||||
|
<dd>{$ ctrl.container.command $}</dd>
|
||||||
|
<dt translate>Memory</dt>
|
||||||
|
<dd>{$ ctrl.container.memory $}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 detail">
|
||||||
|
<h3 translate>Environment</h3>
|
||||||
|
<hr>
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<div ng-repeat="(key, value) in ctrl.container.environment">
|
||||||
|
<dt>{$ key $}</dt>
|
||||||
|
<dd>{$ value $}</dd>
|
||||||
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user