Update role assignment and network mapping.

Use $q to fix multiple asynchronous ajax calls.

Change-Id: Ifc18fcaa0a4ab1c70a91d4f2a134d5e302fb8ff6
This commit is contained in:
jiahuay 2014-07-10 16:13:46 -07:00
parent 65cb094350
commit ae9da1d1b4
13 changed files with 1057 additions and 366 deletions

View File

@ -69,6 +69,32 @@ select {
}
.partition-chart {
padding-top: 30px;
}
.margin-top-minus10 {
margin-top: -10px !important;
}
.drag-enter {
background: none repeat scroll 0 0 #F0F9FF;
border: 2px dashed #BED2DB !important;
box-sizing: border-box;
margin: 5px 0;
min-height: 50px;
padding: 0;
}
.network-draggable {
position: relative;
width: 200px;
}
.network-placeholder {
min-height: 200px;
}
.interface-placeholder {
border: 1px solid #BED2DB;
box-sizing: border-box;
margin: 5px 0;
min-height: 50px;
padding: 10px;
}
.btn-clstr {
border: none !important;
background-color: inherit!important;

View File

@ -3,33 +3,25 @@
"id": 10,
"name": "demo",
"adapter_id": 1,
"os_id":1
"os_id": 1
},
"partition": {
"/swap": {
"size_percentage": 10
},
"/boot": {
"size_percentage": 10
},
"/var": {
"size_percentage": 30
},
"/home": {
"size_percentage": 20
},
"/tmp": {
"size_percentage": 10
"size_percentage": 30
},
"/spare": {
"size_percentage": 40
"size_percentage": 20
}
},
"subnet": [{
"name": "subnet1",
"subnet": "192.168.10.1",
"netmask": "255.255.255.0",
"subnet_id": 1
}, {
"name": "subnet2",
"subnet": "172.1.100.1",
"netmask": "255.255.255.0",
"subnet_id": 2
}],
"interface": {
"eth0": {
"subnet_id": 1,
@ -49,14 +41,16 @@
}
},
"general": {
"timezone": "-8.00",
"timezone": "-4.00",
"language": "en",
"http_proxy": "",
"http_proxy": [""],
"https_proxy": [""],
"default_no_proxy":[""],
"ntp_server": "",
"domain": "compass.com",
"gateway": "172.19.100.1",
"dns_servers": [""],
"search_path": ["compass.com"]
"search_path": ["compass.com"],
"domain": "compass.com",
"default_gateway": "172.19.100.1"
},
"server_credentials": {
"username": "admin",
@ -87,11 +81,11 @@
"username": "ceilometer",
"password": "ceilometer"
},
"super": {
"mysql": {
"username": "root",
"password": "root"
},
"volumn": {
"volume": {
"username": "cinder",
"password": "cinder"
}
@ -125,10 +119,27 @@
"username": "swift",
"password": "swift"
},
"volumn": {
"volume": {
"username": "cinder",
"password": "cinder"
}
},
"network_mapping": {
"management": {
"display": "Management Network",
"mapping_interface": ""
},
"tenant": {
"display": "Tenant Network",
"mapping_interface": ""
},
"storage": {
"display": "Storage Network",
"mapping_interface": ""
},
"public": {
"display": "Public Network",
"mapping_interface": ""
}
}
}

View File

@ -17,7 +17,7 @@
"visible": true
}, {
"title": "Hostname",
"field": "hostname",
"field": "name",
"visible": true
}, {
"title": "Clusters",
@ -58,7 +58,7 @@
"visible": false
}, {
"title": "Hostname",
"field": "hostname",
"field": "name",
"visible": true
}, {
"title": "Clusters",
@ -80,5 +80,50 @@
"title": "State",
"field": "state",
"visible": false
}],
"review": [{
"title": "Host MAC Addr",
"field": "mac",
"visible": true
}, {
"title": "Switch IP",
"field": "switch_ip",
"visible": true
}, {
"title": "Port",
"field": "port",
"visible": true
}, {
"title": "VLAN",
"field": "vlan",
"visible": false
}, {
"title": "Hostname",
"field": "name",
"visible": true
}, {
"title": "Clusters",
"field": "clusters",
"visible": false
}, {
"title": "OS",
"field": "os",
"visible": false
}, {
"title": "OS Reinstall",
"field": "os_installed",
"visible": false
}, {
"title": "Adapter",
"field": "adapter",
"visible": false
}, {
"title": "Roles",
"field": "roles",
"visible": true
}, {
"title": "State",
"field": "state",
"visible": false
}]
}

View File

@ -21,8 +21,10 @@
<!--<script type="text/javascript" src="../vendor/angular/angular-resource.min.js"></script>-->
<script type="text/javascript" src="vendor/angular-ui-router/angular-ui-router.min.js"></script>
<script type="text/javascript" src="vendor/angular-bootstrap/ui-bootstrap-tpls-0.11.0.min.js"></script>
<script type="text/javascript" src="vendor/angular-dragdrop/draganddrop.js"></script>
<script type="text/javascript" src="vendor/ng-table/ng-table.min.js"></script>
<script type="text/javascript" src="vendor/d3/d3.min.js"></script>
<script type="text/javascript" src="src/app/app.js"></script>
<script type="text/javascript" src="src/app/appDev.js"></script>
<script type="text/javascript" src="src/app/services.js"></script>

View File

@ -58,6 +58,38 @@ compassAppDev.run(function($httpBackend, settings, $http) {
return [200, adapters, {}];
});
$httpBackend.whenGET(/\.*\/adapters\/[1-9][0-9]*/).respond(function(method, url, data) {
console.log(method, url);
var adapter = {
"id": 1,
"name": "openstack",
"display": "OpenStack",
"os_installer": "cobbler",
"package_installer": "chef",
"roles": [{
"display_name": "Compute",
"name": "os-compute-worker"
}, {
"display_name": "Controller",
"name": "os-controller"
}, {
"display_name": "Network",
"name": "os-network"
}, {
"display_name": "Storage",
"name": "os-block-storage-worker"
}],
"compatible_os": [{
"name": "CentOs",
"os_id": 1
}, {
"name": "Ubuntu",
"os_id": 2
}]
};
return [200, adapter, {}];
});
$httpBackend.whenGET(settings.apiUrlBase + '/machines-hosts').respond(function(method, url, data) {
console.log(method, url);
var servers = [{
@ -66,7 +98,7 @@ compassAppDev.run(function($httpBackend, settings, $http) {
"switch_ip": "172.29.8.40",
"vlan": "1",
"port": "1",
"hostname": "sv-1",
"name": "sv-1",
"clusters": ["cluster1", "cluster2"],
"os": "CentOS",
"adapter": "OpenStack",
@ -91,7 +123,7 @@ compassAppDev.run(function($httpBackend, settings, $http) {
"switch_ip": "172.29.8.40",
"vlan": "2",
"port": "2",
"hostname": "sv-2",
"name": "sv-2",
"clusters": ["cluster1"],
"os": "CentOS",
"adapter": "OpenStack",
@ -175,7 +207,7 @@ compassAppDev.run(function($httpBackend, settings, $http) {
return [200, config, {}];
});
$httpBackend.whenGET(/\.*\/clusters\/[1-9][0-9]*\/subnet-config/).respond(function(method, url, data) {
$httpBackend.whenGET(settings.apiUrlBase + '/subnetworks').respond(function(method, url, data) {
console.log(method, url);
var subnetworks = [{
"subnet_id": 1,
@ -191,7 +223,7 @@ compassAppDev.run(function($httpBackend, settings, $http) {
return [200, subnetworks, {}];
});
$httpBackend.whenPOST(/\.*\/clusters\/[1-9][0-9]*\/subnet-config/).respond(function(method, url, data) {
$httpBackend.whenPOST(settings.apiUrlBase + '/subnetworks').respond(function(method, url, data) {
console.log(method, url, data);
var subnetConfig = JSON.parse(data);
@ -201,7 +233,7 @@ compassAppDev.run(function($httpBackend, settings, $http) {
return [200, subnetConfig, {}];
});
$httpBackend.whenPUT(/\.*\/clusters\/[1-9][0-9]*\/subnet-config\/[1-9][0-9]*/).respond(function(method, url, data) {
$httpBackend.whenPUT(/\.*\/subnetworks\/[1-9][0-9]*/).respond(function(method, url, data) {
console.log(method, url, data);
var subnetConfig = JSON.parse(data);
@ -210,6 +242,8 @@ compassAppDev.run(function($httpBackend, settings, $http) {
return [200, subnetConfig, {}];
});
// keep routing table for later use
/*
$httpBackend.whenPOST(/\.*\/clusters\/[1-9][0-9]*\/routing-table/).respond(function(method, url, data) {
console.log(method, url, data);
@ -220,7 +254,7 @@ compassAppDev.run(function($httpBackend, settings, $http) {
return [200, routingTable, {}];
});
$httpBackend.whenPUT(/\.*\/clusters\/[1-9][0-9]*\/routing-table\/[1-9][0-9]*/).respond(function(method, url, data) {
$httpBackend.whenPUT(/\.*\/clusters\/[1-9][0-9]*\/routing-table\/[1-9][0-9]/).respond(function(method, url, data) {
console.log(method, url, data);
var routingTable = JSON.parse(data);
@ -228,6 +262,7 @@ compassAppDev.run(function($httpBackend, settings, $http) {
console.log(routingTable);
return [200, routingTable, {}];
});
*/
$httpBackend.whenPOST(/\.*\/clusters\/[1-9][0-9]*\/action/).respond(function(method, url, data) {
console.log(method, url, data);
@ -243,10 +278,28 @@ compassAppDev.run(function($httpBackend, settings, $http) {
return [200, actionResponse, {}];
});
$httpBackend.whenPUT(/\.*\/hosts\/[1-9][0-9]*/).respond(function(method, url, data) {
console.log(method, url, data);
var host_config = JSON.parse(data);
return [200, host_config, {}];
});
$httpBackend.whenPOST(/\.*\/hosts\/[1-9][0-9]*\/network/).respond(function(method, url, data) {
console.log(method, url, data);
var network = JSON.parse(data);
network.id = Math.floor((Math.random() * 100) + 1);
return [200, network, {}];
});
$httpBackend.whenPUT(/\.*\/hosts\/[1-9][0-9]*\/network\/[1-9][0-9]/).respond(function(method, url, data) {
console.log(method, url, data);
var network = JSON.parse(data);
return [200, network, {}];
});
$httpBackend.whenPUT(/\.*\/clusters\/[1-9][0-9]*\/hosts\/[1-9][0-9]*\/config/).respond(function(method, url, data) {
console.log(method, url, data);
var config = JSON.parse(data);
return [200, config, {}];
});
});

View File

@ -58,6 +58,10 @@ angular.module('compass.services', [])
return $http.get(settings.apiUrlBase + '/adapters');
};
this.getAdapter = function(id) {
return $http.get(settings.apiUrlBase + '/adapters/' + id);
};
this.createCluster = function(cluster) {
return $http.post(settings.apiUrlBase + '/clusters', angular.toJson(cluster));
};
@ -70,18 +74,20 @@ angular.module('compass.services', [])
return $http.put(settings.apiUrlBase + '/clusters/' + id + '/config', angular.toJson(config));
};
this.getClusterSubnetConfig = function(id) {
return $http.get(settings.apiUrlBase + '/clusters/' + id + '/subnet-config');
this.getSubnetConfig = function() {
return $http.get(settings.apiUrlBase + '/subnetworks');
};
this.postClusterSubnetConfig = function(id, subnet_config) {
return $http.post(settings.apiUrlBase + '/clusters/' + id + '/subnet-config', angular.toJson(subnet_config));
this.postSubnetConfig = function(subnet_config) {
return $http.post(settings.apiUrlBase + '/subnetworks', angular.toJson(subnet_config));
};
this.putClusterSubnetConfig = function(id, subnetId, subnet_config) {
return $http.put(settings.apiUrlBase + '/clusters/' + id + '/subnet-config/' + subnetId, angular.toJson(subnet_config));
this.putSubnetConfig = function(id, subnet_config) {
return $http.put(settings.apiUrlBase + '/subnetworks/' + id, angular.toJson(subnet_config));
};
// keep routing table for later use
/*
this.postRoutingTable = function(id, routing_table) {
return $http.post(settings.apiUrlBase + '/clusters/' + id + '/routing-table', angular.toJson(routing_table));
};
@ -89,6 +95,7 @@ angular.module('compass.services', [])
this.putRoutingTable = function(id, routingId, routing_table) {
return $http.put(settings.apiUrlBase + '/clusters/' + id + '/routing-table/' + routingId, angular.toJson(routing_table));
};
*/
this.getTimezones = function() {
return $http.get(settings.metadataUrlBase + '/timezone.json');
@ -98,9 +105,21 @@ angular.module('compass.services', [])
return $http.post(settings.apiUrlBase + '/clusters/' + id + '/action', angular.toJson(actions));
};
this.putHost = function(id, config) {
return $http.put(settings.apiUrlBase + '/hosts/' + id, angular.toJson(config));
};
this.postHostNetwork = function(id, network) {
return $http.post(settings.apiUrlBase + '/hosts/' + id + '/network', angular.toJson(network));
};
this.putHostNetwork = function(id, networkId, network) {
return $http.put(settings.apiUrlBase + '/hosts/' + id + '/network/' + networkId, angular.toJson(network));
};
this.updateClusterHostConfig = function(clusterId, hostId, config) {
return $http.put(settings.apiUrlBase + '/hosts/' + clusterId + '/hosts/' + hostId + '/config', angular.toJson(config));
};
}
])
@ -121,20 +140,23 @@ angular.module('compass.services', [])
wizard.generalConfig = {};
wizard.interfaces = {};
wizard.partition = {};
wizard.server_credentials = {};
wizard.service_credentials = {};
wizard.management_credentials = {};
wizard.network_mapping = {};
};
wizard.init();
wizard.preConfig = function(config) {
wizard.setClusterInfo(config.cluster);
wizard.setSubnetworks(config.subnet);
wizard.setInterfaces(config.interface);
wizard.setGeneralConfig(config.general);
wizard.setPartition(config.partition);
wizard.setServerCredentials(config.server_credentials);
wizard.setServiceCredentials(config.service_credentials);
wizard.setManagementCredentials(config.management_credentials);
wizard.setNetworkMapping(config.network_mapping);
};
wizard.setClusterInfo = function(cluster) {
@ -142,7 +164,7 @@ angular.module('compass.services', [])
};
wizard.getClusterInfo = function() {
return wizard.cluster;
return angular.copy(wizard.cluster);
};
wizard.setSteps = function(steps) {
@ -150,7 +172,7 @@ angular.module('compass.services', [])
};
wizard.getSteps = function() {
return wizard.steps;
return angular.copy(wizard.steps);
};
wizard.setCommitState = function(commitState) {
@ -166,7 +188,7 @@ angular.module('compass.services', [])
};
wizard.getAllMachinesHost = function() {
return wizard.allServers;
return angular.copy(wizard.allServers);
};
wizard.setServers = function(servers) {
@ -174,7 +196,7 @@ angular.module('compass.services', [])
};
wizard.getServers = function() {
return wizard.servers;
return angular.copy(wizard.servers);
};
wizard.setAdapter = function(adapter) { ////
@ -182,7 +204,7 @@ angular.module('compass.services', [])
};
wizard.getAdapter = function() { /////
return wizard.adapter;
return angular.copy(wizard.adapter);
};
wizard.setGeneralConfig = function(config) {
@ -190,7 +212,7 @@ angular.module('compass.services', [])
};
wizard.getGeneralConfig = function() {
return wizard.generalConfig;
return angular.copy(wizard.generalConfig);
};
wizard.setSubnetworks = function(subnetworks) {
@ -198,9 +220,11 @@ angular.module('compass.services', [])
};
wizard.getSubnetworks = function() {
return wizard.subnetworks;
return angular.copy(wizard.subnetworks);
};
// keey routing table for later use
/*
wizard.setRoutingTable = function(routingTb) {
wizard.routingtable = routingTb;
};
@ -208,13 +232,14 @@ angular.module('compass.services', [])
wizard.getRoutingTable = function() {
return wizard.routingtable;
};
*/
wizard.setInterfaces = function(interfaces) {
wizard.interfaces = interfaces;
};
wizard.getInterfaces = function() {
return wizard.interfaces;
return angular.copy(wizard.interfaces);
};
wizard.setPartition = function(partition) {
@ -222,15 +247,22 @@ angular.module('compass.services', [])
};
wizard.getPartition = function() {
return wizard.partition;
return angular.copy(wizard.partition);
};
wizard.setServerCredentials = function(credentials) {
wizard.server_credentials = credentials;
};
wizard.getServerCredentials = function() {
return angular.copy(wizard.server_credentials);
}
wizard.setServiceCredentials = function(credentials) {
wizard.service_credentials = credentials;
};
wizard.getServiceCredentials = function() {
return wizard.service_credentials;
return angular.copy(wizard.service_credentials);
};
wizard.setManagementCredentials = function(credentials) {
@ -238,7 +270,15 @@ angular.module('compass.services', [])
};
wizard.getManagementCredentials = function() {
return wizard.management_credentials;
return angular.copy(wizard.management_credentials);
};
wizard.setNetworkMapping = function(mapping) {
wizard.network_mapping = mapping;
};
wizard.getNetworkMapping = function() {
return angular.copy(wizard.network_mapping);
};
return wizard;

View File

@ -22,15 +22,106 @@
<!--TODO: use json to generate inputs-->
<div class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">HTTP Proxy</label>
<label class="col-sm-4 control-label no-padding-right">
Language
<span class="text-danger">*</span>
</label>
<div class="col-sm-8">
<input ng-model="general.http_proxy" type="text" class="col-xs-10 col-sm-5" placeholder="HTTP Proxy" name="http_proxy">
<select ng-model="general.language" name="language" class="col-xs-10 col-sm-5">
<option value="en">English</option>
<option value="cn">Chinese</option>
</select>
</div>
</div>
</div>
<div class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">NTP Server</label>
<label class="col-sm-4 control-label no-padding-right">
Timezone
<span class="text-danger">*</span>
</label>
<div class="col-sm-8">
<select ng-model="general.timezone" name="timezone" class="col-xs-10 col-sm-5">
<option ng-repeat="tm in timezones" value="{{tm.value}}">(GMT {{tm.value}}) {{tm.timezone}}</option>
</select>
</div>
</div>
</div>
<div ng-repeat="http_proxy in general.http_proxy track by $index" class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">
<span ng-if="$index==0">
HTTP Proxy
<span class="text-danger opacity-zero">*</span>
</span>
</label>
<div class="col-sm-8">
<input ng-model="general.http_proxy[$index]" type="text" class="col-xs-10 col-sm-5" placeholder="HTTP Proxy" name="http_proxy">
<span class="col-xs-2 col-sm-3">
<!--Add Action-->
<span class="action" ng-click="addValue('http_proxy')">
<i class="fa fa-plus-circle bigger-140 blue"></i>
</span>
<!--Remove Action-->
<span ng-show="general.http_proxy.length > 1" class="action" ng-click="general.http_proxy.splice($index,1)">
<i class="fa fa-minus-circle bigger-140 blue"></i>
</span>
</span>
</div>
</div>
</div>
<div ng-repeat="https_proxy in general.https_proxy track by $index" class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">
<span ng-if="$index==0">
HTTPS Proxy
<span class="text-danger opacity-zero">*</span>
</span>
</label>
<div class="col-sm-8">
<input ng-model="general.https_proxy[$index]" type="text" class="col-xs-10 col-sm-5" placeholder="HTTPS Proxy" name="https_proxy">
<span class="col-xs-2 col-sm-3">
<!--Add Action-->
<span class="action" ng-click="addValue('https_proxy')">
<i class="fa fa-plus-circle bigger-140 blue"></i>
</span>
<!--Remove Action-->
<span ng-show="general.https_proxy.length > 1" class="action" ng-click="general.https_proxy.splice($index,1)">
<i class="fa fa-minus-circle bigger-140 blue"></i>
</span>
</span>
</div>
</div>
</div>
<div ng-repeat="no_proxy in general.default_no_proxy track by $index" class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">
<span ng-if="$index==0">
Default No Proxy
<span class="text-danger opacity-zero">*</span>
</span>
</label>
<div class="col-sm-8">
<input ng-model="general.default_no_proxy[$index]" type="text" class="col-xs-10 col-sm-5" placeholder="Default No Proxy" name="default_no_proxy">
<span class="col-xs-2 col-sm-3">
<!--Add Action-->
<span class="action" ng-click="addValue('default_no_proxy')">
<i class="fa fa-plus-circle bigger-140 blue"></i>
</span>
<!--Remove Action-->
<span ng-show="general.default_no_proxy.length > 1" class="action" ng-click="general.default_no_proxy.splice($index,1)">
<i class="fa fa-minus-circle bigger-140 blue"></i>
</span>
</span>
</div>
</div>
</div>
<div class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">
NTP Server
<span class="text-danger">*</span>
</label>
<div class="col-sm-8">
<input ng-model="general.ntp_server" type="text" class="col-xs-10 col-sm-5" placeholder="NTP Server" name="ntp_server">
</div>
@ -39,13 +130,16 @@
<div ng-repeat="dns_server in general.dns_servers track by $index" class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">
<span ng-if="$index==0">DNS Servers</span>
<span ng-if="$index==0">
DNS Servers
<span class="text-danger">*</span>
</span>
</label>
<div class="col-sm-8">
<input ng-model="general.dns_servers[$index]" type="text" class="col-xs-10 col-sm-5" placeholder="DNS Server" name="dns_servers">
<span class="col-xs-2 col-sm-3">
<!--Add Action-->
<span class="action" ng-click="addDNSServer()">
<span class="action" ng-click="addValue('dns_servers')">
<i class="fa fa-plus-circle bigger-140 blue"></i>
</span>
<!--Remove Action-->
@ -59,13 +153,16 @@
<div ng-repeat="search_path in general.search_path track by $index" class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">
<span ng-if="$index==0">Search Path</span>
<span ng-if="$index==0">
Search Path
<span class="text-danger">*</span>
</span>
</label>
<div class="col-sm-8">
<input ng-model="general.search_path[$index]" type="text" class="col-xs-10 col-sm-5" placeholder="Search Path" name="search_path">
<span class="col-xs-2 col-sm-3">
<!--Add Action-->
<span class="action" ng-click="addSearchPath()">
<span class="action" ng-click="addValue('search_path')">
<i class="fa fa-plus-circle bigger-140 blue"></i>
</span>
<!--Remove Action-->
@ -78,7 +175,10 @@
</div>
<div class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">Domain</label>
<label class="col-sm-4 control-label no-padding-right">
Domain
<span class="text-danger">*</span>
</label>
<div class="col-sm-8">
<input ng-model="general.domain" type="text" class="col-xs-10 col-sm-5" placeholder="Domain" name="domain">
</div>
@ -86,33 +186,16 @@
</div>
<div class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">Gateway</label>
<label class="col-sm-4 control-label no-padding-right">
Default Gateway
<span class="text-danger">*</span>
</label>
<div class="col-sm-8">
<input ng-model="general.gateway" type="text" class="col-xs-10 col-sm-5" placeholder="Gateway" name="gateway">
</div>
</div>
</div>
<div class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">Timezone</label>
<div class="col-sm-8">
<select ng-model="general.timezone" name="timezone" class="col-xs-10 col-sm-5">
<option ng-repeat="tm in timezones" value="{{tm.value}}">(GMT {{tm.value}}) {{tm.timezone}}</option>
</select>
</div>
</div>
</div>
<div class="form-group">
<div>
<label class="col-sm-4 control-label no-padding-right">Language</label>
<div class="col-sm-8">
<select ng-model="general.language" name="language" class="col-xs-10 col-sm-5">
<option value="en">English</option>
<option value="cn">Chinese</option>
</select>
<input ng-model="general.default_gateway" type="text" class="col-xs-10 col-sm-5" placeholder="Gateway" name="gateway">
</div>
</div>
</div>
</form>
</div>
</div>
@ -167,7 +250,8 @@
</accordion-group>
<accordion-group is-open="status.open">
<!--Keep routing table for later use-->
<!--<accordion-group is-open="status.open">
<accordion-heading>
<i class="ace-icon fa fa-angle-right" ng-class="{'fa-angle-down': status.open, 'fa-angle-right': !status.open}"></i> Routing Table
</accordion-heading>
@ -200,11 +284,9 @@
<input type="text" ng-model="route.gateway" placeholder="Gateway" />
</td>
<td>
<!--Add Action-->
<span class="action" ng-click="addRoute()">
<i class="fa fa-plus-circle bigger-140 blue"></i>
</span>
<!--Remove Action-->
<span ng-show="routingtable.length > 1" class="action" ng-click="removeRoute($index)">
<i class="fa fa-minus-circle bigger-140 blue"></i>
</span>
@ -217,7 +299,7 @@
<div class="col-sm-2">
</div>
</div>
</accordion-group>
</accordion-group>-->
</accordion>
</div>
</div>

View File

@ -25,77 +25,125 @@
</div>
</div>
<div class="pull-right">
<button class="btn btn-sm btn-info" ng-init="addInterface.isCollapsed = true;" ng-click="addInterface.isCollapsed = !addInterface.isCollapsed">Add Interface&nbsp;&nbsp;<i class="ace-icon fa fa-plus" ng-class="{'fa-minus': !addInterface.isCollapsed}"></i>
<button class="btn btn-sm btn-info" ng-init="addInterfacePanel.isCollapsed = true;" ng-click="addInterfacePanel.isCollapsed = !addInterfacePanel.isCollapsed">
Add Interface&nbsp;&nbsp;
<i class="ace-icon fa fa-plus" ng-class="{'fa-minus': !addInterfacePanel.isCollapsed}"></i>
</button>
<button class="btn btn-sm btn-info" ng-init="autoFill.isCollapsed = true;" ng-click="autoFill.isCollapsed = !autoFill.isCollapsed">
Autofill&nbsp;&nbsp;<i class="ace-icon fa fa-plus" ng-class="{'fa-minus': !autoFill.isCollapsed}"></i>
<button class="btn btn-sm btn-info" ng-init="autoFillPanel.isCollapsed = true;" ng-click="autoFillPanel.isCollapsed = !autoFillPanel.isCollapsed">
Autofill&nbsp;&nbsp;<i class="ace-icon fa fa-plus" ng-class="{'fa-minus': !autoFillPanel.isCollapsed}"></i>
</button>
</div>
</div>
<div class="row">
<div collapse="addInterface.isCollapsed">
<div class="well well-lg">
<div class="row">
<div class="col-xs-12">
<table class="table table-hover nowrap">
<thead>
<tr>
<th>Interface</th>
<th>Subnet</th>
<th>Is Mgmt Network</th>
<th>Action</th>
</tr>
</thead>
<tbody ng-init="network={};">
<tr>
<td>
<input type="text" ng-model="newInterface.name" placeholder="Interface" required />
</td>
<td>
<select ng-model="newInterface.subnet_id" class="max-width-200">
<option ng-repeat="sub in subnetworks" value="{{sub.subnet_id}}">
{{sub.name}}
</option>
</select>
</td>
<td>-</td>
<td>
<button type="button" class="btn btn-sm btn-info" ng-click="addInterface(newInterface)">
Add
</button>
</td>
</tr>
<tr ng-repeat="(name, value) in interfaces">
<td>
{{name}}
</td>
<td>
<span ng-repeat="sub in subnetworks">
<span ng-if="sub.subnet_id == value.subnet_id">{{sub.name}}</span>
</span>
</td>
<td>
<input ng-model="value.is_mgmt" type="checkbox" name="is-mgmt" />
</td>
<td>
<!--Remove Action-->
<button class="btn btn-xs btn-danger" ng-click="deleteInterface(name)"><i class="fa fa-trash-o bigger-120"></i>
</button>
</td>
</tr>
</tbody>
</table>
<div collapse="addInterfacePanel.isCollapsed">
<div class="widget-box">
<div class="widget-body">
<div class="widget-main">
<div class="row">
<div class="col-lg-2"></div>
<div class="col-lg-8">
<table class="table table-hover nowrap">
<thead>
<tr>
<th>Interface</th>
<th>Subnet</th>
<th>Is Mgmt Network</th>
<th>Action</th>
</tr>
</thead>
<tbody ng-init="network={};">
<tr>
<td>
<input type="text" ng-model="newInterface.name" placeholder="Interface" required />
</td>
<td>
<select ng-model="newInterface.subnet_id" class="max-width-200">
<option ng-repeat="sub in subnetworks" value="{{sub.subnet_id}}">
{{sub.name}}
</option>
</select>
</td>
<td>-</td>
<td>
<button type="button" class="btn btn-sm btn-info" ng-click="addInterface(newInterface)">
Add
</button>
</td>
</tr>
<tr ng-repeat="(name, value) in interfaces">
<td>
{{name}}
</td>
<td>
<span ng-repeat="sub in subnetworks">
<span ng-if="sub.subnet_id == value.subnet_id">{{sub.name}}</span>
</span>
</td>
<td>
<input ng-model="value.is_mgmt" type="checkbox" name="is-mgmt" />
</td>
<td>
<!--Remove Action-->
<button class="btn btn-xs btn-danger" ng-click="deleteInterface(name)"><i class="fa fa-trash-o bigger-120"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-lg-2"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div collapse="autoFill.isCollapsed">
<div class="well well-lg">
<div class="row">
<div class="col-xs-12">
Autofill Panel
<div collapse="autoFillPanel.isCollapsed">
<div class="widget-box">
<div class="widget-body">
<div class="widget-main">
<div class="row">
<div class="col-lg-2"></div>
<div class="col-lg-8">
<form role="form" class="form-horizontal ng-pristine ng-valid" id="autoForm">
<div class="form-group">
<div>
<label class="col-sm-3 control-label no-padding-right">
Hostname
</label>
<div class="col-sm-9">
<select class="col-xs-10 col-sm-5 ng-pristine ng-valid">
<option value="host">Host</option>
<option value="switch_ip">Switch IP</option>
<option value="switch_alias">Switch Alias</option>
</select>
</div>
</div>
</div>
<div ng-repeat="(name, value) in interfaces" class="form-group">
<label class="col-sm-3 control-label no-padding-right">
{{name}}&nbsp;IP
</label>
<div class="col-sm-9">
<input type="text" placeholder="IP Start">
<select>
<option value="1">Increase by 1</option>
<option value="2">Increase by 2</option>
<option value="3">Increase by 3</option>
<option value="4">Increase by 4</option>
<option value="5">Increase by 5</option>
</select>
</div>
</div>
<div class="col-sm-offset-4">
<button ng-click="autofill()" class="btn btn-sm btn-primary">
Fill Values
</button>
</div>
</form>
</div>
<div class="col-lg-2"></div>
</div>
</div>
</div>
</div>
@ -122,10 +170,10 @@
<tbody>
<tr ng-repeat="server in $data | filter: search" ng-init="serverIndex = $index">
<td ng-repeat="column in server_columns" ng-show="column.visible" sortable="column.field">
<span ng-if="column.field=='hostname'">
<span ng-if="column.field=='name'">
<input ng-model="server[column.field]" placeholder="Hostname" class="form-control margin-bottom-10 max-width-200" type="text">
</span>
<span ng-if="column.field!='hostname'">
<span ng-if="column.field!='name'">
{{server[column.field]}}
</span>

View File

@ -1,64 +1,45 @@
<div ng-controller="networkCtrl">
<div ng-controller="networkMappingCtrl">
<div class="row">
<div class="pull-left">
<span class="input-icon">
<input type="text" placeholder="Search" ng-model="search">
<i class="ace-icon fa fa-search blue"></i>
</span>
</div>
<div class="pull-right">
<div class="col-sm-6">
<div class="widget-box transparent margin-top-minus10">
<div class="widget-header">
<h4>Interfaces</h4>
</div>
<div class="widget-body">
<div class="widget-main">
<div ng-repeat="(interface_key, interface_value) in interfaces">
{{interface_key}}
<div ui-on-Drop="onDrop($event, interface_key)" drag-hover-class="drag-enter" class="interface-placeholder">
</div>
</div>
<div ng-repeat="(network_key, network_value) in networking" ui-draggable="true" on-drop-success="dropSuccessHandler($event, network_key, networking)" class="external-event label-purple ui-draggable network-draggable" ng-if="network_value.mapping_interface==interface_key">
<i class="ace-icon fa fa-arrows"></i>
{{network_value.display}}
</div>
</div>
<div class="row">{{servers}}
<table class="table table-hover table-striped">
<thead>
<tr>
<th>
<input type="checkbox">
</th>
<th>Host MAC</th>
<th>Switch IP</th>
<th>Port</th>
<th>Hostname</th>
<th>Management Network</th>
<th>Tenant Network</th>
<th>Storage Network</th>
<th>Public Network</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="server in servers | filter:search">
<td>
<input ng-model="server.checked" type="checkbox">
</td>
<td>{{server["mac"]}}</td>
<td>{{server["switch_ip"]}}</td>
<td>{{server["port"]}}</td>
<td>{{server["hostname"]}}</td>
<td>
<select ng-model="server.management">
<option ng-repeat="interface in interfaces" value="{{interface}}">{{interface}}</option>
</select>
</td>
<td>
<select ng-model="server.tenant">
<option ng-repeat="interface in interfaces" value="{{interface}}">{{interface}}</option>
</select>
</td>
<td>
<select ng-model="server.storage">
<option ng-repeat="interface in interfaces" value="{{interface}}">{{interface}}</option>
</select>
</td>
<td>
<select ng-model="server.public">
<option ng-repeat="interface in interfaces" value="{{interface}}">{{interface}}</option>
</select>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="widget-box transparent margin-top-minus10">
<div class="widget-header">
<h4>Networks</h4>
</div>
<div class="widget-body">
<div class="widget-main">
<div ui-on-Drop="onDrop($event, '')" drag-hover-class="drag-enter" class="network-placeholder">
<div ng-repeat="(key, value) in networking" ui-draggable="true" on-drop-success="dropSuccessHandler($event, key, networking)" class="external-event label-purple ui-draggable network-draggable" ng-if="!value.mapping_interface">
<i class="ace-icon fa fa-arrows"></i>
{{value.display}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,10 +1,28 @@
<div ng-controller="roleAssignCtrl">
<div class="row">
<div class="pull-left">
<!--Search Input-->
<span class="input-icon">
<input type="text" placeholder="Search" ng-model="search">
<input type="text" placeholder="Search" ng-model="search.$">
<i class="ace-icon fa fa-search blue"></i>
</span>
<!-- Column Show / Hide button -->
<div class="btn-group" dropdown>
<button type="button" class="btn btn-white btn-default dropdown-toggle">
Column Show / Hide
<span class="ace-icon fa fa-caret-down icon-on-right"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="column in server_columns" ng-click="column.visible=!column.visible">
<a class="action">
<span ng-class="{'opacity-zero': !column.visible}">
<i class="ace-icon fa fa-check blue"></i>
</span>
{{column.title}}
</a>
</li>
</ul>
</div>
</div>
<div class="pull-right">
<div class="btn-group" dropdown>
@ -14,7 +32,9 @@
</button>
<ul class="dropdown-menu dropdown-info dropdown-menu-right" role="menu">
<li ng-repeat="role in roles">
<a href value="{{role.name}}" ng-click="assignRole(role)">{{role.display_name}}</a>
<a class="action" ng-click="assignRole(role)">
{{role.display_name}}
</a>
</li>
</ul>
@ -23,29 +43,29 @@
</div>
<div class="row">
<table class="table table-hover table-striped">
<table ng-table="tableParams" class="table table-hover table-striped">
<thead>
<tr>
<th>
<input type="checkbox">
<input type="checkbox" ng-model="selectall" ng-change="selectAllServers(selectall)">
</th>
<th ng-repeat="column in server_columns" ng-show="column.visible" class="sortable"
ng-class="{'sort-asc': tableParams.isSortBy(column.field, 'asc'),
'sort-desc': tableParams.isSortBy(column.field, 'desc')}"
ng-click="tableParams.sorting(column.field, tableParams.isSortBy(column.field, 'asc') ? 'desc' : 'asc')">
{{column.title}}
</th>
<th>Host MAC</th>
<th>Switch IP</th>
<th>Port</th>
<th>Hostname</th>
<th>Roles</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="server in servers | filter:search">
<tr ng-repeat="server in $data | filter: search">
<td>
<input ng-model="server.checked" type="checkbox">
</td>
<td>{{server["mac"]}}</td>
<td>{{server["switch_ip"]}}</td>
<td>{{server["port"]}}</td>
<td>{{server["hostname"]}}</td>
<td ng-repeat="column in server_columns" ng-show="column.visible" sortable="column.field">
{{server[column.field]}}
</td>
<td>
<alert ng-repeat="role in server['roles']" class="role-tag" close="removeRole(server, role)">
{{role.display_name}}

View File

@ -14,19 +14,19 @@
<div class="form-group">
<label class="col-sm-4 control-label no-padding-right">Username</label>
<div class="col-sm-8">
<input type="text" class="col-xs-10 col-sm-5" placeholder="Username" id="server-username">
<input type="text" class="col-xs-10 col-sm-5" placeholder="Username" id="server-username" ng-model="server_credentials.username">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label no-padding-right">Password</label>
<div class="col-sm-8">
<input type="text" class="col-xs-10 col-sm-5" placeholder="Password" id="server-password">
<input type="password" class="col-xs-10 col-sm-5" placeholder="Password" id="server-password" ng-model="server_credentials.password">
</div>
</div>
<div class="form-group">
<label for="{{key}}" class="col-sm-4 control-label no-padding-right">Confirm Password</label>
<label class="col-sm-4 control-label no-padding-right">Confirm Password</label>
<div class="col-sm-8">
<input type="text" class="col-xs-10 col-sm-5" placeholder="Confirm Password" id="{{key}}">
<input type="password" class="col-xs-10 col-sm-5" placeholder="Confirm Password" value="{{server_credentials.password}}">
</div>
</div>
</form>
@ -36,12 +36,12 @@
<accordion-group is-open="status2.open">
<accordion-heading>
<i class="ace-icon fa fa-angle-right" ng-class="{'fa-angle-down': status2.open, 'fa-angle-right': !status2.open}"></i> OpenStack Services Credentials
<i class="ace-icon fa fa-angle-right" ng-class="{'fa-angle-down': status2.open, 'fa-angle-right': !status2.open}"></i> OpenStack Database & Queue Credentials
</accordion-heading>
<div class="row">
<div class="col-lg-2">
<div class="col-lg-1">
</div>
<div class="col-lg-8">
<div class="col-lg-10">
<table class="table table-hover nowrap">
<thead>
<tr>
@ -83,17 +83,19 @@
</tbody>
</table>
</div>
<div class="col-lg-2">
<div class="col-lg-1">
</div>
</div>
</accordion-group>
<accordion-group is-open="status.open">
<accordion-heading>
<i class="ace-icon fa fa-angle-right" ng-class="{'fa-angle-down': status.open, 'fa-angle-right': !status.open}"></i> OpenStack Management Console Credentials
<i class="ace-icon fa fa-angle-right" ng-class="{'fa-angle-down': status.open, 'fa-angle-right': !status.open}"></i> OpenStack Keystone User Credentials
</accordion-heading>
<div class="row">
<div class="col-xs-12">
<div class="col-lg-1">
</div>
<div class="col-lg-10">
<table class="table table-hover nowrap">
<thead>
<tr>
@ -136,6 +138,8 @@
</tbody>
</table>
</div>
<div class="col-lg-1">
</div>
</div>
</accordion-group>

View File

@ -2,7 +2,8 @@ angular.module('compass.wizard', [
'ui.router',
'ui.bootstrap',
'ngTable',
'compass.charts'
'compass.charts',
'ngDragDrop'
])
.config(function config($stateProvider) {
@ -15,14 +16,12 @@ angular.module('compass.wizard', [
})
.controller('wizardCtrl', function($scope, dataService, wizardFactory, $stateParams) {
if($stateParams.config == "true") {
if ($stateParams.config == "true") {
dataService.getWizardPreConfig().success(function(data) {
wizardFactory.preConfig(data);
});
wizardFactory.preConfig(data);
});
}
$scope.clusterInfo = wizardFactory.getClusterInfo();
// current step for create-cluster wizard
$scope.currentStep = 1;
@ -61,8 +60,6 @@ angular.module('compass.wizard', [
$scope.$watch(function() {
return wizardFactory.getCommitState()
}, function(newCommitState, oldCommitState) {
switch (newCommitState.name) {
case "sv_selection":
case "os_global":
@ -72,10 +69,11 @@ angular.module('compass.wizard', [
case "role_assign":
case "network_mapping":
if (newCommitState.name == $scope.steps[$scope.currentStep - 1].name && newCommitState.state == "success") {
console.info("### catch success in wizardCtrl ###", newCommitState, oldCommitState);
console.warn("### catch success in wizardCtrl ###", newCommitState, oldCommitState);
$scope.next();
} else if (newCommitState.state == "error") {
// TODO: error handling / display error message
console.warn("### catch error in wizardCtrl ###", newCommitState, oldCommitState);
}
break;
case "review":
@ -105,11 +103,14 @@ angular.module('compass.wizard', [
};
});
dataService.getAllMachineHosts().success(function(data) {
wizardFactory.setAllMachinesHost(data);
});
dataService.getSubnetConfig().success(function(data) {
wizardFactory.setSubnetworks(data);
});
})
.controller('svSelectCtrl', function($scope, wizardFactory, dataService, $filter, ngTableParams) {
@ -193,22 +194,34 @@ angular.module('compass.wizard', [
};
})
.controller('globalCtrl', function($scope, wizardFactory, dataService) {
.controller('globalCtrl', function($scope, wizardFactory, dataService, $q) {
var cluster = wizardFactory.getClusterInfo();
//For General Section
$scope.general = wizardFactory.getGeneralConfig();
//TODO: bug - should not set dns_servers and search_path to empty
$scope.general["dns_servers"] = [""];
$scope.general["search_path"] = [""];
if (!$scope.general["dns_servers"]) {
$scope.general["dns_servers"] = [""];
}
if (!$scope.general["search_path"]) {
$scope.general["search_path"] = [""];
}
if (!$scope.general["http_proxy"]) {
$scope.general["http_proxy"] = [""];
}
if (!$scope.general["https_proxy"]) {
$scope.general["https_proxy"] = [""];
}
if (!$scope.general["default_no_proxy"]) {
$scope.general["default_no_proxy"] = [""];
}
$scope.addDNSServer = function() {
$scope.general['dns_servers'].push("");
};
$scope.addSearchPath = function() {
$scope.general['search_path'].push("");
$scope.addValue = function(key) {
$scope.general[key].push("");
console.log($scope.general);
console.log($scope.general.http_proxy.length)
};
dataService.getTimezones().success(function(data) {
$scope.timezones = data;
});
@ -229,6 +242,8 @@ angular.module('compass.wizard', [
}, true);
//For Routing Table Section
//keep routing table for later use
/*
$scope.routingtable = wizardFactory.getRoutingTable();
$scope.addRoute = function() {
$scope.routingtable.push({});
@ -242,6 +257,7 @@ angular.module('compass.wizard', [
$scope.routingtable.push({});
}
}, true);
*/
$scope.$watch(function() {
return wizardFactory.getCommitState()
@ -255,63 +271,62 @@ angular.module('compass.wizard', [
});
$scope.commit = function() {
$scope.updateClusterConfig();
$scope.updateSubnet();
$scope.updateRoutingTable();
console.info("$$$$ ", wizardFactory.getSubnetworks(), wizardFactory.getRoutingTable(), wizardFactory.getGeneralConfig())
//TODO: should have check here to see if each part is updated successfully
var commitState = {
"name": "os_global",
"state": "success",
"message": ""
};
wizardFactory.setCommitState(commitState);
};
$scope.updateClusterConfig = function() {
var promises = [];
var os_global_general = {
"os_config": {
"general": $scope.general
}
};
// put cluster config
dataService.updateClusterConfig(cluster.id, os_global_general).success(function(configData) {
wizardFactory.setGeneralConfig(configData["os_config"]["general"]);
var updateClusterConfig = dataService.updateClusterConfig(cluster.id, os_global_general).then(function(configData) {
wizardFactory.setGeneralConfig(configData.data["os_config"]["general"]);
}, function(response) {
return $q.reject(response);
});
promises.push(updateClusterConfig);
var subnetworks = [];
angular.forEach($scope.subnetworks, function(subnet) {
if (subnet.subnet_id === undefined) {
// post subnetworks
var updateSubnetConfig = dataService.postSubnetConfig(subnet).then(function(subnetData) {
subnetworks.push(subnetData.data);
}, function(response) {
return $q.reject(response);
});
promises.push(updateSubnetConfig);
} else {
// put subnetworks
var updateSubnetConfig = dataService.putSubnetConfig(subnet.subnet_id, subnet).then(function(subnetData) {
subnetworks.push(subnetData.data);
}, function(response) {
return $q.reject(response);
});
promises.push(updateSubnetConfig);
}
});
$q.all(promises).then(function() {
$scope.subnetworks = subnetworks;
wizardFactory.setSubnetworks($scope.subnetworks);
var commitState = {
"name": "os_global",
"state": "success",
"message": ""
};
wizardFactory.setCommitState(commitState);
}, function(response) {
console.log("promises error", response);
var commitState = {
"name": "os_global",
"state": "error",
"message": response.statusText
};
wizardFactory.setCommitState(commitState);
});
};
$scope.updateSubnet = function() {
var subnetCount = $scope.subnetworks.length;
var subnetworks = [];
var i = 0;
angular.forEach($scope.subnetworks, function(subnet) {
if (subnet.subnet_id === undefined) {
// post cluster subnet-config
dataService.postClusterSubnetConfig(cluster.id, subnet).success(function(subnetData) {
subnetworks.push(subnetData);
i++;
if (i == subnetCount) {
$scope.subnetworks = subnetworks;
wizardFactory.setSubnetworks($scope.subnetworks);
}
})
} else {
// put cluster subnet-config
dataService.putClusterSubnetConfig(cluster.id, subnet.subnet_id, subnet).success(function(subnetData) {
subnetworks.push(subnetData);
i++;
if (i == subnetCount) {
$scope.subnetworks = subnetworks;
wizardFactory.setSubnetworks($scope.subnetworks);
}
})
}
})
};
// keey routing table for later use
/*
$scope.updateRoutingTable = function() {
var routingCount = $scope.routingtable.length;
var routingTable = [];
@ -340,9 +355,10 @@ angular.module('compass.wizard', [
}
})
};
*/
})
.controller('networkCtrl', function($scope, wizardFactory, dataService, $filter, ngTableParams) {
.controller('networkCtrl', function($scope, wizardFactory, dataService, $filter, ngTableParams, $q) {
var cluster = wizardFactory.getClusterInfo();
$scope.subnetworks = wizardFactory.getSubnetworks();
$scope.interfaces = wizardFactory.getInterfaces();
@ -391,27 +407,29 @@ angular.module('compass.wizard', [
})
};
$scope.initHostIpByInterface = function(interfaceName) {
if ($scope.servers.network[interfaceName] === undefinded) {
$scope.servers.network[interfaceName] = {};
$scope.$watch('addInterfacePanel', function(value) {
if (!$scope.addInterfacePanel.isCollapsed) {
$scope.autoFillPanel.isCollapsed = true;
}
};
}, true);
$scope.$watch('autoFillPanel', function(value) {
if (!$scope.autoFillPanel.isCollapsed) {
$scope.addInterfacePanel.isCollapsed = true;
}
}, true);
$scope.$watch(function() {
return wizardFactory.getCommitState()
}, function(newCommitState, oldCommitState) {
console.info("### catch commit change in networkCtrl ###", newCommitState);
if (newCommitState !== undefined) {
if (newCommitState.name == "network" && newCommitState.state == "triggered") {
$scope.commitNetwork();
} else if (newCommitState.name == "network_mapping" && newCommitState.state == "triggered") {
$scope.commitNetworkMapping();
$scope.commit();
}
}
});
$scope.commitNetwork = function() {
$scope.commit = function() {
var addHostsAction = {
"add_hosts": {
"machines": []
@ -445,13 +463,23 @@ angular.module('compass.wizard', [
}
}
}
wizardFactory.setServers($scope.servers);
$scope.serverCount = $scope.servers.length;
var i = 0;
// post host network
var hostnamePromises = [];
var hostNetworkPromises = [];
angular.forEach($scope.servers, function(server) {
$scope.networkCount = Object.keys(server.network).length;
var hostname = {
"name": server["name"]
};
// update hostname
var updateHostname = dataService.putHost(server.host_id, hostname).then(function(hostData) {
// success callback
}, function(response) {
// error callback
return $q.reject(response);
});
hostnamePromises.push(updateHostname);
angular.forEach(server.network, function(value, key) {
var network = {
"interface": key,
@ -459,39 +487,58 @@ angular.module('compass.wizard', [
"subnet_id": $scope.interfaces[key].subnet_id,
"is_mgmt": $scope.interfaces[key].is_mgmt
};
if (value.id === undefined) {
// post host network
var updateNetwork = dataService.postHostNetwork(server.host_id, network).then(function(networkData) {
// success callback
console.log("post networkdata", networkData.data);
var interface = networkData.data.interface;
var networkId = networkData.data.id;
server.network[interface].id = networkId;
}, function(response) {
// error callback
return $q.reject(response);
});
hostNetworkPromises.push(updateNetwork);
} else {
// put host network
var updateNetwork = dataService.putHostNetwork(server.host_id, value.id, network).then(function(networkData) {
// success callback
console.log("put networkdata", networkData.data);
}, function(response) {
// error callback
return $q.reject(response);
});
hostNetworkPromises.push(updateNetwork);
}
});
});
dataService.postHostNetwork(server.host_id, network).success(function(data) {
i++;
if (i == $scope.serverCount * $scope.networkCount) {
wizardFactory.setInterfaces($scope.interfaces);
wizardFactory.setServers($scope.servers);
var commitState = {
"name": "network",
"state": "success",
"message": ""
};
wizardFactory.setCommitState(commitState);
}
});
})
$q.all(hostnamePromises.concat(hostNetworkPromises)).then(function() {
// update hostname and network for all hosts successfully
wizardFactory.setServers($scope.servers);
var commitState = {
"name": "network",
"state": "success",
"message": ""
};
wizardFactory.setCommitState(commitState);
}, function(response) {
var commitState = {
"name": "network",
"state": "error",
"message": response.statusText
};
wizardFactory.setCommitState(commitState);
});
});
}
};
$scope.commitNetworkMapping = function() {
var commitState = {
"name": "network_mapping",
"state": "success",
"message": ""
};
wizardFactory.setCommitState(commitState);
};
$scope.autofill = function() {
//TODO: add auto fill
alert("Autofill coming soon");
}
};
})
.controller('partitionCtrl', function($scope, wizardFactory, dataService) {
@ -511,7 +558,6 @@ angular.module('compass.wizard', [
};
$scope.$watch('partition', function() {
console.log("changed")
$scope.partitionarray = [];
angular.forEach($scope.partition, function(value, key) {
$scope.partitionarray.push({
@ -524,7 +570,6 @@ angular.module('compass.wizard', [
$scope.$watch(function() {
return wizardFactory.getCommitState()
}, function(newCommitState, oldCommitState) {
console.info("### catch commit change in partitionCtrl ###", newCommitState);
if (newCommitState !== undefined) {
if (newCommitState.name == "partition" && newCommitState.state == "triggered") {
$scope.commit();
@ -553,13 +598,13 @@ angular.module('compass.wizard', [
.controller('securityCtrl', function($scope, wizardFactory, dataService) {
var cluster = wizardFactory.getClusterInfo();
$scope.server_credentials = wizardFactory.getServerCredentials();
$scope.service_credentials = wizardFactory.getServiceCredentials();
$scope.management_credentials = wizardFactory.getManagementCredentials();
$scope.$watch(function() {
return wizardFactory.getCommitState()
}, function(newCommitState, oldCommitState) {
console.info("### catch commit change in securityCtrl ###", newCommitState);
if (newCommitState !== undefined) {
if (newCommitState.name == "security" && newCommitState.state == "triggered") {
$scope.commit();
@ -568,8 +613,19 @@ angular.module('compass.wizard', [
});
$scope.commit = function() {
var partitionData = {};
dataService.updateClusterConfig(cluster.id, partitionData).success(function(data) {
var securityData = {
"os_config": {
"username": $scope.server_credentials.username,
"password": $scope.server_credentials.password
},
"package_config": {
"security": {
"service_credentials": $scope.service_credentials,
"console_crendentials": $scope.management_credentials
}
}
};
dataService.updateClusterConfig(cluster.id, securityData).success(function(data) {
var commitState = {
"name": "security",
"state": "success",
@ -580,11 +636,30 @@ angular.module('compass.wizard', [
};
})
.controller('roleAssignCtrl', function($scope, wizardFactory, dataService) {
.controller('roleAssignCtrl', function($scope, wizardFactory, dataService, $filter, ngTableParams, $q) {
var cluster = wizardFactory.getClusterInfo();
$scope.servers = wizardFactory.getServers();
$scope.roles = wizardFactory.getAdapter().roles;
dataService.getAdapter(cluster.adapter_id).success(function(data) {
wizardFactory.setAdapter(data);
$scope.roles = data.roles;
});
dataService.getServerColumns().success(function(data) {
$scope.server_columns = data.showless;
});
$scope.selectAllServers = function(flag) {
if (flag) {
angular.forEach($scope.servers, function(sv) {
sv.checked = true;
})
} else {
angular.forEach($scope.servers, function(sv) {
sv.checked = false;
})
}
};
$scope.removeRole = function(server, role) {
var serverIndex = $scope.servers.indexOf(server);
@ -593,28 +668,52 @@ angular.module('compass.wizard', [
};
$scope.assignRole = function(role) {
// get selected servers and assign role to them
var roleExist = false;
var serverChecked = false;
for (var i = 0; i < $scope.servers.length; i++) {
if ($scope.servers[i].checked) {
for (var j = 0; j < $scope.servers[i].roles.length; j++) {
if (role.name == $scope.servers[i].roles[j].name) {
roleExist = true;
serverChecked = true;
}
}
if (!serverChecked) {
alert("Please select at least one server");
} else {
// get selected servers and assign role to them
var roleExist = false;
for (var i = 0; i < $scope.servers.length; i++) {
if ($scope.servers[i].checked) {
for (var j = 0; j < $scope.servers[i].roles.length; j++) {
if (role.name == $scope.servers[i].roles[j].name) {
roleExist = true;
}
}
if (!roleExist) {
$scope.servers[i].roles.push(role);
} else {
roleExist = false;
}
}
}
if (!roleExist) {
$scope.servers[i].roles.push(role);
} else {
roleExist = false;
}
}
};
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: $scope.servers.length + 1 // count per page
}, {
counts: [], // hide count-per-page box
total: $scope.servers.length, // length of data
getData: function($defer, params) {
// use build-in angular filter
var orderedData = params.sorting() ?
$filter('orderBy')($scope.servers, params.orderBy()) : $scope.servers;
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
$scope.$watch(function() {
return wizardFactory.getCommitState()
}, function(newCommitState, oldCommitState) {
console.info("### catch commit change in networkCtrl ###", newCommitState);
if (newCommitState !== undefined) {
if (newCommitState.name == "role_assign" && newCommitState.state == "triggered") {
$scope.commit();
@ -623,11 +722,90 @@ angular.module('compass.wizard', [
});
$scope.commit = function() {
var commitState = {
"name": "role_assign",
"state": "success",
"message": ""
};
wizardFactory.setCommitState(commitState);
var promises = [];
angular.forEach($scope.servers, function(server) {
var roles = [];
angular.forEach(server.roles, function(role) {
roles.push(role.name);
});
var config = {
"package_config": {
"roles": roles
}
};
var updateRoles = dataService.updateClusterHostConfig(cluster.id, server.host_id, config).then(function(configData) {
// success callback
}, function(response) {
// error callback
return $q.reject(response);
});
});
$q.all(promises).then(function() {
wizardFactory.setServers($scope.servers);
var commitState = {
"name": "role_assign",
"state": "success",
"message": ""
};
wizardFactory.setCommitState(commitState);
}, function(response) {
console.log("promises error", response);
var commitState = {
"name": "role_assign",
"state": "error",
"message": response.statusText
};
wizardFactory.setCommitState(commitState);
});
};
})
.controller('networkMappingCtrl', function($scope, wizardFactory, dataService) {
var cluster = wizardFactory.getClusterInfo();
$scope.interfaces = wizardFactory.getInterfaces();
$scope.networking = wizardFactory.getNetworkMapping();
$scope.pendingInterface = "";
$scope.onDrop = function($event, key) {
$scope.pendingInterface = key;
};
$scope.dropSuccessHandler = function($event, key, dict) {
dict[key].mapping_interface = $scope.pendingInterface;
};
$scope.$watch(function() {
return wizardFactory.getCommitState()
}, function(newCommitState, oldCommitState) {
if (newCommitState !== undefined) {
if (newCommitState.name == "network_mapping" && newCommitState.state == "triggered") {
$scope.commit();
}
}
});
$scope.commit = function() {
var networks = {};
angular.forEach($scope.networking, function(value, key) {
networks[key] = value.mapping_interface;
});
var network_mapping = {
"package_config": {
"network_mapping": networks
}
};
dataService.updateClusterConfig(cluster.id, network_mapping).success(function(data) {
wizardFactory.setNetworkMapping($scope.networking);
var commitState = {
"name": "network_mapping",
"state": "success",
"message": ""
};
wizardFactory.setCommitState(commitState);
});
//TODO: error handling
};
})

View File

@ -0,0 +1,201 @@
/**
* Created with IntelliJ IDEA.
* User: Ganaraj.Pr
* Date: 11/10/13
* Time: 11:27
* To change this template use File | Settings | File Templates.
*/
if (window.jQuery && (-1 == window.jQuery.event.props.indexOf("dataTransfer"))) {
window.jQuery.event.props.push("dataTransfer");
}
angular.module("ngDragDrop",[])
.directive("uiDraggable", [
'$parse',
'$rootScope',
function ($parse, $rootScope) {
return function (scope, element, attrs) {
var dragData = "",
isDragHandleUsed = false,
dragHandleClass,
dragHandles,
dragTarget;
element.attr("draggable", false);
attrs.$observe("uiDraggable", function (newValue) {
element.attr("draggable", newValue);
});
if (attrs.drag) {
scope.$watch(attrs.drag, function (newValue) {
dragData = newValue || "";
});
}
if (angular.isString(attrs.dragHandleClass)) {
isDragHandleUsed = true;
dragHandleClass = attrs.dragHandleClass.trim() || "drag-handle";
dragHandles = element.find('.' + dragHandleClass).toArray();
element.bind("mousedown", function (e) {
dragTarget = e.target;
});
}
element.bind("dragstart", function (e) {
var isDragAllowed = !isDragHandleUsed || -1 != dragHandles.indexOf(dragTarget);
if (isDragAllowed) {
var sendData = angular.toJson(dragData);
var sendChannel = attrs.dragChannel || "defaultchannel";
var dragImage = attrs.dragImage || null;
if (dragImage) {
var dragImageFn = $parse(attrs.dragImage);
scope.$apply(function() {
var dragImageParameters = dragImageFn(scope, {$event: e});
if (dragImageParameters && dragImageParameters.image) {
var xOffset = dragImageParameters.xOffset || 0,
yOffset = dragImageParameters.yOffset || 0;
e.dataTransfer.setDragImage(dragImageParameters.image, xOffset, yOffset);
}
});
}
e.dataTransfer.setData("text/plain", sendData);
e.dataTransfer.effectAllowed = "copyMove";
$rootScope.$broadcast("ANGULAR_DRAG_START", sendChannel);
}
else {
e.preventDefault();
}
});
element.bind("dragend", function (e) {
var sendChannel = attrs.dragChannel || "defaultchannel";
$rootScope.$broadcast("ANGULAR_DRAG_END", sendChannel);
if (e.dataTransfer && e.dataTransfer.dropEffect !== "none") {
if (attrs.onDropSuccess) {
var fn = $parse(attrs.onDropSuccess);
scope.$apply(function () {
fn(scope, {$event: e});
});
}
}
});
};
}
])
.directive("uiOnDrop", [
'$parse',
'$rootScope',
function ($parse, $rootScope) {
return function (scope, element, attr) {
var dragging = 0; //Ref. http://stackoverflow.com/a/10906204
var dropChannel = "defaultchannel";
var dragChannel = "";
var dragEnterClass = attr.dragEnterClass || "on-drag-enter";
var dragHoverClass = attr.dragHoverClass || "on-drag-hover";
function onDragOver(e) {
if (e.preventDefault) {
e.preventDefault(); // Necessary. Allows us to drop.
}
if (e.stopPropagation) {
e.stopPropagation();
}
e.dataTransfer.dropEffect = e.shiftKey ? 'copy' : 'move';
return false;
}
function onDragLeave(e) {
dragging--;
if (dragging == 0) {
element.removeClass(dragHoverClass);
}
}
function onDragEnter(e) {
dragging++;
$rootScope.$broadcast("ANGULAR_HOVER", dropChannel);
element.addClass(dragHoverClass);
}
function onDrop(e) {
if (e.preventDefault) {
e.preventDefault(); // Necessary. Allows us to drop.
}
if (e.stopPropagation) {
e.stopPropagation(); // Necessary. Allows us to drop.
}
var data = e.dataTransfer.getData("text/plain");
data = angular.fromJson(data);
var fn = $parse(attr.uiOnDrop);
scope.$apply(function () {
fn(scope, {$data: data, $event: e});
});
element.removeClass(dragEnterClass);
}
function isDragChannelAccepted(dragChannel, dropChannel) {
if (dropChannel === "*") {
return true;
}
var channelMatchPattern = new RegExp("(\\s|[,])+(" + dragChannel + ")(\\s|[,])+", "i");
return channelMatchPattern.test("," + dropChannel + ",");
}
$rootScope.$on("ANGULAR_DRAG_START", function (event, channel) {
dragChannel = channel;
if (isDragChannelAccepted(dragChannel, dropChannel)) {
element.bind("dragover", onDragOver);
element.bind("dragenter", onDragEnter);
element.bind("dragleave", onDragLeave);
element.bind("drop", onDrop);
element.addClass(dragEnterClass);
}
});
$rootScope.$on("ANGULAR_DRAG_END", function (e, channel) {
dragChannel = "";
if (isDragChannelAccepted(channel, dropChannel)) {
element.unbind("dragover", onDragOver);
element.unbind("dragenter", onDragEnter);
element.unbind("dragleave", onDragLeave);
element.unbind("drop", onDrop);
element.removeClass(dragHoverClass);
element.removeClass(dragEnterClass);
}
});
$rootScope.$on("ANGULAR_HOVER", function (e, channel) {
if (isDragChannelAccepted(channel, dropChannel)) {
element.removeClass(dragHoverClass);
}
});
attr.$observe('dropChannel', function (value) {
if (value) {
dropChannel = value;
}
});
};
}
]);