CLOUDSTACK-7882: SSH Keypair Creation/Selection in UI Thanks Ilia Shakitko for the porting and testing.
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/19e99848 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/19e99848 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/19e99848 Branch: refs/heads/hotfix/scp-exception Commit: 19e99848c83eca52e5bb980cd6d0632ca73c5525 Parents: ff15320 Author: Wei Zhou <w.z...@tech.leaseweb.com> Authored: Fri Dec 12 14:30:34 2014 +0100 Committer: Wei Zhou <w.z...@tech.leaseweb.com> Committed: Fri Dec 12 14:30:34 2014 +0100 ---------------------------------------------------------------------- .../cloudstack/api/ResponseGenerator.java | 3 + .../command/user/ssh/CreateSSHKeyPairCmd.java | 2 +- .../command/user/ssh/ListSSHKeyPairsCmd.java | 2 +- .../command/user/ssh/RegisterSSHKeyPairCmd.java | 2 +- .../api/command/user/vm/ListVMsCmd.java | 7 + .../api/response/SSHKeyPairResponse.java | 20 ++ .../classes/resources/messages.properties | 1 + server/src/com/cloud/api/ApiResponseHelper.java | 16 ++ .../com/cloud/api/query/QueryManagerImpl.java | 9 + server/src/com/cloud/server/Criteria.java | 1 + .../com/cloud/server/ManagementServerImpl.java | 12 +- ui/css/cloudstack3.css | 12 +- ui/dictionary.jsp | 1 + ui/index.jsp | 29 +- ui/scripts/accounts.js | 281 ++++++++++++++++++- ui/scripts/instanceWizard.js | 24 +- ui/scripts/instances.js | 107 ++++++- ui/scripts/ui-custom/instanceWizard.js | 47 +++- ui/scripts/ui/widgets/listView.js | 4 + 19 files changed, 567 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/api/src/org/apache/cloudstack/api/ResponseGenerator.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index 10fb6df..1cc5bc8 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -84,6 +84,7 @@ import org.apache.cloudstack.api.response.RemoteAccessVpnResponse; import org.apache.cloudstack.api.response.ResourceCountResponse; import org.apache.cloudstack.api.response.ResourceLimitResponse; import org.apache.cloudstack.api.response.ResourceTagResponse; +import org.apache.cloudstack.api.response.SSHKeyPairResponse; import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.ServiceResponse; @@ -186,6 +187,7 @@ import com.cloud.storage.snapshot.SnapshotPolicy; import com.cloud.storage.snapshot.SnapshotSchedule; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; +import com.cloud.user.SSHKeyPair; import com.cloud.user.User; import com.cloud.user.UserAccount; import com.cloud.uservm.UserVm; @@ -446,4 +448,5 @@ public interface ResponseGenerator { ListResponse<UpgradeRouterTemplateResponse> createUpgradeRouterTemplateResponse(List<Long> jobIds); + SSHKeyPairResponse createSSHKeyPairResponse(SSHKeyPair sshkeyPair, boolean privatekey); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/api/src/org/apache/cloudstack/api/command/user/ssh/CreateSSHKeyPairCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/user/ssh/CreateSSHKeyPairCmd.java b/api/src/org/apache/cloudstack/api/command/user/ssh/CreateSSHKeyPairCmd.java index bd7f613..c275f80 100644 --- a/api/src/org/apache/cloudstack/api/command/user/ssh/CreateSSHKeyPairCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/ssh/CreateSSHKeyPairCmd.java @@ -91,7 +91,7 @@ public class CreateSSHKeyPairCmd extends BaseCmd { @Override public void execute() { SSHKeyPair r = _mgr.createSSHKeyPair(this); - CreateSSHKeyPairResponse response = new CreateSSHKeyPairResponse(r.getName(), r.getFingerprint(), r.getPrivateKey()); + CreateSSHKeyPairResponse response = (CreateSSHKeyPairResponse) _responseGenerator.createSSHKeyPairResponse(r, true); response.setResponseName(getCommandName()); response.setObjectName("keypair"); setResponseObject(response); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/api/src/org/apache/cloudstack/api/command/user/ssh/ListSSHKeyPairsCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/user/ssh/ListSSHKeyPairsCmd.java b/api/src/org/apache/cloudstack/api/command/user/ssh/ListSSHKeyPairsCmd.java index 022cbc5..1a77a66 100644 --- a/api/src/org/apache/cloudstack/api/command/user/ssh/ListSSHKeyPairsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/ssh/ListSSHKeyPairsCmd.java @@ -68,7 +68,7 @@ public class ListSSHKeyPairsCmd extends BaseListProjectAndAccountResourcesCmd { Pair<List<? extends SSHKeyPair>, Integer> resultList = _mgr.listSSHKeyPairs(this); List<SSHKeyPairResponse> responses = new ArrayList<SSHKeyPairResponse>(); for (SSHKeyPair result : resultList.first()) { - SSHKeyPairResponse r = new SSHKeyPairResponse(result.getName(), result.getFingerprint()); + SSHKeyPairResponse r = _responseGenerator.createSSHKeyPairResponse(result, false); r.setObjectName("sshkeypair"); responses.add(r); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/api/src/org/apache/cloudstack/api/command/user/ssh/RegisterSSHKeyPairCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/user/ssh/RegisterSSHKeyPairCmd.java b/api/src/org/apache/cloudstack/api/command/user/ssh/RegisterSSHKeyPairCmd.java index c7cbc56..ed9c4cd 100644 --- a/api/src/org/apache/cloudstack/api/command/user/ssh/RegisterSSHKeyPairCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/ssh/RegisterSSHKeyPairCmd.java @@ -99,7 +99,7 @@ public class RegisterSSHKeyPairCmd extends BaseCmd { @Override public void execute() { SSHKeyPair result = _mgr.registerSSHKeyPair(this); - SSHKeyPairResponse response = new SSHKeyPairResponse(result.getName(), result.getFingerprint()); + SSHKeyPairResponse response = _responseGenerator.createSSHKeyPairResponse(result, false); response.setResponseName(getCommandName()); response.setObjectName("keypair"); setResponseObject(response); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/api/src/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java index 76e3db0..3d50fbe 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java @@ -120,6 +120,9 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.AFFINITY_GROUP_ID, type = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "list vms by affinity group") private Long affinityGroupId; + @Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING, description = "list vms by ssh keypair name") + private String keypair; + @Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = ServiceOfferingResponse.class, description = "list by the service offering", since = "4.4") private Long serviceOffId; @@ -184,6 +187,10 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd { return affinityGroupId; } + public String getKeyPairName() { + return keypair; + } + public EnumSet<VMDetails> getDetails() throws InvalidParameterValueException { EnumSet<VMDetails> dv; if (viewDetails == null || viewDetails.size() <= 0) { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/api/src/org/apache/cloudstack/api/response/SSHKeyPairResponse.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/response/SSHKeyPairResponse.java b/api/src/org/apache/cloudstack/api/response/SSHKeyPairResponse.java index 4e1d314..9121957 100644 --- a/api/src/org/apache/cloudstack/api/response/SSHKeyPairResponse.java +++ b/api/src/org/apache/cloudstack/api/response/SSHKeyPairResponse.java @@ -29,6 +29,15 @@ public class SSHKeyPairResponse extends BaseResponse { @Param(description = "Name of the keypair") private String name; + @SerializedName(ApiConstants.ACCOUNT) @Param(description="the owner of the keypair") + private String accountName; + + @SerializedName(ApiConstants.DOMAIN_ID) @Param(description="the domain id of the keypair owner") + private String domainId; + + @SerializedName(ApiConstants.DOMAIN) @Param(description="the domain name of the keypair owner") + private String domain; + @SerializedName("fingerprint") @Param(description = "Fingerprint of the public key") private String fingerprint; @@ -57,4 +66,15 @@ public class SSHKeyPairResponse extends BaseResponse { this.fingerprint = fingerprint; } + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public void setDomainName(String domain) { + this.domain = domain; + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/client/WEB-INF/classes/resources/messages.properties ---------------------------------------------------------------------- diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 53ca37c..2f1d8fc 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -827,6 +827,7 @@ label.menu.templates=Templates label.menu.virtual.appliances=Virtual Appliances label.menu.virtual.resources=Virtual Resources label.menu.volumes=Volumes +label.menu.sshkeypair=SSH KeyPair label.migrate.instance.to.host=Migrate instance to another host label.migrate.instance.to.ps=Migrate instance to another primary storage label.migrate.instance.to=Migrate instance to http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/server/src/com/cloud/api/ApiResponseHelper.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index f4be820..89c1eb7 100644 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -58,6 +58,7 @@ import org.apache.cloudstack.api.response.ControlledEntityResponse; import org.apache.cloudstack.api.response.ControlledViewEntityResponse; import org.apache.cloudstack.api.response.CounterResponse; import org.apache.cloudstack.api.response.CreateCmdResponse; +import org.apache.cloudstack.api.response.CreateSSHKeyPairResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.DomainRouterResponse; @@ -105,6 +106,7 @@ import org.apache.cloudstack.api.response.RemoteAccessVpnResponse; import org.apache.cloudstack.api.response.ResourceCountResponse; import org.apache.cloudstack.api.response.ResourceLimitResponse; import org.apache.cloudstack.api.response.ResourceTagResponse; +import org.apache.cloudstack.api.response.SSHKeyPairResponse; import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.SecurityGroupRuleResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; @@ -291,6 +293,7 @@ import com.cloud.storage.snapshot.SnapshotSchedule; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.SSHKeyPair; import com.cloud.user.User; import com.cloud.user.UserAccount; import com.cloud.uservm.UserVm; @@ -3654,4 +3657,17 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } + @Override + public SSHKeyPairResponse createSSHKeyPairResponse(SSHKeyPair sshkeyPair, boolean privatekey) { + SSHKeyPairResponse response = new SSHKeyPairResponse(sshkeyPair.getName(), sshkeyPair.getFingerprint()); + if (privatekey) { + response = new CreateSSHKeyPairResponse(sshkeyPair.getName(), sshkeyPair.getFingerprint(), sshkeyPair.getPrivateKey()); + } + Account account = ApiDBUtils.findAccountById(sshkeyPair.getAccountId()); + response.setAccountName(account.getAccountName()); + Domain domain = ApiDBUtils.findDomainById(sshkeyPair.getDomainId()); + response.setDomainId(domain.getUuid()); + response.setDomainName(domain.getName()); + return response; + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/server/src/com/cloud/api/query/QueryManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 9d97f3b..634b065 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -835,6 +835,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { Object isoId = cmd.getIsoId(); Object vpcId = cmd.getVpcId(); Object affinityGroupId = cmd.getAffinityGroupId(); + Object keyPairName = cmd.getKeyPairName(); Object serviceOffId = cmd.getServiceOfferingId(); Object pod = null; Object hostId = null; @@ -886,6 +887,10 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sb.and("affinityGroupId", sb.entity().getAffinityGroupId(), SearchCriteria.Op.EQ); } + if (keyPairName != null) { + sb.and("keyPairName", sb.entity().getKeypairName(), SearchCriteria.Op.EQ); + } + if (!isRootAdmin) { sb.and("displayVm", sb.entity().isDisplayVm(), SearchCriteria.Op.EQ); } @@ -978,6 +983,10 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sc.setParameters("affinityGroupId", affinityGroupId); } + if (keyPairName != null) { + sc.setParameters("keyPairName", keyPairName); + } + if (cmd instanceof ListVMsCmdByAdmin) { ListVMsCmdByAdmin aCmd = (ListVMsCmdByAdmin)cmd; if (aCmd.getPodId() != null) { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/server/src/com/cloud/server/Criteria.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/server/Criteria.java b/server/src/com/cloud/server/Criteria.java index 02bafa7..47b7996 100644 --- a/server/src/com/cloud/server/Criteria.java +++ b/server/src/com/cloud/server/Criteria.java @@ -86,6 +86,7 @@ public class Criteria { public static final String AFFINITY_GROUP_ID = "affinitygroupid"; public static final String SERVICE_OFFERING_ID = "serviceofferingid"; public static final String DISPLAY = "display"; + public static final String SSH_KEYPAIR = "keypair"; public Criteria(String orderBy, Boolean ascending, Long offset, Long limit) { this.offset = offset; http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/server/src/com/cloud/server/ManagementServerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index f426b05..b525c0e 100644 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -16,7 +16,9 @@ // under the License. package com.cloud.server; +import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; +import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -3607,7 +3609,15 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } String name = cmd.getName(); - String publicKey = SSHKeysHelper.getPublicKeyFromKeyMaterial(cmd.getPublicKey()); + String key = cmd.getPublicKey(); + try { + if (key != null) { + key = URLDecoder.decode(key, "UTF-8"); + } + } catch (UnsupportedEncodingException e) { + } finally { + } + String publicKey = SSHKeysHelper.getPublicKeyFromKeyMaterial(key); if (publicKey == null) { throw new InvalidParameterValueException("Public key is invalid"); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/ui/css/cloudstack3.css ---------------------------------------------------------------------- diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 2ba0d5a..d6225ea 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -5500,7 +5500,7 @@ label.error { } .multi-wizard .progress ul { - width: 780px; + width: 900px; height: 40px; float: left; clear: both; @@ -6072,7 +6072,7 @@ label.error { } /*** Data disk offering*/ -.multi-wizard.instance-wizard .data-disk-offering .content .section { +.multi-wizard.instance-wizard .content .section { padding: 9px 0 16px; margin: 12px 0 15px 8px; } @@ -12447,6 +12447,14 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it background-position: -68px -612px; } +.resetSSHKeyForVirtualMachine .icon { + background-position: -196px -3px; +} + +.resetSSHKeyForVirtualMachine:hover .icon { + background-position: -195px -586px; +} + .changeService .icon { background-position: -38px -33px; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/ui/dictionary.jsp ---------------------------------------------------------------------- diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index 2d15c97..4923b81 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -829,6 +829,7 @@ dictionary = { 'label.menu.virtual.appliances': '<fmt:message key="label.menu.virtual.appliances" />', 'label.menu.virtual.resources': '<fmt:message key="label.menu.virtual.resources" />', 'label.menu.volumes': '<fmt:message key="label.menu.volumes" />', +'label.menu.sshkeypair': '<fmt:message key="label.menu.sshkeypair" />', 'label.migrate.instance.to': '<fmt:message key="label.migrate.instance.to" />', 'label.migrate.instance.to.host': '<fmt:message key="label.migrate.instance.to.host" />', 'label.migrate.instance.to.ps': '<fmt:message key="label.migrate.instance.to.ps" />', http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/ui/index.jsp ---------------------------------------------------------------------- diff --git a/ui/index.jsp b/ui/index.jsp index 086bcd0..dee2f75 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -101,7 +101,8 @@ <li><span class="number">4</span><span class="multiline"><fmt:message key="label.disk.offering"/></span><span class="arrow"></span></li> <li><span class="number">5</span><span><fmt:message key="label.affinity"/></span><span class="arrow"></span></li> <li><span class="number">6</span><span><fmt:message key="label.menu.network"/></span><span class="arrow"></span></li> - <li class="last"><span class="number">7</span><span><fmt:message key="label.review"/></span></li> + <li><span class="number">7</span><span><fmt:message key="label.menu.sshkeypair"/></span><span class="arrow"></span></li> + <li class="last"><span class="number">8</span><span><fmt:message key="label.review"/></span></li> </ul> </div> <form> @@ -393,7 +394,18 @@ </div> </div> </div> - <!-- Step 7: Review --> + <!-- Step 7: SSH Key pairs --> + <div class="step sshkeyPairs" wizard-step-id="sshkeyPairs"> + <div class="content"> + <div class="section no-thanks"> + <input type="radio" name="sshkeypair" value="" /> + <label><fmt:message key="label.no.thanks"/></label> + </div> + <!-- Existing key pairs --> + <div class="select-container"></div> + </div> + </div> + <!-- Step 8: Review --> <div class="step review" wizard-step-id="review"> <div class="main-desc"> <fmt:message key="message.vm.review.launch"/> @@ -535,6 +547,19 @@ </div> </div> + <!-- SSH Key Pairs --> + <div class="select"> + <div class="name"> + <span>SSH Key Pairs</span> + </div> + <div class="value"> + <span wizard-field="sshkey-pairs"></span> + </div> + <div class="edit"> + <a href="7"><fmt:message key="label.edit"/></a> + </div> + </div> + <!-- userdata --> <div class="select"> <div class="select"> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/ui/scripts/accounts.js ---------------------------------------------------------------------- diff --git a/ui/scripts/accounts.js b/ui/scripts/accounts.js index a1bf4c9..62ed4b8 100644 --- a/ui/scripts/accounts.js +++ b/ui/scripts/accounts.js @@ -24,7 +24,7 @@ sectionSelect: { label: 'label.select-view', preFilter: function() { - return ['accounts']; + return ['accounts', 'sshkeypairs']; } }, sections: { @@ -1468,6 +1468,280 @@ } } } + }, + sshkeypairs: { + type: 'select', + id: 'sshkeypairs', + title: 'SSH Key Pairs', + listView: { + name: 'sshkeypairs', + fields: { + name: { + label: 'label.name' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + }, + privatekey: { + label: 'Private Key', + span: false + } + }, + dataProvider: function(args) { + var data = { +// domainid: g_domainid, +// account: g_account + }; + + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listSSHKeyPairs'), + data: data, + success: function(json) { + var items = json.listsshkeypairsresponse.sshkeypair; + args.response.success({ + data: items + }); + } + }); + }, + actions: { + add: { + label: 'Create a SSH Key Pair', + + preFilter: function(args) { + return true; + }, + + messages: { + notification: function(args) { + return 'Created a SSH Key Pair.'; + } + }, + + createForm: { + title: 'Create a SSH Key Pair', + desc: 'Please fill in the following data to create or register a ssh key pair.<br><br>(1) If public key is set, CloudStack will register the public key. You can use it through your private key.<br><br>(2) If public key is not set, CloudStack will create a new SSH Key pair. In this case, please copy and save the private key. CloudStack will not keep it.<br>', + fields: { + name: { + label: 'label.name', + validation: { + required: true + }, + }, + publickey: { + label: 'Public Key' + }, + domain: { + label: 'label.domain', + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + }, + select: function(args) { + if (isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL("listDomains&listAll=true"), + success: function(json) { + var items = []; + items.push({ + id: "", + description: "" + }); + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + args.response.success({ + data: items + }); + } + }); + args.$select.change(function() { + var $form = $(this).closest('form'); + if ($(this).val() == "") { + $form.find('.form-item[rel=account]').hide(); + } else { + $form.find('.form-item[rel=account]').css('display', 'inline-block'); + } + }); + } else { + var items = []; + items.push({ + id: "", + description: "" + }); + args.response.success({ + data: items + }); + } + }, + }, + account: { + label: 'label.account', + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + } + } + }, + + action: function(args) { + + var data = { + name: args.data.name + }; + + if (args.data.domain != null && args.data.domain.length > 0) { + $.extend(data, { + domainid: args.data.domain + }); + if (args.data.account != null && args.data.account.length > 0) { + $.extend(data, { + account: args.data.account + }); + } + } + + if (args.data.publickey != null && args.data.publickey.length > 0) { + $.extend(data, { + publickey: encodeURIComponent(args.data.publickey) + }); + $.ajax({ + url: createURL('registerSSHKeyPair'), + data: data, + type: "POST", + success: function(json) { + var item = json.registersshkeypairresponse.keypair; + args.response.success({ + data: item + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } else { + $.ajax({ + url: createURL('createSSHKeyPair'), + data: data, + success: function(json) { + var item = json.createsshkeypairresponse.keypair; + args.response.success({ + data: item + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } + }, + + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + detailView: { + name: 'SSH Key Pair Details', + isMaximized: true, + viewAll: { + label: 'label.instances', + path: 'instances' + }, + actions: { + remove: { + label: 'Remove SSH Key Pair', + messages: { + confirm: function(args) { + return 'Please confirm that you want to remove this SSH Key Pair'; + }, + notification: function(args) { + return 'Removed a SSH Key Pair'; + } + }, + action: function(args) { + var data = { + domainid: args.context.sshkeypairs[0].domainid, + account: args.context.sshkeypairs[0].account, + name: args.context.sshkeypairs[0].name + }; + $.ajax({ + url: createURL('deleteSSHKeyPair'), + data: data, + success: function(json) { + args.response.success(); + $(window).trigger('cloudStack.fullRefresh'); + } + }); + } + } + }, + tabs: { + details: { + title: 'label.details', + + fields: [{ + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, { + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + }, + privatekey: { + label: 'Private Key', + span: false + }, + fingerprint: { + label: 'FingerPrint' + } + }], + + dataProvider: function(args) { + var data = { + name: args.context.sshkeypairs[0].name + }; + $.ajax({ + url: createURL('listSSHKeyPairs&listAll=true'), + data: data, + success: function(json) { + args.response.success({ + actionFilter: sshkeypairActionfilter, + data: json.listsshkeypairsresponse.sshkeypair[0] + }); + } + }); + } + } + } + } + } } } }; @@ -1546,4 +1820,9 @@ return allowedActions; } + var sshkeypairActionfilter = function(args) { + var allowedActions = []; + allowedActions.push("remove"); + return allowedActions; + } })(cloudStack); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/ui/scripts/instanceWizard.js ---------------------------------------------------------------------- diff --git a/ui/scripts/instanceWizard.js b/ui/scripts/instanceWizard.js index e4d3e30..a488885 100644 --- a/ui/scripts/instanceWizard.js +++ b/ui/scripts/instanceWizard.js @@ -665,7 +665,22 @@ }, - // Step 7: Review + // Step 7: SSH Key Pairs + function(args) { + $.ajax({ + url: createURL('listSSHKeyPairs'), + success: function(json) { + var sshkeypair = json.listsshkeypairsresponse.sshkeypair; + args.response.success({ + data: { + sshkeyPairs: sshkeypair + } + }); + } + }); + }, + + // Step 8: Review function(args) { return false; } @@ -952,6 +967,13 @@ } } + //step 4: select ssh key pair + if (args.data.sshkeypair != null && args.data.sshkeypair.length > 0) { + $.extend(deployVmData, { + keypair : args.data.sshkeypair + }); + } + var displayname = args.data.displayname; if (displayname != null && displayname.length > 0) { $.extend(deployVmData, { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/ui/scripts/instances.js ---------------------------------------------------------------------- diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index ee8ef0a..90ce2b1 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -362,6 +362,14 @@ }); } + if ("sshkeypairs" in args.context) { + $.extend(data, { + domainid: args.context.sshkeypairs[0].domainid, + account: args.context.sshkeypairs[0].account, + keypair: args.context.sshkeypairs[0].name + }); + } + $.ajax({ url: createURL('listVirtualMachines'), data: data, @@ -1624,7 +1632,99 @@ poll: pollAsyncJobResult } }, - + + resetSSHKeyForVirtualMachine: { + label: 'Reset SSH Key Pair', + createForm: { + title: 'Reset SSH Key Pair on VM', + desc: 'Please specify a ssh key pair that you would like to add to this VM. Please note the root password will be changed by this operation if password is enabled.', + fields: { + sshkeypair: { + label: 'New SSH Key Pair', + validation: { + required: true + }, + select: function(args) { + var data = { + domainid: args.context.instances[0].domainid, + account: args.context.instances[0].account, + listAll: true + }; + + $.ajax({ + url: createURL("listSSHKeyPairs"), + data: data, + async: false, + success: function(json) { + var items = []; + var sshkeypairs = json.listsshkeypairsresponse.sshkeypair; + if (sshkeypairs == null) { + } else { + for (var i = 0; i < sshkeypairs.length; i++) { + var sshkeypair = sshkeypairs[i]; + if (sshkeypair.name != args.context.instances[0].keypair) { + items.push({ + id: sshkeypair.name, + description: sshkeypair.name + }); + } + } + } + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + + action: function(args) { + var data = { + domainid: args.context.instances[0].domainid, + account: args.context.instances[0].account, + id: args.context.instances[0].id, + keypair: args.data.sshkeypair + }; + + $.ajax({ + url: createURL("resetSSHKeyForVirtualMachine"), + data: data, + async: true, + success: function(json) { + var jid = json.resetSSHKeyforvirtualmachineresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.virtualmachine; + }, + getActionFilter: function() { + return vmActionfilter; + } + } + }); + } + }); + }, + messages: { + notification: function(args) { + return 'Reset SSH Key Pair on VM'; + }, + complete: function(args) { + if (args.password != null) { + return 'Password of the VM has been reset to ' + args.password; + } + + return false; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + assignVmToAnotherAccount: { label: 'label.assign.instance.another', createForm: { @@ -1899,6 +1999,9 @@ publicip: { label: 'label.public.ip' }, + keypair: { + label: 'SSH Key Pair' + }, domain: { label: 'label.domain' }, @@ -2387,7 +2490,7 @@ if (isAdmin() || isDomainAdmin()) { allowedActions.push("assignVmToAnotherAccount"); } - + allowedActions.push("resetSSHKeyForVirtualMachine"); } else if (jsonObj.state == 'Starting') { // allowedActions.push("stop"); } else if (jsonObj.state == 'Error') { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/ui/scripts/ui-custom/instanceWizard.js ---------------------------------------------------------------------- diff --git a/ui/scripts/ui-custom/instanceWizard.js b/ui/scripts/ui-custom/instanceWizard.js index e8b0f39..93b895a 100644 --- a/ui/scripts/ui-custom/instanceWizard.js +++ b/ui/scripts/ui-custom/instanceWizard.js @@ -715,6 +715,51 @@ }; }, + 'sshkeyPairs': function($step, formData) { + var originalValues = function(formData) { + if (formData.sshkeypair) { + $step.find('input[type=radio]').filter(function() { + return $(this).val() == formData.sshkeypair; + }).click(); + } else { + $step.find('input[type=radio]:first').click(); + } + }; + return { + response: { + success: function(args) { + $step.find('.main-desc, p.no-sshkey-pairs').remove(); + + if (args.data.sshkeyPairs && args.data.sshkeyPairs.length) { + $step.prepend( + $('<div>').addClass('main-desc').append( + $('<p>').html(_l('Please select a ssh key pair you want this VM to use:')) + ) + ); + $step.find('.section.no-thanks').show(); + $step.find('.select-container').append( + makeSelects( + 'sshkeypair', + args.data.sshkeyPairs, { + name: 'name', + id: 'name' + }, { + 'wizard-field': 'sshkey-pairs' + } + ) + ); + originalValues(formData); // if we can select only one. + } else { + $step.find('.section.no-thanks').hide(); + $step.find('.select-container').append( + $('<p>').addClass('no-sshkey-pairs').html(_l('You do not have any ssh key pairs. Please continue to the next step.')) + ); + } + } + } + }; + }, + 'network': function($step, formData) { var showAddNetwork = true; @@ -1253,7 +1298,7 @@ return $wizard.dialog({ title: _l('label.vm.add'), - width: 800, + width: 896, height: 570, closeOnEscape: false, zIndex: 5000 http://git-wip-us.apache.org/repos/asf/cloudstack/blob/19e99848/ui/scripts/ui/widgets/listView.js ---------------------------------------------------------------------- diff --git a/ui/scripts/ui/widgets/listView.js b/ui/scripts/ui/widgets/listView.js index 07b60d9..93eaa71 100644 --- a/ui/scripts/ui/widgets/listView.js +++ b/ui/scripts/ui/widgets/listView.js @@ -1135,6 +1135,10 @@ }); $ul.appendTo($td); + } else if (field.span == false) { + $td.append( + $('<pre>').html(_s(content)) + ); } else { $td.append( $('<span>').html(_s(content))