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))

Reply via email to