This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new 46a3279  ui: instance settings visibility (#3244)
46a3279 is described below

commit 46a32795bcbefd7475d62421a71fbdeff0e2c407
Author: Abhishek Kumar <abhishek.mr...@gmail.com>
AuthorDate: Fri May 24 15:58:15 2019 +0530

    ui: instance settings visibility (#3244)
    
    This change allows instance Settings tab to be visible but inaccessible 
when instance is running. A warning is shown when user tries to access Settings 
for a running instance and tab content is greyed out.
    It also allows some admin defined instance settings/details to be made 
static for user. User will be able to see them in instance settings tab but 
cannot change their values as action buttons are disabled and greyed out. This 
can be achieved by providing a comma-separated list details for global settings 
key 'user.vm.readonly.ui.details'. A new value 'readonlyuidetails' has been 
added in UserVMResponse for UI manipulate editing functionality of 
settings/details.
    
    Signed-off-by: Abhishek Kumar <abhishek.mr...@gmail.com>
---
 .../cloudstack/api/response/UserVmResponse.java    |  12 ++
 .../org/apache/cloudstack/query/QueryService.java  |   4 +
 .../java/com/cloud/api/query/QueryManagerImpl.java |   6 +-
 .../com/cloud/api/query/dao/UserVmJoinDaoImpl.java |   3 +
 ui/css/cloudstack3.css                             |  15 ++
 ui/l10n/en.js                                      |   2 +
 ui/scripts/instances.js                            | 164 ++++++++++++---------
 7 files changed, 137 insertions(+), 69 deletions(-)

diff --git 
a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java 
b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java
index 8db4f85..bbf6b6c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java
@@ -262,6 +262,10 @@ public class UserVmResponse extends 
BaseResponseWithTagInformation implements Co
     @Param(description = "Vm details in key/value pairs.", since = "4.2.1")
     private Map details;
 
+    @SerializedName("readonlyuidetails")
+    @Param(description = "List of UI read-only Vm details as comma separated 
string.", since = "4.13.0")
+    private String readOnlyUIDetails;
+
     @SerializedName(ApiConstants.SSH_KEYPAIR)
     @Param(description = "ssh key-pair")
     private String keyPairName;
@@ -810,6 +814,10 @@ public class UserVmResponse extends 
BaseResponseWithTagInformation implements Co
         this.details = details;
     }
 
+    public void setReadOnlyUIDetails(String readOnlyUIDetails) {
+        this.readOnlyUIDetails = readOnlyUIDetails;
+    }
+
     public void setOsTypeId(String osTypeId) {
         this.osTypeId = osTypeId;
     }
@@ -826,6 +834,10 @@ public class UserVmResponse extends 
BaseResponseWithTagInformation implements Co
         return details;
     }
 
+    public String getReadOnlyUIDetails() {
+        return readOnlyUIDetails;
+    }
+
     public Boolean getDynamicallyScalable() {
         return isDynamicallyScalable;
     }
diff --git a/api/src/main/java/org/apache/cloudstack/query/QueryService.java 
b/api/src/main/java/org/apache/cloudstack/query/QueryService.java
index e8fd0b8..6a7c200 100644
--- a/api/src/main/java/org/apache/cloudstack/query/QueryService.java
+++ b/api/src/main/java/org/apache/cloudstack/query/QueryService.java
@@ -92,6 +92,10 @@ public interface QueryService {
             "user.vm.blacklisted.details", "rootdisksize, cpuOvercommitRatio, 
memoryOvercommitRatio, Message.ReservedCapacityFreed.Flag",
             "Determines whether users can view certain VM settings", true);
 
+    static final ConfigKey<String> UserVMReadOnlyUIDetails = new 
ConfigKey<String>("Advanced", String.class,
+            "user.vm.readonly.ui.details", "dataDiskController, 
rootDiskController",
+            "List of UI read-only VM settings/details as comma separated 
string", true);
+
     ListResponse<UserResponse> searchForUsers(ListUsersCmd cmd) throws 
PermissionDeniedException;
 
     ListResponse<EventResponse> searchForEvents(ListEventsCmd cmd);
diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java 
b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
index e165277..2cf72e2 100644
--- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
@@ -25,8 +25,6 @@ import java.util.Set;
 
 import javax.inject.Inject;
 
-import com.cloud.cluster.ManagementServerHostVO;
-import com.cloud.cluster.dao.ManagementServerHostDao;
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
 import org.apache.cloudstack.affinity.AffinityGroupResponse;
@@ -156,6 +154,8 @@ import com.cloud.api.query.vo.TemplateJoinVO;
 import com.cloud.api.query.vo.UserAccountJoinVO;
 import com.cloud.api.query.vo.UserVmJoinVO;
 import com.cloud.api.query.vo.VolumeJoinVO;
+import com.cloud.cluster.ManagementServerHostVO;
+import com.cloud.cluster.dao.ManagementServerHostDao;
 import com.cloud.dc.DedicatedResourceVO;
 import com.cloud.dc.dao.DedicatedResourceDao;
 import com.cloud.domain.Domain;
@@ -3714,6 +3714,6 @@ public class QueryManagerImpl extends 
MutualExclusiveIdsManagerBase implements Q
 
     @Override
     public ConfigKey<?>[] getConfigKeys() {
-        return new ConfigKey<?>[] {AllowUserViewDestroyedVM, 
UserVMBlacklistedDetails};
+        return new ConfigKey<?>[] {AllowUserViewDestroyedVM, 
UserVMBlacklistedDetails, UserVMReadOnlyUIDetails};
     }
 }
diff --git 
a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java 
b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
index 9b75776..58b167f 100644
--- a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
@@ -321,6 +321,9 @@ public class UserVmJoinDaoImpl extends 
GenericDaoBaseWithTagInformation<UserVmJo
                 }
             }
             userVmResponse.setDetails(resourceDetails);
+            if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
+                
userVmResponse.setReadOnlyUIDetails(QueryManagerImpl.UserVMReadOnlyUIDetails.value());
+            }
         }
 
         userVmResponse.setObjectName(objectName);
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 3794ca1..5ef4a58 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -564,6 +564,21 @@ body.login {
   margin: 0 auto;
 }
 
+.blocking-overlay {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  left: 0px;
+  top: 0px;
+  background: #F2F2F2;
+  z-index: 500;
+  /*+opacity:70%;*/
+  filter: alpha(opacity=70);
+  -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70);
+  -moz-opacity: 0.7;
+  opacity: 0.7;
+}
+
 .loading-overlay {
   opacity: 0.7;
   position: absolute;
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index c16a955..7e992e5 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -1944,6 +1944,8 @@ var dictionary = {
 "message.action.restore.instance":"Please confirm that you want to restore 
this instance.",
 "message.action.revert.snapshot":"Please confirm that you want to revert the 
owning volume to this snapshot.",
 "message.action.secure.host":"This will restart the host agent and libvirtd 
process after applying new X509 certificates, please confirm?",
+"message.action.settings.warning.vm.running":"Please stop the virtual machine 
to access settings",
+"message.action.settings.warning.vm.started":"Virtual machine has been 
started. It needs to be stopped to access settings",
 "message.action.start.instance":"Please confirm that you want to start this 
instance.",
 "message.action.start.router":"Please confirm that you want to start this 
router.",
 "message.action.start.systemvm":"Please confirm that you want to start this 
system VM.",
diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js
index 57a060f..30bff8a 100644
--- a/ui/scripts/instances.js
+++ b/ui/scripts/instances.js
@@ -847,10 +847,6 @@
                     if (includingSecurityGroupService == false) {
                         hiddenTabs.push("securityGroups");
                     }
-                                       
-                                       if (args.context.instances[0].state == 
'Running') {
-                                               hiddenTabs.push("settings");
-                                       }
 
                     return hiddenTabs;
                 },
@@ -3216,10 +3212,31 @@
                                                                $.ajax({
                                                                        url: 
createURL('listVirtualMachines&id=' + args.context.instances[0].id),
                                                                        
success: function(json) {
-                                                                               
var details = json.listvirtualmachinesresponse.virtualmachine[0].details;
-                                                                               
args.response.success({
-                                                                               
        data: parseDetails(details)
-                                                                               
});
+                                        var virtualMachine = 
json.listvirtualmachinesresponse.virtualmachine[0];
+                                        args.response.success({
+                                            data: 
parseDetails(virtualMachine.details)
+                                        });
+
+                                        if (virtualMachine.state != 'Stopped') 
{
+                                            
$('#details-tab-settings').append($('<div>').addClass('blocking-overlay'));
+                                            cloudStack.dialog.notice({
+                                                message: 
_l('message.action.settings.warning.vm.running')
+                                            });
+                                        } else {
+                                            if(virtualMachine && 
virtualMachine.readonlyuidetails && virtualMachine.readonlyuidetails.length > 
0) {
+                                                var readOnlyUIDetails = []
+                                                
$.each(virtualMachine.readonlyuidetails.split(","), function(){
+                                                    
readOnlyUIDetails.push($.trim(this));
+                                                });
+                                                $('#details-tab-settings 
tr').each(function() {
+                                                    
if($.inArray($.trim($(this).find('td:first').text()), readOnlyUIDetails) >= 0) {
+                                                        $(this).find('td:last 
div.action').each(function() {
+                                                            
$(this).addClass("disabled")
+                                                        });
+                                                    }
+                                                });
+                                            }
+                                        };
                                                                        },
 
                                                                        error: 
function(json) {
@@ -3234,85 +3251,100 @@
                                                                                
name: args.data.jsonObj.name,
                                                                                
value: args.data.value
                                                                        };
-                                                                       var 
existingDetails;
+                                                                       var 
virtualMachine;
                                                                        $.ajax({
                                                                                
url: createURL('listVirtualMachines&id=' + args.context.instances[0].id),
                                                                                
async:false,
                                                                                
success: function(json) {
-                                                                               
        var details = 
json.listvirtualmachinesresponse.virtualmachine[0].details;
-                                                                               
        console.log(details);
-                                                                               
        existingDetails = details;
-                                                                               
},
-
-                                                                               
error: function(json) {
-                                                                               
        args.response.error(parseXMLHttpResponse(json));
-                                                                               
}
-                                                                       });
-                                                                       
console.log(existingDetails);
-                                                                       var 
newDetails = '';
-                                                                       for (d 
in existingDetails) {
-                                                                               
if (d != data.name) {
-                                                                               
        newDetails += 'details[0].' + d + '=' + existingDetails[d] + '&';
-                                                                               
}
-                                                                       }
-                                                                       
newDetails += 'details[0].' + data.name + '=' + data.value;
-                                                                       
-                                                                       $.ajax({
-                                                                               
url: createURL('updateVirtualMachine&id=' + args.context.instances[0].id + '&' 
+ newDetails),
-                                                                               
async:false,
-                                                                               
success: function(json) {
-                                                                               
        var items = json.updatevirtualmachineresponse.virtualmachine.details;
-                                                                               
        args.response.success({
-                                                                               
                data: parseDetails(items)
-                                                                               
        });
+                                                                               
        virtualMachine = json.listvirtualmachinesresponse.virtualmachine[0];
                                                                                
},
 
                                                                                
error: function(json) {
                                                                                
        args.response.error(parseXMLHttpResponse(json));
                                                                                
}
                                                                        });
-                                                               },
+                                    if (virtualMachine && virtualMachine.state 
== "Stopped") {
+                                        // It could happen that a stale web 
page has been opened up when VM was stopped but
+                                        // vm was turned on through another 
route - UI or API. so we should check again.
+                                        var existingDetails = 
virtualMachine.details;
+                                        console.log(existingDetails);
+                                        var newDetails = {};
+                                        for (d in existingDetails) {
+                                            if (d != data.name) {
+                                                newDetails['details[0].' + d] 
= existingDetails[d];
+                                            }
+                                        }
+                                        newDetails['details[0].' + data.name] 
= data.value;
+                                        var postData = {'id' : 
args.context.instances[0].id};
+                                        $.extend(postData, newDetails);
+                                        $.ajax({
+                                            url: 
createURL('updateVirtualMachine'),
+                                            data: postData,
+                                            async:false,
+                                            success: function(json) {
+                                                var items = 
json.updatevirtualmachineresponse.virtualmachine.details;
+                                                args.response.success({
+                                                    data: parseDetails(items)
+                                                });
+                                            },
+                                            error: function(json) {
+                                                
args.response.error(parseXMLHttpResponse(json));
+                                            }
+                                        });
+                                    } else {
+                                        
$('#details-tab-settings').append($('<div>').addClass('blocking-overlay'));
+                                        cloudStack.dialog.notice({
+                                            message: 
_l('message.action.settings.warning.vm.started')
+                                        });
+                                    }
+                                },
                                                                remove: 
function(args) {
-                                                                       var 
existingDetails;
+                                                                       var 
virtualMachine;
                                                                        $.ajax({
                                                                                
url: createURL('listVirtualMachines&id=' + args.context.instances[0].id),
                                                                                
async:false,
                                                                                
success: function(json) {
-                                                                               
        var details = 
json.listvirtualmachinesresponse.virtualmachine[0].details;
-                                                                               
        existingDetails = details;
+                                                                               
        virtualMachine = json.listvirtualmachinesresponse.virtualmachine[0];
                                                                                
},
 
                                                                                
error: function(json) {
                                                                                
        args.response.error(parseXMLHttpResponse(json));
                                                                                
}
                                                                        });
-                                                                       
-                                                                       var 
detailToDelete = args.data.jsonObj.name;
-                                                                       var 
newDetails = ''
-                                                                       for 
(detail in existingDetails) {
-                                                                               
if (detail != detailToDelete) {
-                                                                               
        newDetails += 'details[0].' + detail + '=' + existingDetails[detail] + 
'&';
-                                                                               
}
-                                                                       }
-                                                                       if 
(newDetails != '') {
-                                                                               
newDetails = newDetails.substring(0, newDetails.length - 1);
-                                                                       }
-                                                                       else {
-                                                                               
newDetails += 'cleanupdetails=true'
-                                                                       }
-                                                                       $.ajax({
-                                                                               
url: createURL('updateVirtualMachine&id=' + args.context.instances[0].id + '&' 
+ newDetails),
-                                                                               
async:false,
-                                                                               
success: function(json) {
-                                                                               
        var items = json.updatevirtualmachineresponse.virtualmachine.details;
-                                                                               
        args.response.success({
-                                                                               
                data: parseDetails(items)
-                                                                               
        });
-                                                                               
},
-                                                                               
error: function(json) {
-                                                                               
        args.response.error(parseXMLHttpResponse(json));
-                                                                               
}
-                                                                       });
+                                    if (virtualMachine && virtualMachine.state 
== "Stopped") {
+                                        // It could happen that a stale web 
page has been opened up when VM was stopped but
+                                        // vm was turned on through another 
route - UI or API. so we should check again.
+                                        var detailToDelete = 
args.data.jsonObj.name;
+                                        var existingDetails = 
virtualMachine.details;
+                                        var newDetails = {};
+                                        for (detail in existingDetails) {
+                                            if (detail != detailToDelete) {
+                                                newDetails['details[0].' + 
detail] = existingDetails[detail];
+                                            }
+                                        }
+
+                                        var postData = 
$.isEmptyObject(newDetails) ? {'cleanupdetails': true} : newDetails;
+                                        $.extend(postData, {'id' : 
args.context.instances[0].id});
+                                        $.ajax({
+                                            url: 
createURL('updateVirtualMachine'),
+                                            data: postData,
+                                            async:false,
+                                            success: function(json) {
+                                                var items = 
json.updatevirtualmachineresponse.virtualmachine.details;
+                                                args.response.success({
+                                                    data: parseDetails(items)
+                                                });
+                                            },
+                                            error: function(json) {
+                                                
args.response.error(parseXMLHttpResponse(json));
+                                            }
+                                        });
+                                    } else {
+                                        
$('#details-tab-settings').append($('<div>').addClass('blocking-overlay'));
+                                        cloudStack.dialog.notice({
+                                            message: 
_l('message.action.settings.warning.vm.started')
+                                        });
+                                    }
                                                                },
                                                                add: 
function(args) {
                                                                        var 
name = args.data.name;

Reply via email to