Merge branch 'master' of github.com:Mirantis/product

This commit is contained in:
Vladimir Kozhukalov 2012-07-18 18:39:47 +04:00
commit 2e9f9e0e10
12 changed files with 126 additions and 28 deletions

2
cooks

@ -1 +1 @@
Subproject commit 10d11738e69c31bd31c75b689275570bd2824b7f
Subproject commit 6e5cea9f5525b3a08591071472a709f0f069ab49

View File

@ -241,6 +241,10 @@ behavior: url(/static/css/pie.htc);
color: #333333;
}
.cluster-control .btn {
margin-left: 15px;
}
.dialog-node {
cursor: pointer !important;
}

View File

@ -10,18 +10,6 @@
<link href="/static/css/overlap.css" rel="stylesheet">
<link href="/static/css/buttons.css" rel="stylesheet">
<link href="/static/css/font-awesome.css" rel="stylesheet">
<style>
@font-face {
font-family: 'FontAwesome';
src: url('/static/font/fontawesome-webfont.eot');
src: url('/static/font/fontawesome-webfont.eot?#iefix') format('embedded-opentype'),
url('/static/font/fontawesome-webfont.woff') format('woff'),
url('/static/font/fontawesome-webfont.ttf') format('truetype'),
url('/static/font/fontawesome-webfont.svg#FontAwesome') format('svg');
font-weight: normal;
font-style: normal;
}
</style>
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>

View File

@ -16,11 +16,15 @@ function(models, dialogViews, taskViews, clusterPageTemplate, clusterNodeTemplat
updateInterval: 5000,
template: _.template(clusterPageTemplate),
events: {
'click .js-add-nodes': 'addRemoveNodes'
'click .add-nodes-btn': 'addRemoveNodes',
'click .assign-roles-btn': 'assignRoles'
},
addRemoveNodes: function(e) {
(new dialogViews.addRemoveNodesDialog({model: this.model})).render();
},
assignRoles: function(e) {
(new dialogViews.assignRolesDialog({model: this.model})).render();
},
initialize: function() {
this.model.bind('change', this.render, this);
this.scheduleUpdate();

View File

@ -3,20 +3,20 @@ define(
'models',
'text!templates/dialogs/add_remove_nodes.html',
'text!templates/dialogs/create_cluster.html',
'text!templates/dialogs/node_list.html'
'text!templates/dialogs/node_list.html',
'text!templates/dialogs/assign_roles.html'
],
function(models, addRemoveNodesDialogTemplate, createClusterDialogTemplate, nodeDialogNodeListTemplate) {
function(models, addRemoveNodesDialogTemplate, createClusterDialogTemplate, nodeDialogNodeListTemplate, assignRolesDialogTemplate) {
var views = {}
views.addRemoveNodesDialog = Backbone.View.extend({
className: 'modal fade',
template: _.template(addRemoveNodesDialogTemplate),
events: {
'click .js-save-changes': 'saveChanges',
'click .save-changes-btn': 'saveChanges',
'click .dialog-node': 'toggleNode'
},
saveChanges: function(e) {
e.preventDefault();
var nodes = this.$('.node-checked').map(function(){return $(this).attr('data-node-id')}).get();
this.model.update({nodes: nodes});
this.$el.modal('hide');
@ -45,11 +45,10 @@ function(models, addRemoveNodesDialogTemplate, createClusterDialogTemplate, node
className: 'modal fade',
template: _.template(createClusterDialogTemplate),
events: {
'click .js-create-cluster': 'createCluster',
'click .create-cluster-btn': 'createCluster',
'click .dialog-node': 'toggleNode'
},
createCluster: function(e) {
e.preventDefault();
this.$('.help-inline').text('');
this.$('.control-group').removeClass('error');
var nodes = this.$('.node-checked').map(function(){return $(this).attr('data-node-id')}).get();
@ -111,5 +110,23 @@ function(models, addRemoveNodesDialogTemplate, createClusterDialogTemplate, node
}
});
views.assignRolesDialog = Backbone.View.extend({
className: 'modal fade',
template: _.template(assignRolesDialogTemplate),
events: {
'click .assign-roles-btn': 'assignRoles'
},
assignRoles: function() {
// TODO
this.$el.modal('hide');
},
render: function() {
this.$el.html(this.template());
this.$el.on('hidden', function() {$(this).remove()});
this.$el.modal();
return this;
}
});
return views;
});

View File

@ -46,7 +46,7 @@
</div>
<% } else if (node.get('status') == 'error') { %>
<div class="statusbar-text msg-error">
<i class="icon-warning-sign"></i><strong>Error</strong>
<i class="icon-exclamation-sign"></i><strong>Error</strong>
</div>
<% } else if (node.get('status') == 'deploying') { %>
<div class="statusbar-text msg-warning">

View File

@ -1,7 +1,12 @@
<div class="row">
<div class="span8"><h1><%= cluster.get('name') %></h1></div>
<div class="span2"><button class="btn pull-right"><i class="icon-wrench icon-white"></i>Settings</button></div>
<div class="span2"><button class="btn btn-success pull-right js-add-nodes"><i class="icon-plus-sign icon-white"></i>Add Nodes</button></div>
<div class="span6">
<h1><%= cluster.get('name') %></h1>
</div>
<div class="span6 cluster-control">
<button class="btn btn-success pull-right add-nodes-btn"><i class="icon-plus-sign icon-white"></i>Add Nodes</button>
<button class="btn pull-right assign-roles-btn"><i class="icon-tags icon-white"></i>Assign Roles</button>
<button class="btn pull-right"><i class="icon-wrench icon-white"></i>Settings</button>
</div>
</div>
<div class="deployment-control"></div>
<div class="task-status"></div>

View File

@ -19,6 +19,6 @@
</div>
</div>
<div class="modal-footer">
<a href="#" class="btn" data-dismiss="modal">Close</a>
<a href="#" class="btn btn-success js-save-changes">Save changes</a>
<button class="btn" data-dismiss="modal">Close</button>
<button class="btn btn-success save-changes-btn">Save changes</button>
</div>

View File

@ -0,0 +1,39 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h2>Assign Roles</h2>
</div>
<div class="modal-body">
<h3>Please choose deployment type</h3>
<form>
<table class="table">
<tbody>
<tr>
<td style="width: 16px;">
<label class="radio">
<input type="radio" name="type">
</label>
</td>
<td>
<p>Simple Deployment</p>
<p><small>Simple OpenStack deployment</small></p>
</td>
</tr>
<tr>
<td style="width: 16px;">
<label class="radio">
<input type="radio" name="type">
</label>
</td>
<td>
<p>HA Deployment</p>
<p><small>Highly-available OpenStack deployment</small></p>
</td>
</tr>
</tbody>
</table>
</form>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal">Cancel</button>
<button class="btn btn-success assign-roles-btn">Assign Roles</button>
</div>

View File

@ -35,6 +35,6 @@
</div>
</div>
<div class="modal-footer">
<a href="#" class="btn" data-dismiss="modal">Cancel</a>
<a href="#" class="btn btn-success js-create-cluster">Create Cluster</a>
<button class="btn" data-dismiss="modal">Cancel</button>
<button class="btn btn-success create-cluster-btn">Create Cluster</button>
</div>

View File

@ -1,5 +1,6 @@
import time, os
import devops
import unittest
from devops.model import Environment, Network, Node, Disk, Cdrom, Interface
from devops.controller import Controller
from devops.driver.libvirt import Libvirt
@ -130,3 +131,40 @@ def tearDown():
if not ci.environment_cache_file:
ci.destroy_environment()
class CookbokTestCase(unittest.TestCase):
def setUp(self):
self.ip = ci.environment.node['cookbooks'].ip_address
self.cookbooks_dir = os.path.abspath(
os.path.join(
os.path.dirname(__file__),
"..", "..", "cooks", "cookbooks"
)
)
self.remote = SSHClient()
self.remote.connect_ssh(str(self.ip), "root", "r00tme")
self.remote.mkdir("/opt/os-cookbooks/")
with self.remote.open('/tmp/solo.rb', 'w') as solo_rb:
solo_rb.write("""
file_cache_path "/tmp/chef"
cookbook_path "/opt/os-cookbooks"
""")
def upload_cookbooks(self, cookbooks):
if not isinstance(cookbooks, list):
cookbooks = [cookbooks]
for cookbook in cookbooks:
self.remote.scp_d(os.path.join(self.cookbooks_dir, cookbook), "/opt/os-cookbooks/")
def chef_solo(self, attributes={}):
with self.remote.open('/tmp/solo.json', 'w') as f:
f.write(json.dumps(attributes))
result = self.remote.exec_cmd("chef-solo -l debug -c /tmp/solo.rb -j /tmp/solo.json")
if result['exit_status'] != 0:
raise ChefRunError(result['exit_status'], result['stdout'], result['stderr'])
return result

View File

@ -99,6 +99,9 @@ class SSHClient(object):
logging.info("Removing directory: %s" % path)
return self.exec_cmd("rm -rf %s" % path)
def open(self, path, mode='r'):
return self.sftp_client.open(path, mode)
def scp(self, frm, to):
logging.info("Copying file: %s -> %s" % (frm, to))
self.sftp_client.put(frm, to)