diff --git a/.gitignore b/.gitignore
index 48aa29b69e30..1a73724c1172 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,7 +51,6 @@ tools/cli/build/
*.jar
*.war
*.mar
-*.zip
*.iso
*.tar.gz
*.tgz
@@ -98,3 +97,5 @@ systemvm/.pydevproject
test/.pydevprojec
plugins/hypervisors/kvm/.pydevproject
scripts/.pydevproject
+*.qcow2
+*.raw
diff --git a/.java-version b/.java-version
index d3bdbdf1fdae..6259340971be 100644
--- a/.java-version
+++ b/.java-version
@@ -1 +1 @@
-1.7
+1.8
diff --git a/.travis.yml b/.travis.yml
index 359d6666788b..d5fd173d71ed 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,7 +19,7 @@ dist: trusty
group: edge
language: java
jdk:
-- openjdk7
+- oraclejdk8
python:
- "2.7"
cache:
@@ -32,8 +32,11 @@ env:
global:
- PATH=$HOME/.local/bin:$PATH
matrix:
- - TESTS="smoke/test_affinity_groups
+ # Keep the TESTS sorted by name and grouped by type
+ - TESTS="smoke/test_accounts
+ smoke/test_affinity_groups
smoke/test_affinity_groups_projects
+ smoke/test_certauthority_root
smoke/test_deploy_vgpu_enabled_vm
smoke/test_deploy_vm_iso
smoke/test_deploy_vm_root_resize
@@ -42,8 +45,12 @@ env:
smoke/test_disk_offerings
smoke/test_dynamicroles
smoke/test_global_settings
- smoke/test_guest_vlan_range
- smoke/test_hosts
+ smoke/test_guest_vlan_range"
+
+ - TESTS="smoke/test_hostha_kvm
+ smoke/test_hostha_simulator
+ smoke/test_host_annotations
+ smoke/test_host_maintenance
smoke/test_internal_lb
smoke/test_iso
smoke/test_list_ids_parameter
@@ -51,18 +58,22 @@ env:
smoke/test_login
smoke/test_metrics_api
smoke/test_multipleips_per_nic
+ smoke/test_nested_virtualization
smoke/test_network
smoke/test_network_acl
smoke/test_nic
smoke/test_nic_adapter_type
- smoke/test_non_contigiousvlan"
-
- - TESTS="smoke/test_outofbandmanagement
+ smoke/test_non_contigiousvlan
+ smoke/test_outofbandmanagement
+ smoke/test_outofbandmanagement_nestedplugin
smoke/test_over_provisioning
smoke/test_password_server
smoke/test_portable_publicip
- smoke/test_primary_storage
+ smoke/test_portforwardingrules"
+
+ - TESTS="smoke/test_primary_storage
smoke/test_privategw_acl
+ smoke/test_projects
smoke/test_public_ip_range
smoke/test_pvlan
smoke/test_regions
@@ -80,6 +91,7 @@ env:
smoke/test_ssvm
smoke/test_staticroles
smoke/test_templates
+ smoke/test_usage
smoke/test_usage_events
smoke/test_vm_life_cycle
smoke/test_vm_snapshots
@@ -97,8 +109,12 @@ env:
component/test_acl_listsnapshot
component/test_acl_listvm
component/test_acl_listvolume
- component/test_acl_sharednetwork
- component/test_acl_sharednetwork_deployVM-impersonation"
+ component/test_acl_sharednetwork"
+
+ - TESTS="component/test_allocation_states
+ component/test_acl_sharednetwork_deployVM-impersonation
+ component/test_affinity_groups_projects
+ component/test_cpu_domain_limits
component/test_cpu_limits"
- TESTS="component/test_cpu_max_limits
@@ -117,41 +133,37 @@ env:
component/test_non_contiguous_vlan
component/test_persistent_networks"
- - TESTS="component/test_projects
+ - TESTS="component/test_project_limits
component/test_project_configs
- component/test_project_limits
component/test_project_usage
- component/test_regions
+ component/test_project_resources
component/test_regions_accounts
component/test_routers
- component/test_snapshots"
+ component/test_snapshots
+ component/test_stopped_vm"
+
+ - TESTS="component/test_project_resources"
- - TESTS="component/test_resource_limits"
+ - TESTS="component/test_project_limits
+ component/test_resource_limits"
- - TESTS="component/test_stopped_vm
- component/test_tags
+ - TESTS="component/test_tags
component/test_templates
component/test_update_vm
- component/test_usage"
+ component/test_volumes"
- - TESTS="component/test_volumes
+ - TESTS="component/test_vpc
component/test_vpc_network
component/test_vpc_offerings
component/test_vpn_users"
# FIXME: fix following tests and include them in Travis
-# - TESTS="component/test_affinity_groups_projects"
-# - TESTS="component/test_allocation_states"
-# - TESTS="component/test_vpc"
-# - TESTS="component/test_project_resources"
-# - TESTS="component/test_cpu_domain_limits"
-# - TESTS="component/test_acl_isolatednetwork"
-# - TESTS="component/test_accounts"
-# - TESTS="component/test_organization_states"
+# - TESTS="component/test_vpc" Please add when PR: https://github.com/apache/cloudstack/pull/955 CLOUDSTACK-8969 is fixed
+# - TESTS="component/test_organization_states" Please add when CLOUDSTACK-7735 is fixed
-before_install: travis_wait 60 ./tools/travis/before_install.sh
+before_install: travis_wait 30 ./tools/travis/before_install.sh
install: ./tools/travis/install.sh
-before_script: travis_wait 60 ./tools/travis/before_script.sh
+before_script: travis_wait 30 ./tools/travis/before_script.sh
script:
- travis_wait 40 ./tools/travis/script.sh ${TESTS}
after_success: ./tools/travis/after_success.sh
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c4ad1974eb63..6ac3ad56dd4d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,10 +3,26 @@ Contributing to Apache CloudStack (ACS)
Summary
-------
-This document covers how to contribute to the ACS project. These instructions assume you have a GitHub.com account, so if you don't have one you will have to create one. Your proposed code changes will be published to your own fork of the ACS project and you will submit a Pull Request for your changes to be added.
+This document covers how to contribute to the ACS project. ACS uses github PRs to manage code contributions.
+These instructions assume you have a GitHub.com account, so if you don't have one you will have to create one. Your proposed code changes will be published to your own fork of the ACS project and you will submit a Pull Request for your changes to be added.
_Lets get started!!!_
+Bug fixes
+---------
+
+It's very important that we can easily track bug fix commits, so their hashes should remain the same in all branches.
+Therefore, a pull request (PR) that fixes a bug, should be sent against a release branch.
+This can be either the "current release" or the "previous release", depending on which ones are maintained.
+Since the goal is a stable master, bug fixes should be "merged forward" to the next branch in order: "previous release" -> "current release" -> master (in other words: old to new)
+
+Developing new features
+-----------------------
+
+Development should be done in a feature branch, branched off of master.
+Send a PR(steps below) to get it into master (2x LGTM applies).
+PR will only be merged when master is open, will be held otherwise until master is open again.
+No back porting / cherry-picking features to existing branches!
Fork the code
-------------
@@ -30,6 +46,7 @@ $ git rebase upstream/master
Making changes
--------------
+
It is important that you create a new branch to make changes on and that you do not change the `master` branch (other than to rebase in changes from `upstream/master`). In this example I will assume you will be making your changes to a branch called `feature_x`. This `feature_x` branch will be created on your local repository and will be pushed to your forked repository on GitHub. Once this branch is on your fork you will create a Pull Request for the changes to be added to the ACS project.
It is best practice to create a new branch each time you want to contribute to the project and only track the changes for that pull request in this branch.
@@ -72,6 +89,8 @@ Make a GitHub Pull Request to contribute your changes
When you are happy with your changes and you are ready to contribute them, you will create a Pull Request on GitHub to do so. This is done by pushing your local changes to your forked repository (default remote name is `origin`) and then initiating a pull request on GitHub.
+Please include JIRA id, detailed information about the bug/feature, what all tests are executed, how the reviewer can test this feature etc. Incase of UI PRs, a screenshot is preferred.
+
> **IMPORTANT:** Make sure you have rebased your `feature_x` branch to include the latest code from `upstream/master` _before_ you do this.
``` bash
@@ -105,3 +124,7 @@ $ git checkout master
$ git branch -D feature_x
$ git push origin :feature_x
```
+
+Release Principles
+------------------
+Detailed information about ACS release principles is available at https://cwiki.apache.org/confluence/display/CLOUDSTACK/Release+principles+for+Apache+CloudStack+4.6+and+up
diff --git a/INSTALL.md b/INSTALL.md
index 8a83fb0f7204..626df91dc564 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -15,7 +15,7 @@ was tested against a CentOS 6.5 x86_64 setup.
Install tools and dependencies used for development:
$ yum install git ant ant-devel java-1.6.0-openjdk java-1.6.0-openjdk-devel
- mysql mysql-server tomcat6 mkisofs gcc python MySQL-python openssh-clients wget
+ mysql mysql-server mkisofs gcc python MySQL-python openssh-clients wget
# yum -y update
# yum -y install java-1.7.0-openjdk
@@ -124,7 +124,6 @@ To create debs install the following extra packages:
# apt-get -y install python-mysqldb
# apt-get -y install debhelper
- # apt-get -y install tomcat6
Then:
@@ -138,7 +137,6 @@ All the deb packages will be located one level down.
To create rpms, install the following extra packages:
# yum -y install rpm-build
- # yum -y install tomcat6
# yum -y install ws-commons-util
# yum -y instal gcc
# yum -y install glibc-devel
@@ -154,7 +152,7 @@ All the rpm packages will be created in `dist/rpmbuild/RPMS/x86_64` directory.
## Notes
-If you will be using Xen as your hypervisor, please download [vhd-util](http://download.cloud.com.s3.amazonaws.com/tools/vhd-util)
+If you will be using Xen as your hypervisor, please download [vhd-util](http://download.cloudstack.org/tools/vhd-util)
If management server is installed on RHEL/CentOS, then copy vhd-util into:
diff --git a/LICENSE b/LICENSE
index 982b15844f4a..0dcb45c61893 100644
--- a/LICENSE
+++ b/LICENSE
@@ -208,7 +208,7 @@ Within the console-proxy/js directory
jquery.js
-Within the patches/systemvm/debian/config/etc directory
+Within the systemvm/debian/etc directory
placed in the public domain
by Adiscon GmbH http://www.adiscon.com/
rsyslog.conf
@@ -216,14 +216,14 @@ Within the patches/systemvm/debian/config/etc directory
dnsmasq.conf
vpcdnsmasq.conf
-Within the patches/systemvm/debian/config/etc/apache2 directory
+Within the systemvm/debian/etc/apache2 directory
licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above)
Copyright (c) 2012 The Apache Software Foundation
from The Apache Software Foundation http://www.apache.org/
httpd.conf
vhost.template
-Within the patches/systemvm/debian/config/etc/ssh/ directory
+Within the systemvm/debian/etc/ssh/ directory
licensed under the BSD (2-clause) http://www.opensource.org/licenses/BSD-2-Clause (as follows)
@@ -254,7 +254,7 @@ Within the patches/systemvm/debian/config/etc/ssh/ directory
from OpenSSH Project http://www.openssh.org/
sshd_config
-Within the patches/systemvm/debian/config/root/redundant_router directory
+Within the systemvm/debian/root/redundant_router directory
placed in the public domain
by The netfilter.org project http://www.netfilter.org/
conntrackd.conf.templ
@@ -271,65 +271,6 @@ Within the scripts/vm/hypervisor/xenserver directory
from OpenStack, LLC http://www.openstack.org
swift
-Within the tools/appliance/definitions/{devcloud,systemvmtemplate,systemvmtemplate64} directory
- licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
-
- Copyright (c) 2010-2012 Patrick Debois
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
- from Patrick Debois http://www.jedi.be/blog/
- base.sh from https://github.com/jedi4ever/veewee
- cleanup.sh from https://github.com/jedi4ever/veewee
- definition.rb from https://github.com/jedi4ever/veewee
- preseed.cfg from https://github.com/jedi4ever/veewee
- zerodisk.sh from https://github.com/jedi4ever/veewee
-
-Within the tools/devcloud/src/deps/boxes/basebox-build directory
- licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
-
- Copyright (c) 2010-2012 Patrick Debois
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
- from Patrick Debois http://www.jedi.be/blog/
- definition.rb from https://github.com/jedi4ever/veewee
- preseed.cfg from https://github.com/jedi4ever/veewee
-
Within the ui/lib directory
placed in the public domain
by Eric Meyer http://meyerweb.com/eric/
diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000000..17adfe69a312
--- /dev/null
+++ b/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,39 @@
+## Description
+
+
+
+
+
+## Types of changes
+
+- [ ] Breaking change (fix or feature that would cause existing functionality to change)
+- [ ] New feature (non-breaking change which adds functionality)
+- [ ] Bug fix (non-breaking change which fixes an issue)
+- [ ] Enhancement (improves an existing feature and functionality)
+- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
+
+## GitHub Issue/PRs
+
+
+
+
+
+
+## Screenshots (if appropriate):
+
+## How Has This Been Tested?
+
+
+
+
+
+## Checklist:
+
+
+- [ ] I have read the [CONTRIBUTING](https://github.com/apache/cloudstack/blob/master/CONTRIBUTING.md) document.
+- [ ] My code follows the code style of this project.
+- [ ] My change requires a change to the documentation.
+- [ ] I have updated the documentation accordingly.
+- [ ] I have added tests to cover my changes.
+- [ ] All new and existing tests passed.
+
diff --git a/README.md b/README.md
index 287f8f2bf687..17a7a8f7bd9e 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ For more information on Apache CloudStack, please visit the [website](http://clo
Apache CloudStack project uses Git. The official Git repository is at:
- https://git-wip-us.apache.org/repos/asf/cloudstack.git
+ https://gitbox.apache.org/repos/asf/cloudstack.git
And a mirror is hosted on Github:
@@ -92,8 +92,7 @@ developer [page](http://cloudstack.apache.org/developers.html) for contributing
* [Blog](https://blogs.apache.org/cloudstack)
* [Twitter](https://twitter.com/cloudstack)
-* [Planet CloudStack](http://planet.apache.org/cloudstack)
-* [Events and meetup](http://lanyrd.com/topics/apache-cloudstack)
+* [Events and meetup](http://cloudstackcollab.org/)
## Reporting Security Vulnerabilities
diff --git a/agent-simulator/tomcatconf/commands-simulator.properties.in b/agent-simulator/tomcatconf/commands-simulator.properties.in
deleted file mode 100644
index 4350bb788b43..000000000000
--- a/agent-simulator/tomcatconf/commands-simulator.properties.in
+++ /dev/null
@@ -1,21 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-
-configureSimulator=com.cloud.api.commands.ConfigureSimulatorCmd;1
-querySimulatorMock=com.cloud.api.commands.QuerySimulatorMockCmd;1
-cleanupSimulatorMock=com.cloud.api.commands.CleanupSimulatorMockCmd;1
diff --git a/agent/bindir/cloud-setup-agent.in b/agent/bindir/cloud-setup-agent.in
index 8d2b91961aef..3c6203c2d340 100755
--- a/agent/bindir/cloud-setup-agent.in
+++ b/agent/bindir/cloud-setup-agent.in
@@ -26,6 +26,7 @@ from cloudutils.configFileOps import configFileOps
from cloudutils.globalEnv import globalEnv
from cloudutils.networkConfig import networkConfig
from cloudutils.syscfg import sysConfigFactory
+from cloudutils.serviceConfig import configureLibvirtConfig
from optparse import OptionParser
@@ -100,6 +101,7 @@ if __name__ == '__main__':
parser.add_option("-c", "--cluster", dest="cluster", help="cluster id")
parser.add_option("-t", "--hypervisor", default="kvm", dest="hypervisor", help="hypervisor type")
parser.add_option("-g", "--guid", dest="guid", help="guid")
+ parser.add_option("-s", action="store_true", default=False, dest="secure", help="Secure and enable TLS for libvirtd")
parser.add_option("--pubNic", dest="pubNic", help="Public traffic interface")
parser.add_option("--prvNic", dest="prvNic", help="Private traffic interface")
parser.add_option("--guestNic", dest="guestNic", help="Guest traffic interface")
@@ -110,6 +112,12 @@ if __name__ == '__main__':
glbEnv.bridgeType = bridgeType
(options, args) = parser.parse_args()
+
+ if not options.auto and options.secure:
+ configureLibvirtConfig(True)
+ print "Libvirtd with TLS configured"
+ sys.exit(0)
+
if options.auto is None:
userInputs = getUserInputs()
glbEnv.mgtSvr = userInputs[0]
@@ -138,7 +146,9 @@ if __name__ == '__main__':
glbEnv.nics.append(options.prvNic)
glbEnv.nics.append(options.pubNic)
glbEnv.nics.append(options.guestNic)
-
+
+ glbEnv.secure = options.secure
+
print "Starting to configure your system:"
syscfg = sysConfigFactory.getSysConfigFactory(glbEnv)
try:
diff --git a/agent/bindir/libvirtqemuhook.in b/agent/bindir/libvirtqemuhook.in
index 9fbe037d1c15..55ab3e673095 100755
--- a/agent/bindir/libvirtqemuhook.in
+++ b/agent/bindir/libvirtqemuhook.in
@@ -6,25 +6,36 @@
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-import sys
+
+import logging
import re
+import sys
from xml.dom.minidom import parse
from cloudutils.configFileOps import configFileOps
from cloudutils.networkConfig import networkConfig
+
+logging.basicConfig(filename='/var/log/libvirt/qemu-hook.log',
+ filemode='a',
+ format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
+ datefmt='%H:%M:%S',
+ level=logging.INFO)
+logger = logging.getLogger('qemu-hook')
+
def isOldStyleBridge(brName):
if brName.find("cloudVirBr") == 0:
return True
else:
return False
+
def isNewStyleBridge(brName):
if brName.startswith('brvx-'):
return False
@@ -32,12 +43,14 @@ def isNewStyleBridge(brName):
return False
else:
return True
+
def getGuestNetworkDevice():
- netlib = networkConfig()
+ netlib = networkConfig()
cfo = configFileOps("/etc/cloudstack/agent/agent.properties")
guestDev = cfo.getEntry("guest.network.device")
enslavedDev = netlib.getEnslavedDev(guestDev, 1)
return enslavedDev.split(".")[0]
+
def handleMigrateBegin():
try:
domain = parse(sys.stdin)
@@ -45,20 +58,26 @@ def handleMigrateBegin():
source = interface.getElementsByTagName("source")[0]
bridge = source.getAttribute("bridge")
if isOldStyleBridge(bridge):
- vlanId = bridge.replace("cloudVirBr","")
+ vlanId = bridge.replace("cloudVirBr", "")
elif isNewStyleBridge(bridge):
- vlanId = re.sub(r"br(\w+)-","",bridge)
+ vlanId = re.sub(r"br(\w+)-", "", bridge)
else:
continue
phyDev = getGuestNetworkDevice()
- newBrName="br" + phyDev + "-" + vlanId
+ newBrName = "br" + phyDev + "-" + vlanId
source.setAttribute("bridge", newBrName)
print(domain.toxml())
except:
pass
+
+
if __name__ == '__main__':
if len(sys.argv) != 5:
sys.exit(0)
- if sys.argv[2] == "migrate" and sys.argv[3] == "begin":
- handleMigrateBegin()
+ # For docs refer https://libvirt.org/hooks.html#qemu
+ logger.debug("Executing qemu hook with args: %s" % sys.argv)
+ action, status = sys.argv[2:4]
+
+ if action == "migrate" and status == "begin":
+ handleMigrateBegin()
diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties
index 8b99ee364661..ad35b96bab6e 100644
--- a/agent/conf/agent.properties
+++ b/agent/conf/agent.properties
@@ -30,6 +30,17 @@ workers=5
#host= The IP address of management server
host=localhost
+# The time interval in seconds after which agent will check if connected host
+# is the preferred host (the first host in the comma-separated list is preferred
+# one) and will attempt to reconnect to the preferred host when it's connected
+# to one of the secondary/backup hosts. The timer task is scheduled after agent
+# connects to a management server. On connection, it receives admin configured
+# cluster-level 'indirect.agent.lb.check.interval' setting that will be used by
+# the agent as the preferred host check interval however the following setting
+# if defined overrides the received value. The value 0 and lb algorithm 'shuffle'
+# disables this background task.
+#host.lb.check.interval=0
+
#port = The port management server listening on, default is 8250
port=8250
@@ -56,6 +67,11 @@ zone=default
# local storage path, by default, it's /var/lib/libvirt/images/
#local.storage.path=/var/lib/libvirt/images/
+# Qemu socket path, directory where Qemu sockets are placed.
+# These sockets are for the Qemu Guest Agent and SSVM privisioning
+# Make sure that AppArmor or SELinux allow libvirt to write there
+#qemu.sockets.path=/var/lib/libvirt/qemu
+
# The UUID for the local storage pool, this is mandatory!
# Generate with "uuidgen"
local.storage.uuid=
@@ -153,6 +169,41 @@ hypervisor.type=kvm
# Some newer linux kernels are incapable of reliably migrating vms with kvmclock
# This is a workaround for the bug, admin can set this to true per-host
#
-#router.aggregation.command.each.timeout=600
-#timeout value for aggregation commands send to virtual router
+# vm.rng.enable=false
+# This enabled the VirtIO Random Number Generator device for guests.
+#
+# vm.rng.model=random
+# The model of VirtIO Random Number Generator (RNG) to present to the Guest.
+# Currently only 'random' is supported.
+#
+# vm.rng.path=/dev/random
+# Local Random Number Device Generator to use for VirtIO RNG for Guests.
+# This is usually /dev/random, but per platform this might be different
+#
+# vm.rng.rate.bytes=2048
+# The amount of bytes the Guest may request/obtain from the RNG in the period
+# specified below.
+#
+# vm.rng.rate.period=1000
+# The number of milliseconds in which the guest is allowed to obtain the bytes
+# specified above.
+#
+# router.aggregation.command.each.timeout=600
+# timeout value for aggregation commands send to virtual router
+#
+# host.overcommit.mem.mb = 0
+# allows to increase amount of ram available on host virtually to utilize Zswap, KSM features
+# and modern fast SSD/3D XPoint devices. Specified amount of MBs is added to the memory agent
+# reports to the Management Server
+# Default: 0
+#
+# vm.watchdog.model=i6300esb
+# The model of Watchdog timer to present to the Guest
+# For all models refer to the libvirt documentation.
+# Recommend value is: i6300esb
#
+# vm.watchdog.action=none
+# Action to take when the Guest/Instance is no longer notifiying the Watchdog
+# timer.
+# For all actions refer to the libvirt documentation.
+# Recommended values are: none, reset and poweroff.
diff --git a/agent/pom.xml b/agent/pom.xml
index 02eb9d8b1dc2..50b10c17827d 100644
--- a/agent/pom.xml
+++ b/agent/pom.xml
@@ -23,7 +23,7 @@
org.apache.cloudstack
cloudstack
- 4.9.4.0-SNAPSHOT
+ 4.11.1.0-SNAPSHOT
diff --git a/agent/src/com/cloud/agent/Agent.java b/agent/src/com/cloud/agent/Agent.java
index 7fab5f4d3013..67115e649a1b 100644
--- a/agent/src/com/cloud/agent/Agent.java
+++ b/agent/src/com/cloud/agent/Agent.java
@@ -16,12 +16,16 @@
// under the License.
package com.cloud.agent;
+import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.channels.ClosedChannelException;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -35,7 +39,18 @@
import javax.naming.ConfigurationException;
+import org.apache.cloudstack.agent.directdownload.SetupDirectDownloadCertificate;
+import org.apache.cloudstack.agent.lb.SetupMSListAnswer;
+import org.apache.cloudstack.agent.lb.SetupMSListCommand;
+import org.apache.cloudstack.ca.PostCertificateRenewalCommand;
+import org.apache.cloudstack.ca.SetupCertificateAnswer;
+import org.apache.cloudstack.ca.SetupCertificateCommand;
+import org.apache.cloudstack.ca.SetupKeyStoreCommand;
+import org.apache.cloudstack.ca.SetupKeystoreAnswer;
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
+import org.apache.cloudstack.utils.security.KeyStoreUtils;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.slf4j.MDC;
@@ -54,8 +69,10 @@
import com.cloud.agent.transport.Request;
import com.cloud.agent.transport.Response;
import com.cloud.exception.AgentControlChannelException;
+import com.cloud.host.Host;
import com.cloud.resource.ServerResource;
import com.cloud.utils.PropertiesUtil;
+import com.cloud.utils.StringUtils;
import com.cloud.utils.backoff.BackoffAlgorithm;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.exception.CloudRuntimeException;
@@ -68,6 +85,7 @@
import com.cloud.utils.nio.Task;
import com.cloud.utils.script.OutputInterpreter;
import com.cloud.utils.script.Script;
+import com.google.common.base.Strings;
/**
* @config
@@ -111,6 +129,8 @@ public int value() {
Long _id;
Timer _timer = new Timer("Agent Timer");
+ Timer certTimer;
+ Timer hostLBTimer;
List _watchList = new ArrayList();
long _sequence = 0;
@@ -123,17 +143,22 @@ public int value() {
long _startupWait = _startupWaitDefault;
boolean _reconnectAllowed = true;
//For time sentitive task, e.g. PingTask
- private final ThreadPoolExecutor _ugentTaskPool;
+ ThreadPoolExecutor _ugentTaskPool;
ExecutorService _executor;
+ Thread _shutdownThread = new ShutdownThread(this);
+
+ private String _keystoreSetupPath;
+ private String _keystoreCertImportPath;
+
// for simulator use only
public Agent(final IAgentShell shell) {
_shell = shell;
_link = null;
- _connection = new NioClient("Agent", _shell.getHost(), _shell.getPort(), _shell.getWorkers(), this);
+ _connection = new NioClient("Agent", _shell.getNextHost(), _shell.getPort(), _shell.getWorkers(), this);
- Runtime.getRuntime().addShutdownHook(new ShutdownThread(this));
+ Runtime.getRuntime().addShutdownHook(_shutdownThread);
_ugentTaskPool =
new ThreadPoolExecutor(shell.getPingRetries(), 2 * shell.getPingRetries(), 10, TimeUnit.MINUTES, new SynchronousQueue(), new NamedThreadFactory(
@@ -166,12 +191,13 @@ public Agent(final IAgentShell shell, final int localAgentId, final ServerResour
throw new ConfigurationException("Unable to configure " + _resource.getName());
}
- _connection = new NioClient("Agent", _shell.getHost(), _shell.getPort(), _shell.getWorkers(), this);
+ final String host = _shell.getNextHost();
+ _connection = new NioClient("Agent", host, _shell.getPort(), _shell.getWorkers(), this);
// ((NioClient)_connection).setBindAddress(_shell.getPrivateIp());
s_logger.debug("Adding shutdown hook");
- Runtime.getRuntime().addShutdownHook(new ShutdownThread(this));
+ Runtime.getRuntime().addShutdownHook(_shutdownThread);
_ugentTaskPool =
new ThreadPoolExecutor(shell.getPingRetries(), 2 * shell.getPingRetries(), 10, TimeUnit.MINUTES, new SynchronousQueue(), new NamedThreadFactory(
@@ -182,7 +208,7 @@ public Agent(final IAgentShell shell, final int localAgentId, final ServerResour
"agentRequest-Handler"));
s_logger.info("Agent [id = " + (_id != null ? _id : "new") + " : type = " + getResourceName() + " : zone = " + _shell.getZone() + " : pod = " + _shell.getPod() +
- " : workers = " + _shell.getWorkers() + " : host = " + _shell.getHost() + " : port = " + _shell.getPort());
+ " : workers = " + _shell.getWorkers() + " : host = " + host + " : port = " + _shell.getPort());
}
public String getVersion() {
@@ -218,12 +244,41 @@ public String getResourceName() {
return _resource.getClass().getSimpleName();
}
+ /**
+ * In case of a software based agent restart, this method
+ * can help to perform explicit garbage collection of any old
+ * agent instances and its inner objects.
+ */
+ private void scavengeOldAgentObjects() {
+ _executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(2000L);
+ } catch (final InterruptedException ignored) {
+ } finally {
+ System.gc();
+ }
+ }
+ });
+ }
+
public void start() {
if (!_resource.start()) {
s_logger.error("Unable to start the resource: " + _resource.getName());
throw new CloudRuntimeException("Unable to start the resource: " + _resource.getName());
}
+ _keystoreSetupPath = Script.findScript("scripts/util/", KeyStoreUtils.KS_SETUP_SCRIPT);
+ if (_keystoreSetupPath == null) {
+ throw new CloudRuntimeException(String.format("Unable to find the '%s' script", KeyStoreUtils.KS_SETUP_SCRIPT));
+ }
+
+ _keystoreCertImportPath = Script.findScript("scripts/util/", KeyStoreUtils.KS_IMPORT_SCRIPT);
+ if (_keystoreCertImportPath == null) {
+ throw new CloudRuntimeException(String.format("Unable to find the '%s' script", KeyStoreUtils.KS_IMPORT_SCRIPT));
+ }
+
try {
_connection.start();
} catch (final NioConnectionException e) {
@@ -231,8 +286,10 @@ public void start() {
s_logger.info("Attempted to connect to the server, but received an unexpected exception, trying again...");
}
while (!_connection.isStartup()) {
+ final String host = _shell.getNextHost();
_shell.getBackoffAlgorithm().waitBeforeRetry();
- _connection = new NioClient("Agent", _shell.getHost(), _shell.getPort(), _shell.getWorkers(), this);
+ _connection = new NioClient("Agent", host, _shell.getPort(), _shell.getWorkers(), this);
+ s_logger.info("Connecting to host:" + host);
try {
_connection.start();
} catch (final NioConnectionException e) {
@@ -240,6 +297,8 @@ public void start() {
s_logger.info("Attempted to connect to the server, but received an unexpected exception, trying again...");
}
}
+ _shell.updateConnectedHost();
+ scavengeOldAgentObjects();
}
public void stop(final String reason, final String detail) {
@@ -264,6 +323,7 @@ public void stop(final String reason, final String detail) {
}
_connection.stop();
_connection = null;
+ _link = null;
}
if (_resource != null) {
@@ -271,7 +331,34 @@ public void stop(final String reason, final String detail) {
_resource = null;
}
- _ugentTaskPool.shutdownNow();
+ if (_startup != null) {
+ _startup = null;
+ }
+
+ if (_ugentTaskPool != null) {
+ _ugentTaskPool.shutdownNow();
+ _ugentTaskPool = null;
+ }
+
+ if (_executor != null) {
+ _executor.shutdown();
+ _executor = null;
+ }
+
+ if (_timer != null) {
+ _timer.cancel();
+ _timer = null;
+ }
+
+ if (hostLBTimer != null) {
+ hostLBTimer.cancel();
+ hostLBTimer = null;
+ }
+
+ if (certTimer != null) {
+ certTimer.cancel();
+ certTimer = null;
+ }
}
public Long getId() {
@@ -284,6 +371,26 @@ public void setId(final Long id) {
_shell.setPersistentProperty(getResourceName(), "id", Long.toString(id));
}
+ private synchronized void scheduleServicesRestartTask() {
+ if (certTimer != null) {
+ certTimer.cancel();
+ certTimer.purge();
+ }
+ certTimer = new Timer("Certificate Renewal Timer");
+ certTimer.schedule(new PostCertificateRenewalTask(this), 5000L);
+ }
+
+ private synchronized void scheduleHostLBCheckerTask(final long checkInterval) {
+ if (hostLBTimer != null) {
+ hostLBTimer.cancel();
+ }
+ if (checkInterval > 0L) {
+ s_logger.info("Scheduling preferred host timer task with host.lb.interval=" + checkInterval + "ms");
+ hostLBTimer = new Timer("Host LB Timer");
+ hostLBTimer.scheduleAtFixedRate(new PreferredHostCheckerTask(), checkInterval, checkInterval);
+ }
+ }
+
public void scheduleWatch(final Link link, final Request request, final long delay, final long period) {
synchronized (_watchList) {
if (s_logger.isDebugEnabled()) {
@@ -306,8 +413,8 @@ protected void cancelTasks() {
_watchList.clear();
}
}
- public synchronized void lockStartupTask(final Link link)
- {
+
+ public synchronized void lockStartupTask(final Link link) {
_startup = new StartupTask(link);
_timer.schedule(_startup, _startupWait);
}
@@ -315,9 +422,11 @@ public synchronized void lockStartupTask(final Link link)
public void sendStartup(final Link link) {
final StartupCommand[] startup = _resource.initialize();
if (startup != null) {
+ final String msHostList = _shell.getPersistentProperty(null, "host");
final Command[] commands = new Command[startup.length];
for (int i = 0; i < startup.length; i++) {
setupStartupCommand(startup[i]);
+ startup[i].setMSHostList(msHostList);
commands[i] = startup[i];
}
final Request request = new Request(_id != null ? _id : -1, -1, commands, false, false);
@@ -376,25 +485,17 @@ protected void reconnect(final Link link) {
}
}
- link.close();
- link.terminated();
+ if (link != null) {
+ link.close();
+ link.terminated();
+ }
setLink(null);
cancelTasks();
_resource.disconnected();
- int inProgress = 0;
- do {
- _shell.getBackoffAlgorithm().waitBeforeRetry();
-
- s_logger.info("Lost connection to the server. Dealing with the remaining commands...");
-
- inProgress = _inProgress.get();
- if (inProgress > 0) {
- s_logger.info("Cannot connect because we still have " + inProgress + " commands in progress.");
- }
- } while (inProgress > 0);
+ s_logger.info("Lost connection to host: " + _shell.getConnectedHost() + ". Attempting reconnection while we still have " + _inProgress.get() + " commands in progress.");
_connection.stop();
@@ -408,18 +509,26 @@ protected void reconnect(final Link link) {
_shell.getBackoffAlgorithm().waitBeforeRetry();
}
- _connection = new NioClient("Agent", _shell.getHost(), _shell.getPort(), _shell.getWorkers(), this);
+ final String host = _shell.getNextHost();
do {
- s_logger.info("Reconnecting...");
+ _connection = new NioClient("Agent", host, _shell.getPort(), _shell.getWorkers(), this);
+ s_logger.info("Reconnecting to host:" + host);
try {
_connection.start();
} catch (final NioConnectionException e) {
s_logger.warn("NIO Connection Exception " + e);
s_logger.info("Attempted to connect to the server, but received an unexpected exception, trying again...");
+ _connection.stop();
+ try {
+ _connection.cleanUp();
+ } catch (final IOException ex) {
+ s_logger.warn("Fail to clean up old connection. " + ex);
+ }
}
_shell.getBackoffAlgorithm().waitBeforeRetry();
} while (!_connection.isStartup());
- s_logger.info("Connected to the server");
+ _shell.updateConnectedHost();
+ s_logger.info("Connected to the host: " + _shell.getConnectedHost());
}
public void processStartupAnswer(final Answer answer, final Response response, final Link link) {
@@ -515,7 +624,17 @@ protected void processRequest(final Request request, final Link link) {
s_logger.warn("No handler found to process cmd: " + cmd.toString());
answer = new AgentControlAnswer(cmd);
}
-
+ } else if (cmd instanceof SetupKeyStoreCommand && ((SetupKeyStoreCommand) cmd).isHandleByAgent()) {
+ answer = setupAgentKeystore((SetupKeyStoreCommand) cmd);
+ } else if (cmd instanceof SetupCertificateCommand && ((SetupCertificateCommand) cmd).isHandleByAgent()) {
+ answer = setupAgentCertificate((SetupCertificateCommand) cmd);
+ if (Host.Type.Routing.equals(_resource.getType())) {
+ scheduleServicesRestartTask();
+ }
+ } else if (cmd instanceof SetupDirectDownloadCertificate) {
+ answer = setupDirectDownloadCertificate((SetupDirectDownloadCertificate) cmd);
+ } else if (cmd instanceof SetupMSListCommand) {
+ answer = setupManagementServerList((SetupMSListCommand) cmd);
} else {
if (cmd instanceof ReadyCommand) {
processReadyCommand(cmd);
@@ -565,6 +684,135 @@ protected void processRequest(final Request request, final Link link) {
}
}
+ private Answer setupDirectDownloadCertificate(SetupDirectDownloadCertificate cmd) {
+ String certificate = cmd.getCertificate();
+ String certificateName = cmd.getCertificateName();
+ s_logger.info("Importing certificate " + certificateName + " into keystore");
+
+ final File agentFile = PropertiesUtil.findConfigFile("agent.properties");
+ if (agentFile == null) {
+ return new Answer(cmd, false, "Failed to find agent.properties file");
+ }
+
+ final String keyStoreFile = agentFile.getParent() + "/" + KeyStoreUtils.KS_FILENAME;
+
+ String cerFile = agentFile.getParent() + "/" + certificateName + ".cer";
+ Script.runSimpleBashScript(String.format("echo '%s' > %s", certificate, cerFile));
+
+ String privatePasswordFormat = "sed -n '/keystore.passphrase/p' '%s' 2>/dev/null | sed 's/keystore.passphrase=//g' 2>/dev/null";
+ String privatePasswordCmd = String.format(privatePasswordFormat, agentFile.getAbsolutePath());
+ String privatePassword = Script.runSimpleBashScript(privatePasswordCmd);
+
+ String importCommandFormat = "keytool -importcert -file %s -keystore %s -alias '%s' -storepass '%s' -noprompt";
+ String importCmd = String.format(importCommandFormat, cerFile, keyStoreFile, certificateName, privatePassword);
+ Script.runSimpleBashScript(importCmd);
+ return new Answer(cmd, true, "Certificate " + certificateName + " imported");
+ }
+
+ public Answer setupAgentKeystore(final SetupKeyStoreCommand cmd) {
+ final String keyStorePassword = cmd.getKeystorePassword();
+ final long validityDays = cmd.getValidityDays();
+
+ s_logger.debug("Setting up agent keystore file and generating CSR");
+
+ final File agentFile = PropertiesUtil.findConfigFile("agent.properties");
+ if (agentFile == null) {
+ return new Answer(cmd, false, "Failed to find agent.properties file");
+ }
+ final String keyStoreFile = agentFile.getParent() + "/" + KeyStoreUtils.KS_FILENAME;
+ final String csrFile = agentFile.getParent() + "/" + KeyStoreUtils.CSR_FILENAME;
+
+ String storedPassword = _shell.getPersistentProperty(null, KeyStoreUtils.KS_PASSPHRASE_PROPERTY);
+ if (Strings.isNullOrEmpty(storedPassword)) {
+ storedPassword = keyStorePassword;
+ _shell.setPersistentProperty(null, KeyStoreUtils.KS_PASSPHRASE_PROPERTY, storedPassword);
+ }
+
+ Script script = new Script(_keystoreSetupPath, 60000, s_logger);
+ script.add(agentFile.getAbsolutePath());
+ script.add(keyStoreFile);
+ script.add(storedPassword);
+ script.add(String.valueOf(validityDays));
+ script.add(csrFile);
+ String result = script.execute();
+ if (result != null) {
+ throw new CloudRuntimeException("Unable to setup keystore file");
+ }
+
+ final String csrString;
+ try {
+ csrString = FileUtils.readFileToString(new File(csrFile), Charset.defaultCharset());
+ } catch (IOException e) {
+ throw new CloudRuntimeException("Unable to read generated CSR file", e);
+ }
+ return new SetupKeystoreAnswer(csrString);
+ }
+
+ private Answer setupAgentCertificate(final SetupCertificateCommand cmd) {
+ final String certificate = cmd.getCertificate();
+ final String privateKey = cmd.getPrivateKey();
+ final String caCertificates = cmd.getCaCertificates();
+
+ s_logger.debug("Importing received certificate to agent's keystore");
+
+ final File agentFile = PropertiesUtil.findConfigFile("agent.properties");
+ if (agentFile == null) {
+ return new Answer(cmd, false, "Failed to find agent.properties file");
+ }
+ final String keyStoreFile = agentFile.getParent() + "/" + KeyStoreUtils.KS_FILENAME;
+ final String certFile = agentFile.getParent() + "/" + KeyStoreUtils.CERT_FILENAME;
+ final String privateKeyFile = agentFile.getParent() + "/" + KeyStoreUtils.PKEY_FILENAME;
+ final String caCertFile = agentFile.getParent() + "/" + KeyStoreUtils.CACERT_FILENAME;
+
+ try {
+ FileUtils.writeStringToFile(new File(certFile), certificate, Charset.defaultCharset());
+ FileUtils.writeStringToFile(new File(caCertFile), caCertificates, Charset.defaultCharset());
+ s_logger.debug("Saved received client certificate to: " + certFile);
+ } catch (IOException e) {
+ throw new CloudRuntimeException("Unable to save received agent client and ca certificates", e);
+ }
+
+ Script script = new Script(_keystoreCertImportPath, 60000, s_logger);
+ script.add(agentFile.getAbsolutePath());
+ script.add(keyStoreFile);
+ script.add(KeyStoreUtils.AGENT_MODE);
+ script.add(certFile);
+ script.add("");
+ script.add(caCertFile);
+ script.add("");
+ script.add(privateKeyFile);
+ script.add(privateKey);
+ String result = script.execute();
+ if (result != null) {
+ throw new CloudRuntimeException("Unable to import certificate into keystore file");
+ }
+ return new SetupCertificateAnswer(true);
+ }
+
+ private void processManagementServerList(final List msList, final String lbAlgorithm, final Long lbCheckInterval) {
+ if (CollectionUtils.isNotEmpty(msList) && !Strings.isNullOrEmpty(lbAlgorithm)) {
+ try {
+ final String newMSHosts = String.format("%s%s%s", StringUtils.toCSVList(msList), IAgentShell.hostLbAlgorithmSeparator, lbAlgorithm);
+ _shell.setPersistentProperty(null, "host", newMSHosts);
+ _shell.setHosts(newMSHosts);
+ _shell.resetHostCounter();
+ s_logger.info("Processed new management server list: " + newMSHosts);
+ } catch (final Exception e) {
+ throw new CloudRuntimeException("Could not persist received management servers list", e);
+ }
+ }
+ if ("shuffle".equals(lbAlgorithm)) {
+ scheduleHostLBCheckerTask(0);
+ } else {
+ scheduleHostLBCheckerTask(_shell.getLbCheckerInterval(lbCheckInterval));
+ }
+ }
+
+ private Answer setupManagementServerList(final SetupMSListCommand cmd) {
+ processManagementServerList(cmd.getMsList(), cmd.getLbAlgorithm(), cmd.getLbCheckInterval());
+ return new SetupMSListAnswer(true);
+ }
+
public void processResponse(final Response response, final Link link) {
final Answer answer = response.getAnswer();
if (s_logger.isDebugEnabled()) {
@@ -585,15 +833,16 @@ public void processResponse(final Response response, final Link link) {
}
public void processReadyCommand(final Command cmd) {
-
final ReadyCommand ready = (ReadyCommand)cmd;
- s_logger.info("Proccess agent ready command, agent id = " + ready.getHostId());
+ s_logger.info("Processing agent ready command, agent id = " + ready.getHostId());
if (ready.getHostId() != null) {
setId(ready.getHostId());
}
- s_logger.info("Ready command is processed: agent id = " + getId());
+ processManagementServerList(ready.getMsHostList(), ready.getLbAlgorithm(), ready.getLbCheckInterval());
+
+ s_logger.info("Ready command is processed for agent id = " + getId());
}
public void processOtherTask(final Task task) {
@@ -875,4 +1124,98 @@ public void doTask(final Task task) throws TaskExecutionException {
}
}
}
+
+ /**
+ * Task stops the current agent and launches a new agent
+ * when there are no outstanding jobs in the agent's task queue
+ */
+ public class PostCertificateRenewalTask extends ManagedContextTimerTask {
+
+ private Agent agent;
+
+ public PostCertificateRenewalTask(final Agent agent) {
+ this.agent = agent;
+ }
+
+ @Override
+ protected void runInContext() {
+ while (true) {
+ try {
+ if (_inProgress.get() == 0) {
+ s_logger.debug("Running post certificate renewal task to restart services.");
+
+ // Let the resource perform any post certificate renewal cleanups
+ _resource.executeRequest(new PostCertificateRenewalCommand());
+
+ IAgentShell shell = agent._shell;
+ ServerResource resource = agent._resource.getClass().newInstance();
+
+ // Stop current agent
+ agent.cancelTasks();
+ agent._reconnectAllowed = false;
+ Runtime.getRuntime().removeShutdownHook(agent._shutdownThread);
+ agent.stop(ShutdownCommand.Requested, "Restarting due to new X509 certificates");
+
+ // Nullify references for GC
+ agent._shell = null;
+ agent._watchList = null;
+ agent._shutdownThread = null;
+ agent._controlListeners = null;
+ agent = null;
+
+ // Start a new agent instance
+ shell.launchNewAgent(resource);
+ return;
+ }
+ if (s_logger.isTraceEnabled()) {
+ s_logger.debug("Other tasks are in progress, will retry post certificate renewal command after few seconds");
+ }
+ Thread.sleep(5000);
+ } catch (final Exception e) {
+ s_logger.warn("Failed to execute post certificate renewal command:", e);
+ break;
+ }
+ }
+ }
+ }
+
+ public class PreferredHostCheckerTask extends ManagedContextTimerTask {
+
+ @Override
+ protected void runInContext() {
+ try {
+ final String[] msList = _shell.getHosts();
+ if (msList == null || msList.length < 1) {
+ return;
+ }
+ final String preferredHost = msList[0];
+ final String connectedHost = _shell.getConnectedHost();
+ if (s_logger.isTraceEnabled()) {
+ s_logger.trace("Running preferred host checker task, connected host=" + connectedHost + ", preferred host=" + preferredHost);
+ }
+ if (preferredHost != null && !preferredHost.equals(connectedHost) && _link != null) {
+ boolean isHostUp = true;
+ try (final Socket socket = new Socket()) {
+ socket.connect(new InetSocketAddress(preferredHost, _shell.getPort()), 5000);
+ } catch (final IOException e) {
+ isHostUp = false;
+ if (s_logger.isTraceEnabled()) {
+ s_logger.trace("Host: " + preferredHost + " is not reachable");
+ }
+ }
+ if (isHostUp && _link != null && _inProgress.get() == 0) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Preferred host " + preferredHost + " is found to be reachable, trying to reconnect");
+ }
+ _shell.resetHostCounter();
+ reconnect(_link);
+ }
+ }
+ } catch (Throwable t) {
+ s_logger.error("Error caught while attempting to connect to preferred host", t);
+ }
+ }
+
+ }
+
}
diff --git a/agent/src/com/cloud/agent/AgentShell.java b/agent/src/com/cloud/agent/AgentShell.java
index 5e0da68c6d66..01654ac9caa9 100644
--- a/agent/src/com/cloud/agent/AgentShell.java
+++ b/agent/src/com/cloud/agent/AgentShell.java
@@ -50,6 +50,7 @@
import com.cloud.utils.backoff.BackoffAlgorithm;
import com.cloud.utils.backoff.impl.ConstantTimeBackoff;
import com.cloud.utils.exception.CloudRuntimeException;
+import com.google.common.base.Strings;
public class AgentShell implements IAgentShell, Daemon {
private static final Logger s_logger = Logger.getLogger(AgentShell.class.getName());
@@ -67,10 +68,14 @@ public class AgentShell implements IAgentShell, Daemon {
private int _proxyPort;
private int _workers;
private String _guid;
+ private int _hostCounter = 0;
private int _nextAgentId = 1;
private volatile boolean _exit = false;
private int _pingRetries;
private final List _agents = new ArrayList();
+ private String hostToConnect;
+ private String connectedHost;
+ private Long preferredHostCheckInterval;
public AgentShell() {
}
@@ -106,8 +111,54 @@ public String getPod() {
}
@Override
- public String getHost() {
- return _host;
+ public String getNextHost() {
+ final String[] hosts = getHosts();
+ if (_hostCounter >= hosts.length) {
+ _hostCounter = 0;
+ }
+ hostToConnect = hosts[_hostCounter % hosts.length];
+ _hostCounter++;
+ return hostToConnect;
+ }
+
+ @Override
+ public String getConnectedHost() {
+ return connectedHost;
+ }
+
+ @Override
+ public long getLbCheckerInterval(final Long receivedLbInterval) {
+ if (preferredHostCheckInterval != null) {
+ return preferredHostCheckInterval * 1000L;
+ }
+ if (receivedLbInterval != null) {
+ return receivedLbInterval * 1000L;
+ }
+ return 0L;
+ }
+
+ @Override
+ public void updateConnectedHost() {
+ connectedHost = hostToConnect;
+ }
+
+
+ @Override
+ public void resetHostCounter() {
+ _hostCounter = 0;
+ }
+
+ @Override
+ public String[] getHosts() {
+ return _host.split(",");
+ }
+
+ @Override
+ public void setHosts(final String host) {
+ if (!Strings.isNullOrEmpty(host)) {
+ _host = host.split(hostLbAlgorithmSeparator)[0];
+ resetHostCounter();
+ }
}
@Override
@@ -240,7 +291,8 @@ protected boolean parseCommand(final String[] args) throws ConfigurationExceptio
if (host == null) {
host = "localhost";
}
- _host = host;
+
+ setHosts(host);
if (zone != null)
_zone = zone;
@@ -280,6 +332,9 @@ protected boolean parseCommand(final String[] args) throws ConfigurationExceptio
_properties.setProperty("guid", _guid);
}
+ String val = getProperty(null, preferredHostIntervalKey);
+ preferredHostCheckInterval = (Strings.isNullOrEmpty(val) ? null : Long.valueOf(val));
+
return true;
}
@@ -364,7 +419,7 @@ private void launchAgentFromClassInfo(String resourceClassNames) throws Configur
final Constructor> constructor = impl.getDeclaredConstructor();
constructor.setAccessible(true);
ServerResource resource = (ServerResource)constructor.newInstance();
- launchAgent(getNextAgentId(), resource);
+ launchNewAgent(resource);
} catch (final ClassNotFoundException e) {
throw new ConfigurationException("Resource class not found: " + name + " due to: " + e.toString());
} catch (final SecurityException e) {
@@ -392,9 +447,10 @@ private void launchAgentFromTypeInfo() throws ConfigurationException {
s_logger.trace("Launching agent based on type=" + typeInfo);
}
- private void launchAgent(int localAgentId, ServerResource resource) throws ConfigurationException {
+ public void launchNewAgent(ServerResource resource) throws ConfigurationException {
// we don't track agent after it is launched for now
- Agent agent = new Agent(this, localAgentId, resource);
+ _agents.clear();
+ Agent agent = new Agent(this, getNextAgentId(), resource);
_agents.add(agent);
agent.start();
}
diff --git a/agent/src/com/cloud/agent/IAgentShell.java b/agent/src/com/cloud/agent/IAgentShell.java
index dde67381a4af..5d389a07041b 100644
--- a/agent/src/com/cloud/agent/IAgentShell.java
+++ b/agent/src/com/cloud/agent/IAgentShell.java
@@ -19,36 +19,56 @@
import java.util.Map;
import java.util.Properties;
+import javax.naming.ConfigurationException;
+
+import com.cloud.resource.ServerResource;
import com.cloud.utils.backoff.BackoffAlgorithm;
public interface IAgentShell {
- public Map getCmdLineProperties();
+ String hostLbAlgorithmSeparator = "@";
+ String preferredHostIntervalKey = "host.lb.check.interval";
+
+ Map getCmdLineProperties();
+
+ Properties getProperties();
+
+ String getPersistentProperty(String prefix, String name);
+
+ void setPersistentProperty(String prefix, String name, String value);
+
+ String getNextHost();
+
+ String getPrivateIp();
+
+ int getPort();
+
+ int getWorkers();
- public Properties getProperties();
+ int getProxyPort();
- public String getPersistentProperty(String prefix, String name);
+ String getGuid();
- public void setPersistentProperty(String prefix, String name, String value);
+ String getZone();
- public String getHost();
+ String getPod();
- public String getPrivateIp();
+ BackoffAlgorithm getBackoffAlgorithm();
- public int getPort();
+ int getPingRetries();
- public int getWorkers();
+ String getVersion();
- public int getProxyPort();
+ void setHosts(String hosts);
- public String getGuid();
+ void resetHostCounter();
- public String getZone();
+ String[] getHosts();
- public String getPod();
+ long getLbCheckerInterval(Long receivedLbInterval);
- public BackoffAlgorithm getBackoffAlgorithm();
+ void updateConnectedHost();
- public int getPingRetries();
+ String getConnectedHost();
- public String getVersion();
+ void launchNewAgent(ServerResource resource) throws ConfigurationException;
}
diff --git a/agent/src/com/cloud/agent/dao/impl/PropertiesStorage.java b/agent/src/com/cloud/agent/dao/impl/PropertiesStorage.java
index df1b1ea7b271..a1db88c86c48 100644
--- a/agent/src/com/cloud/agent/dao/impl/PropertiesStorage.java
+++ b/agent/src/com/cloud/agent/dao/impl/PropertiesStorage.java
@@ -23,8 +23,6 @@
import java.util.Map;
import java.util.Properties;
-import javax.ejb.Local;
-
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
@@ -37,7 +35,6 @@
* @config {@table || Param Name | Description | Values | Default || || path |
* path to the properties _file | String | db/db.properties || * }
**/
-@Local(value = {StorageComponent.class})
public class PropertiesStorage implements StorageComponent {
private static final Logger s_logger = Logger.getLogger(PropertiesStorage.class);
Properties _properties = new Properties();
@@ -51,6 +48,9 @@ public synchronized String get(String key) {
@Override
public synchronized void persist(String key, String value) {
+ if (!loadFromFile(_file)) {
+ s_logger.error("Failed to load changes and then write to them");
+ }
_properties.setProperty(key, value);
FileOutputStream output = null;
try {
@@ -65,6 +65,20 @@ public synchronized void persist(String key, String value) {
}
}
+ private synchronized boolean loadFromFile(final File file) {
+ try {
+ PropertiesUtil.loadFromFile(_properties, file);
+ _file = file;
+ } catch (FileNotFoundException e) {
+ s_logger.error("How did we get here? ", e);
+ return false;
+ } catch (IOException e) {
+ s_logger.error("IOException: ", e);
+ return false;
+ }
+ return true;
+ }
+
@Override
public synchronized boolean configure(String name, Map params) {
_name = name;
@@ -86,17 +100,7 @@ public synchronized boolean configure(String name, Map params) {
return false;
}
}
- try {
- PropertiesUtil.loadFromFile(_properties, file);
- _file = file;
- } catch (FileNotFoundException e) {
- s_logger.error("How did we get here? ", e);
- return false;
- } catch (IOException e) {
- s_logger.error("IOException: ", e);
- return false;
- }
- return true;
+ return loadFromFile(file);
}
@Override
diff --git a/agent/src/com/cloud/agent/dhcp/FakeDhcpSnooper.java b/agent/src/com/cloud/agent/dhcp/FakeDhcpSnooper.java
index 8509b438f5bc..c42a5af814d1 100644
--- a/agent/src/com/cloud/agent/dhcp/FakeDhcpSnooper.java
+++ b/agent/src/com/cloud/agent/dhcp/FakeDhcpSnooper.java
@@ -24,7 +24,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
-import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
@@ -32,7 +31,6 @@
import com.cloud.utils.Pair;
import com.cloud.utils.net.NetUtils;
-@Local(value = {DhcpSnooper.class})
public class FakeDhcpSnooper implements DhcpSnooper {
private static final Logger s_logger = Logger.getLogger(FakeDhcpSnooper.class);
private Queue _ipAddresses = new ConcurrentLinkedQueue();
diff --git a/agent/src/com/cloud/agent/direct/download/DirectTemplateDownloader.java b/agent/src/com/cloud/agent/direct/download/DirectTemplateDownloader.java
new file mode 100644
index 000000000000..a88b4526e9d9
--- /dev/null
+++ b/agent/src/com/cloud/agent/direct/download/DirectTemplateDownloader.java
@@ -0,0 +1,71 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.agent.direct.download;
+
+public interface DirectTemplateDownloader {
+
+ class DirectTemplateInformation {
+ private String installPath;
+ private Long size;
+ private String checksum;
+
+ public DirectTemplateInformation(String installPath, Long size, String checksum) {
+ this.installPath = installPath;
+ this.size = size;
+ this.checksum = checksum;
+ }
+
+ public String getInstallPath() {
+ return installPath;
+ }
+
+ public Long getSize() {
+ return size;
+ }
+
+ public String getChecksum() {
+ return checksum;
+ }
+ }
+
+ /**
+ * Perform template download to pool specified on downloader creation
+ * @return true if successful, false if not
+ */
+ boolean downloadTemplate();
+
+ /**
+ * Perform extraction (if necessary) and installation of previously downloaded template
+ * @return true if successful, false if not
+ */
+ boolean extractAndInstallDownloadedTemplate();
+
+ /**
+ * Get template information after it is properly installed on pool
+ * @return template information
+ */
+ DirectTemplateInformation getTemplateInformation();
+
+ /**
+ * Perform checksum validation of previously downloadeed template
+ * @return true if successful, false if not
+ */
+ boolean validateChecksum();
+}
diff --git a/agent/src/com/cloud/agent/direct/download/DirectTemplateDownloaderImpl.java b/agent/src/com/cloud/agent/direct/download/DirectTemplateDownloaderImpl.java
new file mode 100644
index 000000000000..419ab7d1bbde
--- /dev/null
+++ b/agent/src/com/cloud/agent/direct/download/DirectTemplateDownloaderImpl.java
@@ -0,0 +1,220 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package com.cloud.agent.direct.download;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+import org.apache.cloudstack.utils.security.DigestHelper;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.UUID;
+
+public abstract class DirectTemplateDownloaderImpl implements DirectTemplateDownloader {
+
+ private String url;
+ private String destPoolPath;
+ private Long templateId;
+ private String downloadedFilePath;
+ private String installPath;
+ private String checksum;
+ private boolean redownload = false;
+ public static final Logger s_logger = Logger.getLogger(DirectTemplateDownloaderImpl.class.getName());
+
+ protected DirectTemplateDownloaderImpl(final String url, final String destPoolPath, final Long templateId, final String checksum) {
+ this.url = url;
+ this.destPoolPath = destPoolPath;
+ this.templateId = templateId;
+ this.checksum = checksum;
+ }
+
+ private static String directDownloadDir = "template";
+
+ /**
+ * Return direct download temporary path to download template
+ */
+ protected static String getDirectDownloadTempPath(Long templateId) {
+ String templateIdAsString = String.valueOf(templateId);
+ return directDownloadDir + File.separator + templateIdAsString.substring(0,1) +
+ File.separator + templateIdAsString;
+ }
+
+ /**
+ * Create folder on path if it does not exist
+ */
+ protected void createFolder(String path) {
+ File dir = new File(path);
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getDestPoolPath() {
+ return destPoolPath;
+ }
+
+ public Long getTemplateId() {
+ return templateId;
+ }
+
+ public String getDownloadedFilePath() {
+ return downloadedFilePath;
+ }
+
+ public void setDownloadedFilePath(String filePath) {
+ this.downloadedFilePath = filePath;
+ }
+
+ public String getChecksum() {
+ return checksum;
+ }
+
+ public void setChecksum(String checksum) {
+ this.checksum = checksum;
+ }
+
+ public boolean isRedownload() {
+ return redownload;
+ }
+
+ /**
+ * Return filename from url
+ */
+ public String getFileNameFromUrl() {
+ String[] urlParts = url.split("/");
+ return urlParts[urlParts.length - 1];
+ }
+
+ /**
+ * Checks if downloaded template is extractable
+ * @return true if it should be extracted, false if not
+ */
+ private boolean isTemplateExtractable() {
+ String type = Script.runSimpleBashScript("file " + downloadedFilePath + " | awk -F' ' '{print $2}'");
+ return type.equalsIgnoreCase("bzip2") || type.equalsIgnoreCase("gzip") || type.equalsIgnoreCase("zip");
+ }
+
+ @Override
+ public boolean extractAndInstallDownloadedTemplate() {
+ installPath = UUID.randomUUID().toString();
+ if (isTemplateExtractable()) {
+ extractDownloadedTemplate();
+ } else {
+ Script.runSimpleBashScript("mv " + downloadedFilePath + " " + getInstallFullPath());
+ }
+ return true;
+ }
+
+ /**
+ * Return install full path
+ */
+ private String getInstallFullPath() {
+ return destPoolPath + File.separator + installPath;
+ }
+
+ /**
+ * Return extract command to execute given downloaded file
+ */
+ private String getExtractCommandForDownloadedFile() {
+ if (downloadedFilePath.endsWith(".zip")) {
+ return "unzip -p " + downloadedFilePath + " | cat > " + getInstallFullPath();
+ } else if (downloadedFilePath.endsWith(".bz2")) {
+ return "bunzip2 -c " + downloadedFilePath + " > " + getInstallFullPath();
+ } else if (downloadedFilePath.endsWith(".gz")) {
+ return "gunzip -c " + downloadedFilePath + " > " + getInstallFullPath();
+ } else {
+ throw new CloudRuntimeException("Unable to extract template " + templateId + " on " + downloadedFilePath);
+ }
+ }
+
+ /**
+ * Extract downloaded template into installPath, remove compressed file
+ */
+ private void extractDownloadedTemplate() {
+ String extractCommand = getExtractCommandForDownloadedFile();
+ Script.runSimpleBashScript(extractCommand);
+ Script.runSimpleBashScript("rm -f " + downloadedFilePath);
+ }
+
+ @Override
+ public DirectTemplateInformation getTemplateInformation() {
+ String sizeResult = Script.runSimpleBashScript("ls -als " + getInstallFullPath() + " | awk '{print $1}'");
+ long size = Long.parseLong(sizeResult);
+ return new DirectTemplateInformation(installPath, size, checksum);
+ }
+
+ @Override
+ public boolean validateChecksum() {
+ if (StringUtils.isNotBlank(checksum)) {
+ int retry = 3;
+ boolean valid = false;
+ try {
+ while (!valid && retry > 0) {
+ retry--;
+ s_logger.info("Performing checksum validation for downloaded template " + templateId + " using " + checksum + ", retries left: " + retry);
+ valid = DigestHelper.check(checksum, new FileInputStream(downloadedFilePath));
+ if (!valid && retry > 0) {
+ s_logger.info("Checksum validation failded, re-downloading template");
+ redownload = true;
+ resetDownloadFile();
+ downloadTemplate();
+ }
+ }
+ s_logger.info("Checksum validation for template " + templateId + ": " + (valid ? "succeeded" : "failed"));
+ return valid;
+ } catch (IOException e) {
+ throw new CloudRuntimeException("could not check sum for file: " + downloadedFilePath, e);
+ } catch (NoSuchAlgorithmException e) {
+ throw new CloudRuntimeException("Unknown checksum algorithm: " + checksum, e);
+ }
+ }
+ s_logger.info("No checksum provided, skipping checksum validation");
+ return true;
+ }
+
+ /**
+ * Delete and create download file
+ */
+ private void resetDownloadFile() {
+ File f = new File(getDownloadedFilePath());
+ s_logger.info("Resetting download file: " + getDownloadedFilePath() + ", in order to re-download and persist template " + templateId + " on it");
+ try {
+ if (f.exists()) {
+ f.delete();
+ }
+ f.createNewFile();
+ } catch (IOException e) {
+ s_logger.error("Error creating file to download on: " + getDownloadedFilePath() + " due to: " + e.getMessage());
+ throw new CloudRuntimeException("Failed to create download file for direct download");
+ }
+ }
+
+}
diff --git a/agent/src/com/cloud/agent/direct/download/HttpDirectTemplateDownloader.java b/agent/src/com/cloud/agent/direct/download/HttpDirectTemplateDownloader.java
new file mode 100644
index 000000000000..147ccabf8fc8
--- /dev/null
+++ b/agent/src/com/cloud/agent/direct/download/HttpDirectTemplateDownloader.java
@@ -0,0 +1,104 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.agent.direct.download;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class HttpDirectTemplateDownloader extends DirectTemplateDownloaderImpl {
+
+ protected HttpClient client;
+ private static final MultiThreadedHttpConnectionManager s_httpClientManager = new MultiThreadedHttpConnectionManager();
+ public static final Logger s_logger = Logger.getLogger(HttpDirectTemplateDownloader.class.getName());
+ protected GetMethod request;
+ protected Map reqHeaders = new HashMap<>();
+
+ public HttpDirectTemplateDownloader(String url, Long templateId, String destPoolPath, String checksum, Map headers) {
+ super(url, destPoolPath, templateId, checksum);
+ s_httpClientManager.getParams().setConnectionTimeout(5000);
+ s_httpClientManager.getParams().setSoTimeout(5000);
+ client = new HttpClient(s_httpClientManager);
+ request = createRequest(url, headers);
+ String downloadDir = getDirectDownloadTempPath(templateId);
+ createTemporaryDirectoryAndFile(downloadDir);
+ }
+
+ protected void createTemporaryDirectoryAndFile(String downloadDir) {
+ createFolder(getDestPoolPath() + File.separator + downloadDir);
+ File f = new File(getDestPoolPath() + File.separator + downloadDir + File.separator + getFileNameFromUrl());
+ setDownloadedFilePath(f.getAbsolutePath());
+ }
+
+ protected GetMethod createRequest(String downloadUrl, Map headers) {
+ GetMethod request = new GetMethod(downloadUrl);
+ request.setFollowRedirects(true);
+ if (MapUtils.isNotEmpty(headers)) {
+ for (String key : headers.keySet()) {
+ request.setRequestHeader(key, headers.get(key));
+ reqHeaders.put(key, headers.get(key));
+ }
+ }
+ return request;
+ }
+
+ @Override
+ public boolean downloadTemplate() {
+ try {
+ int status = client.executeMethod(request);
+ if (status != HttpStatus.SC_OK) {
+ s_logger.warn("Not able to download template, status code: " + status);
+ return false;
+ }
+ return performDownload();
+ } catch (IOException e) {
+ throw new CloudRuntimeException("Error on HTTP request: " + e.getMessage());
+ } finally {
+ request.releaseConnection();
+ }
+ }
+
+ protected boolean performDownload() {
+ s_logger.info("Downloading template " + getTemplateId() + " from " + getUrl() + " to: " + getDownloadedFilePath());
+ try (
+ InputStream in = request.getResponseBodyAsStream();
+ OutputStream out = new FileOutputStream(getDownloadedFilePath());
+ ) {
+ IOUtils.copy(in, out);
+ } catch (IOException e) {
+ s_logger.error("Error downloading template " + getTemplateId() + " due to: " + e.getMessage());
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/agent/src/com/cloud/agent/direct/download/HttpsDirectTemplateDownloader.java b/agent/src/com/cloud/agent/direct/download/HttpsDirectTemplateDownloader.java
new file mode 100644
index 000000000000..38f59837cd83
--- /dev/null
+++ b/agent/src/com/cloud/agent/direct/download/HttpsDirectTemplateDownloader.java
@@ -0,0 +1,129 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.agent.direct.download;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.commons.collections.MapUtils;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContexts;
+
+import javax.net.ssl.SSLContext;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.Map;
+
+public class HttpsDirectTemplateDownloader extends HttpDirectTemplateDownloader {
+
+ private CloseableHttpClient httpsClient;
+ private HttpUriRequest req;
+
+ public HttpsDirectTemplateDownloader(String url, Long templateId, String destPoolPath, String checksum, Map headers) {
+ super(url, templateId, destPoolPath, checksum, headers);
+ SSLContext sslcontext = null;
+ try {
+ sslcontext = getSSLContext();
+ } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | KeyManagementException e) {
+ throw new CloudRuntimeException("Failure getting SSL context for HTTPS downloader: " + e.getMessage());
+ }
+ SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+ RequestConfig config = RequestConfig.custom()
+ .setConnectTimeout(5000)
+ .setConnectionRequestTimeout(5000)
+ .setSocketTimeout(5000).build();
+ httpsClient = HttpClients.custom().setSSLSocketFactory(factory).setDefaultRequestConfig(config).build();
+ createUriRequest(url, headers);
+ }
+
+ protected void createUriRequest(String downloadUrl, Map headers) {
+ req = new HttpGet(downloadUrl);
+ if (MapUtils.isNotEmpty(headers)) {
+ for (String headerKey: headers.keySet()) {
+ req.setHeader(headerKey, headers.get(headerKey));
+ }
+ }
+ }
+
+ private SSLContext getSSLContext() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException {
+ KeyStore trustStore = KeyStore.getInstance("jks");
+ FileInputStream instream = new FileInputStream(new File("/etc/cloudstack/agent/cloud.jks"));
+ try {
+ String privatePasswordFormat = "sed -n '/keystore.passphrase/p' '%s' 2>/dev/null | sed 's/keystore.passphrase=//g' 2>/dev/null";
+ String privatePasswordCmd = String.format(privatePasswordFormat, "/etc/cloudstack/agent/agent.properties");
+ String privatePassword = Script.runSimpleBashScript(privatePasswordCmd);
+ trustStore.load(instream, privatePassword.toCharArray());
+ } finally {
+ instream.close();
+ }
+ return SSLContexts.custom()
+ .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
+ .build();
+ }
+
+ @Override
+ public boolean downloadTemplate() {
+ CloseableHttpResponse response;
+ try {
+ response = httpsClient.execute(req);
+ } catch (IOException e) {
+ throw new CloudRuntimeException("Error on HTTPS request: " + e.getMessage());
+ }
+ return consumeResponse(response);
+ }
+
+ /**
+ * Consume response and persist it on getDownloadedFilePath() file
+ */
+ protected boolean consumeResponse(CloseableHttpResponse response) {
+ s_logger.info("Downloading template " + getTemplateId() + " from " + getUrl() + " to: " + getDownloadedFilePath());
+ if (response.getStatusLine().getStatusCode() != 200) {
+ throw new CloudRuntimeException("Error on HTTPS response");
+ }
+ try {
+ HttpEntity entity = response.getEntity();
+ InputStream in = entity.getContent();
+ OutputStream out = new FileOutputStream(getDownloadedFilePath());
+ IOUtils.copy(in, out);
+ } catch (Exception e) {
+ s_logger.error("Error parsing response for template " + getTemplateId() + " due to: " + e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/agent/src/com/cloud/agent/direct/download/MetalinkDirectTemplateDownloader.java b/agent/src/com/cloud/agent/direct/download/MetalinkDirectTemplateDownloader.java
new file mode 100644
index 000000000000..2fd8ba036111
--- /dev/null
+++ b/agent/src/com/cloud/agent/direct/download/MetalinkDirectTemplateDownloader.java
@@ -0,0 +1,98 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package com.cloud.agent.direct.download;
+
+import com.cloud.utils.UriUtils;
+import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+public class MetalinkDirectTemplateDownloader extends HttpDirectTemplateDownloader {
+
+ private String metalinkUrl;
+ private List metalinkUrls;
+ private List metalinkChecksums;
+ private Random random = new Random();
+ private static final Logger s_logger = Logger.getLogger(MetalinkDirectTemplateDownloader.class.getName());
+
+ public MetalinkDirectTemplateDownloader(String url, String destPoolPath, Long templateId, String checksum, Map headers) {
+ super(url, templateId, destPoolPath, checksum, headers);
+ metalinkUrl = url;
+ metalinkUrls = UriUtils.getMetalinkUrls(metalinkUrl);
+ metalinkChecksums = UriUtils.getMetalinkChecksums(metalinkUrl);
+ if (CollectionUtils.isEmpty(metalinkUrls)) {
+ throw new CloudRuntimeException("No urls found on metalink file: " + metalinkUrl + ". Not possible to download template " + templateId);
+ }
+ setUrl(metalinkUrls.get(0));
+ s_logger.info("Metalink downloader created, metalink url: " + metalinkUrl + " parsed - " +
+ metalinkUrls.size() + " urls and " +
+ (CollectionUtils.isNotEmpty(metalinkChecksums) ? metalinkChecksums.size() : "0") + " checksums found");
+ }
+
+ @Override
+ public boolean downloadTemplate() {
+ if (StringUtils.isBlank(getUrl())) {
+ throw new CloudRuntimeException("Download url has not been set, aborting");
+ }
+ String downloadDir = getDirectDownloadTempPath(getTemplateId());
+ boolean downloaded = false;
+ int i = 0;
+ do {
+ if (!isRedownload()) {
+ setUrl(metalinkUrls.get(i));
+ }
+ s_logger.info("Trying to download template from url: " + getUrl());
+ try {
+ File f = new File(getDestPoolPath() + File.separator + downloadDir + File.separator + getFileNameFromUrl());
+ if (f.exists()) {
+ f.delete();
+ f.createNewFile();
+ }
+ setDownloadedFilePath(f.getAbsolutePath());
+ request = createRequest(getUrl(), reqHeaders);
+ downloaded = super.downloadTemplate();
+ if (downloaded) {
+ s_logger.info("Successfully downloaded template from url: " + getUrl());
+ }
+
+ } catch (Exception e) {
+ s_logger.error("Error downloading template: " + getTemplateId() + " from " + getUrl() + ": " + e.getMessage());
+ }
+ i++;
+ }
+ while (!downloaded && !isRedownload() && i < metalinkUrls.size());
+ return downloaded;
+ }
+
+ @Override
+ public boolean validateChecksum() {
+ if (StringUtils.isBlank(getChecksum()) && CollectionUtils.isNotEmpty(metalinkChecksums)) {
+ String chk = metalinkChecksums.get(random.nextInt(metalinkChecksums.size()));
+ setChecksum(chk);
+ s_logger.info("Checksum not provided but " + metalinkChecksums.size() + " found on metalink file, performing checksum using one of them: " + chk);
+ }
+ return super.validateChecksum();
+ }
+}
diff --git a/agent/src/com/cloud/agent/direct/download/NfsDirectTemplateDownloader.java b/agent/src/com/cloud/agent/direct/download/NfsDirectTemplateDownloader.java
new file mode 100644
index 000000000000..16901afedf1b
--- /dev/null
+++ b/agent/src/com/cloud/agent/direct/download/NfsDirectTemplateDownloader.java
@@ -0,0 +1,70 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package com.cloud.agent.direct.download;
+
+import com.cloud.utils.UriUtils;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.UUID;
+
+public class NfsDirectTemplateDownloader extends DirectTemplateDownloaderImpl {
+
+ private String srcHost;
+ private String srcPath;
+
+ private static final String mountCommand = "mount -t nfs %s %s";
+
+ /**
+ * Parse url and set srcHost and srcPath
+ */
+ private void parseUrl() {
+ URI uri = null;
+ String url = getUrl();
+ try {
+ uri = new URI(UriUtils.encodeURIComponent(url));
+ if (uri.getScheme() != null && uri.getScheme().equalsIgnoreCase("nfs")) {
+ srcHost = uri.getHost();
+ srcPath = uri.getPath();
+ }
+ } catch (URISyntaxException e) {
+ throw new CloudRuntimeException("Invalid NFS url " + url + " caused error: " + e.getMessage());
+ }
+ }
+
+ public NfsDirectTemplateDownloader(String url, String destPool, Long templateId, String checksum) {
+ super(url, destPool, templateId, checksum);
+ parseUrl();
+ }
+
+ @Override
+ public boolean downloadTemplate() {
+ String mountSrcUuid = UUID.randomUUID().toString();
+ String mount = String.format(mountCommand, srcHost + ":" + srcPath, "/mnt/" + mountSrcUuid);
+ Script.runSimpleBashScript(mount);
+ String downloadDir = getDestPoolPath() + File.separator + getDirectDownloadTempPath(getTemplateId());
+ setDownloadedFilePath(downloadDir + File.separator + getFileNameFromUrl());
+ Script.runSimpleBashScript("cp /mnt/" + mountSrcUuid + srcPath + " " + getDownloadedFilePath());
+ Script.runSimpleBashScript("umount /mnt/" + mountSrcUuid);
+ return true;
+ }
+}
diff --git a/agent/src/com/cloud/agent/resource/DummyResource.java b/agent/src/com/cloud/agent/resource/DummyResource.java
index c0167f635983..fe519ca9497f 100644
--- a/agent/src/com/cloud/agent/resource/DummyResource.java
+++ b/agent/src/com/cloud/agent/resource/DummyResource.java
@@ -22,8 +22,6 @@
import java.util.Map;
import java.util.UUID;
-import javax.ejb.Local;
-
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.CheckNetworkAnswer;
@@ -43,7 +41,6 @@
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.utils.StringUtils;
-@Local(value = {ServerResource.class})
public class DummyResource implements ServerResource {
String _name;
Host.Type _type;
diff --git a/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java b/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java
index 08f098239865..b3b17e7d970b 100644
--- a/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java
+++ b/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java
@@ -32,11 +32,8 @@
import javax.naming.ConfigurationException;
-import org.apache.log4j.Logger;
-
-import com.google.gson.Gson;
-
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
+import org.apache.log4j.Logger;
import com.cloud.agent.Agent.ExitStatus;
import com.cloud.agent.api.AgentControlAnswer;
@@ -62,8 +59,10 @@
import com.cloud.resource.ServerResource;
import com.cloud.resource.ServerResourceBase;
import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.ReflectUtil;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.script.Script;
+import com.google.gson.Gson;
/**
*
@@ -240,9 +239,11 @@ public boolean configure(String name, Map params) throws Configu
_proxyVmId = NumbersUtil.parseLong(value, 0);
if (_localgw != null) {
- String mgmtHost = (String)params.get("host");
+ String mgmtHosts = (String)params.get("host");
if (_eth1ip != null) {
- addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, mgmtHost);
+ for (final String mgmtHost : mgmtHosts.split(",")) {
+ addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, mgmtHost);
+ }
String internalDns1 = (String) params.get("internaldns1");
if (internalDns1 == null) {
s_logger.warn("No DNS entry found during configuration of NfsSecondaryStorage");
@@ -275,12 +276,12 @@ private void addRouteToInternalIpOrCidr(String localgw, String eth1ip, String et
s_logger.debug("addRouteToInternalIp: destIp is null");
return;
}
- if (!NetUtils.isValidIp(destIpOrCidr) && !NetUtils.isValidCIDR(destIpOrCidr)) {
+ if (!NetUtils.isValidIp4(destIpOrCidr) && !NetUtils.isValidIp4Cidr(destIpOrCidr)) {
s_logger.warn(" destIp is not a valid ip address or cidr destIp=" + destIpOrCidr);
return;
}
boolean inSameSubnet = false;
- if (NetUtils.isValidIp(destIpOrCidr)) {
+ if (NetUtils.isValidIp4(destIpOrCidr)) {
if (eth1ip != null && eth1mask != null) {
inSameSubnet = NetUtils.sameSubnet(eth1ip, destIpOrCidr, eth1mask);
} else {
@@ -315,20 +316,19 @@ public String getName() {
private void launchConsoleProxy(final byte[] ksBits, final String ksPassword, final String encryptorPassword) {
final Object resource = this;
+ s_logger.info("Building class loader for com.cloud.consoleproxy.ConsoleProxy");
+ final ClassLoader loader = ReflectUtil.getClassLoaderForName("console-proxy");
if (_consoleProxyMain == null) {
+ s_logger.info("Running com.cloud.consoleproxy.ConsoleProxy with encryptor password=" + encryptorPassword);
_consoleProxyMain = new Thread(new ManagedContextRunnable() {
@Override
protected void runInContext() {
try {
- Class> consoleProxyClazz = Class.forName("com.cloud.consoleproxy.ConsoleProxy");
+ Class> consoleProxyClazz = loader.loadClass("com.cloud.consoleproxy.ConsoleProxy");
try {
- s_logger.info("Invoke setEncryptorPassword(), ecnryptorPassword: " + encryptorPassword);
- Method methodSetup = consoleProxyClazz.getMethod("setEncryptorPassword", String.class);
- methodSetup.invoke(null, encryptorPassword);
-
s_logger.info("Invoke startWithContext()");
- Method method = consoleProxyClazz.getMethod("startWithContext", Properties.class, Object.class, byte[].class, String.class);
- method.invoke(null, _properties, resource, ksBits, ksPassword);
+ Method method = consoleProxyClazz.getMethod("startWithContext", Properties.class, Object.class, byte[].class, String.class, String.class);
+ method.invoke(null, _properties, resource, ksBits, ksPassword, encryptorPassword);
} catch (SecurityException e) {
s_logger.error("Unable to launch console proxy due to SecurityException", e);
System.exit(ExitStatus.Error.value());
@@ -357,7 +357,7 @@ protected void runInContext() {
s_logger.info("com.cloud.consoleproxy.ConsoleProxy is already running");
try {
- Class> consoleProxyClazz = Class.forName("com.cloud.consoleproxy.ConsoleProxy");
+ Class> consoleProxyClazz = loader.loadClass("com.cloud.consoleproxy.ConsoleProxy");
Method methodSetup = consoleProxyClazz.getMethod("setEncryptorPassword", String.class);
methodSetup.invoke(null, encryptorPassword);
} catch (SecurityException e) {
diff --git a/agent/test/com/cloud/agent/AgentShellTest.java b/agent/test/com/cloud/agent/AgentShellTest.java
index 5baa7bf800e9..868293c8977b 100644
--- a/agent/test/com/cloud/agent/AgentShellTest.java
+++ b/agent/test/com/cloud/agent/AgentShellTest.java
@@ -16,6 +16,8 @@
// under the License.
package com.cloud.agent;
+import java.util.Arrays;
+import java.util.List;
import java.util.UUID;
import javax.naming.ConfigurationException;
@@ -23,6 +25,8 @@
import org.junit.Assert;
import org.junit.Test;
+import com.cloud.utils.StringUtils;
+
public class AgentShellTest {
@Test
public void parseCommand() throws ConfigurationException {
@@ -31,7 +35,7 @@ public void parseCommand() throws ConfigurationException {
shell.parseCommand(new String[] {"port=55555", "threads=4", "host=localhost", "pod=pod1", "guid=" + anyUuid, "zone=zone1"});
Assert.assertEquals(55555, shell.getPort());
Assert.assertEquals(4, shell.getWorkers());
- Assert.assertEquals("localhost", shell.getHost());
+ Assert.assertEquals("localhost", shell.getNextHost());
Assert.assertEquals(anyUuid.toString(), shell.getGuid());
Assert.assertEquals("pod1", shell.getPod());
Assert.assertEquals("zone1", shell.getZone());
@@ -44,4 +48,15 @@ public void loadProperties() throws ConfigurationException {
Assert.assertNotNull(shell.getProperties());
Assert.assertFalse(shell.getProperties().entrySet().isEmpty());
}
+
+ @Test
+ public void testGetHost() {
+ AgentShell shell = new AgentShell();
+ List hosts = Arrays.asList("10.1.1.1", "20.2.2.2", "30.3.3.3", "2001:db8::1");
+ shell.setHosts(StringUtils.listToCsvTags(hosts));
+ for (String host : hosts) {
+ Assert.assertEquals(host, shell.getNextHost());
+ }
+ Assert.assertEquals(shell.getNextHost(), hosts.get(0));
+ }
}
diff --git a/agent/test/com/cloud/agent/direct/download/DirectTemplateDownloaderImplTest.java b/agent/test/com/cloud/agent/direct/download/DirectTemplateDownloaderImplTest.java
new file mode 100644
index 000000000000..b244d02f4993
--- /dev/null
+++ b/agent/test/com/cloud/agent/direct/download/DirectTemplateDownloaderImplTest.java
@@ -0,0 +1,36 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package com.cloud.agent.direct.download;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DirectTemplateDownloaderImplTest {
+
+ private static final Long templateId = 202l;
+
+ @Test
+ public void testGetDirectDownloadTempPath() {
+ String path = DirectTemplateDownloaderImpl.getDirectDownloadTempPath(templateId);
+ Assert.assertEquals("template/2/202", path);
+ }
+}
diff --git a/api/pom.xml b/api/pom.xml
index d9be0a1877e5..b0a8c160f50c 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -23,7 +23,7 @@
org.apache.cloudstack
cloudstack
- 4.9.4.0-SNAPSHOT
+ 4.11.1.0-SNAPSHOT
@@ -51,6 +51,21 @@
cloud-framework-config
${project.version}
+
+ org.apache.cloudstack
+ cloud-framework-ca
+ ${project.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${cs.commons-lang3.version}
+
+
+ org.apache.cloudstack
+ cloud-framework-direct-download
+ ${project.version}
+
diff --git a/api/resources/META-INF/cloudstack/api-config/spring-api-config-context.xml b/api/resources/META-INF/cloudstack/api-config/spring-api-config-context.xml
index 2cd126630728..5ea32464ee9b 100644
--- a/api/resources/META-INF/cloudstack/api-config/spring-api-config-context.xml
+++ b/api/resources/META-INF/cloudstack/api-config/spring-api-config-context.xml
@@ -21,10 +21,10 @@
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+ http://www.springframework.org/schema/context/spring-context.xsd"
>
diff --git a/api/resources/META-INF/cloudstack/api-planner/spring-api-planner-context.xml b/api/resources/META-INF/cloudstack/api-planner/spring-api-planner-context.xml
index 2fd34a8ee0a5..8523daf1d216 100644
--- a/api/resources/META-INF/cloudstack/api-planner/spring-api-planner-context.xml
+++ b/api/resources/META-INF/cloudstack/api-planner/spring-api-planner-context.xml
@@ -21,10 +21,10 @@
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+ http://www.springframework.org/schema/context/spring-context.xsd"
>
diff --git a/core/src/com/cloud/agent/api/GetFileStatsCommand.java b/api/src/com/cloud/agent/api/BadCommand.java
similarity index 71%
rename from core/src/com/cloud/agent/api/GetFileStatsCommand.java
rename to api/src/com/cloud/agent/api/BadCommand.java
index b2da1c316475..55976f64185a 100644
--- a/core/src/com/cloud/agent/api/GetFileStatsCommand.java
+++ b/api/src/com/cloud/agent/api/BadCommand.java
@@ -1,4 +1,3 @@
-//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
@@ -15,30 +14,17 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
-//
-
package com.cloud.agent.api;
-import com.cloud.agent.api.LogLevel.Log4jLevel;
-import com.cloud.storage.Volume;
-
-@LogLevel(Log4jLevel.Trace)
-public class GetFileStatsCommand extends Command {
- protected GetFileStatsCommand() {
- }
-
- String paths;
-
- public GetFileStatsCommand(Volume volume) {
- paths = volume.getPath();
- }
-
- public String getPaths() {
- return paths;
- }
+public class BadCommand extends Command {
@Override
public boolean executeInSequence() {
+ // TODO Auto-generated method stub
return false;
}
+
+ public BadCommand(){
+ super();
+ }
}
diff --git a/api/src/com/cloud/agent/api/storage/OVFHelper.java b/api/src/com/cloud/agent/api/storage/OVFHelper.java
new file mode 100644
index 000000000000..85d4030b215b
--- /dev/null
+++ b/api/src/com/cloud/agent/api/storage/OVFHelper.java
@@ -0,0 +1,336 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.agent.api.storage;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import com.cloud.configuration.Resource.ResourceType;
+import com.cloud.exception.InternalErrorException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import com.cloud.agent.api.to.DatadiskTO;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class OVFHelper {
+ private static final Logger s_logger = Logger.getLogger(OVFHelper.class);
+
+ /**
+ * Get disk virtual size given its values on fields: 'ovf:capacity' and 'ovf:capacityAllocationUnits'
+ * @param capacity capacity
+ * @param allocationUnits capacity allocation units
+ * @return disk virtual size
+ */
+ public static Long getDiskVirtualSize(Long capacity, String allocationUnits, String ovfFilePath) throws InternalErrorException {
+ if ((capacity != 0) && (allocationUnits != null)) {
+ long units = 1;
+ if (allocationUnits.equalsIgnoreCase("KB") || allocationUnits.equalsIgnoreCase("KiloBytes") || allocationUnits.equalsIgnoreCase("byte * 2^10")) {
+ units = ResourceType.bytesToKiB;
+ } else if (allocationUnits.equalsIgnoreCase("MB") || allocationUnits.equalsIgnoreCase("MegaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^20")) {
+ units = ResourceType.bytesToMiB;
+ } else if (allocationUnits.equalsIgnoreCase("GB") || allocationUnits.equalsIgnoreCase("GigaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^30")) {
+ units = ResourceType.bytesToGiB;
+ }
+ return capacity * units;
+ } else {
+ throw new InternalErrorException("Failed to read capacity and capacityAllocationUnits from the OVF file: " + ovfFilePath);
+ }
+ }
+
+ public List getOVFVolumeInfo(final String ovfFilePath) {
+ if (StringUtils.isBlank(ovfFilePath)) {
+ return new ArrayList();
+ }
+ ArrayList vf = new ArrayList();
+ ArrayList vd = new ArrayList();
+
+ File ovfFile = new File(ovfFilePath);
+ try {
+ final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(ovfFilePath));
+ NodeList disks = doc.getElementsByTagName("Disk");
+ NodeList files = doc.getElementsByTagName("File");
+ NodeList items = doc.getElementsByTagName("Item");
+ boolean toggle = true;
+ for (int j = 0; j < files.getLength(); j++) {
+ Element file = (Element)files.item(j);
+ OVFFile of = new OVFFile();
+ of._href = file.getAttribute("ovf:href");
+ if (of._href.endsWith("vmdk") || of._href.endsWith("iso")) {
+ of._id = file.getAttribute("ovf:id");
+ String size = file.getAttribute("ovf:size");
+ if (StringUtils.isNotBlank(size)) {
+ of._size = Long.parseLong(size);
+ } else {
+ String dataDiskPath = ovfFile.getParent() + File.separator + of._href;
+ File this_file = new File(dataDiskPath);
+ of._size = this_file.length();
+ }
+ of.isIso = of._href.endsWith("iso");
+ if (toggle && !of.isIso) {
+ of._bootable = true;
+ toggle = !toggle;
+ }
+ vf.add(of);
+ }
+ }
+ for (int i = 0; i < disks.getLength(); i++) {
+ Element disk = (Element)disks.item(i);
+ OVFDisk od = new OVFDisk();
+ String virtualSize = disk.getAttribute("ovf:capacity");
+ od._capacity = NumberUtils.toLong(virtualSize, 0L);
+ String allocationUnits = disk.getAttribute("ovf:capacityAllocationUnits");
+ od._diskId = disk.getAttribute("ovf:diskId");
+ od._fileRef = disk.getAttribute("ovf:fileRef");
+ od._populatedSize = NumberUtils.toLong(disk.getAttribute("ovf:populatedSize"));
+
+ if ((od._capacity != 0) && (allocationUnits != null)) {
+
+ long units = 1;
+ if (allocationUnits.equalsIgnoreCase("KB") || allocationUnits.equalsIgnoreCase("KiloBytes") || allocationUnits.equalsIgnoreCase("byte * 2^10")) {
+ units = ResourceType.bytesToKiB;
+ } else if (allocationUnits.equalsIgnoreCase("MB") || allocationUnits.equalsIgnoreCase("MegaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^20")) {
+ units = ResourceType.bytesToMiB;
+ } else if (allocationUnits.equalsIgnoreCase("GB") || allocationUnits.equalsIgnoreCase("GigaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^30")) {
+ units = ResourceType.bytesToGiB;
+ }
+ od._capacity = od._capacity * units;
+ }
+ od._controller = getControllerType(items, od._diskId);
+ vd.add(od);
+ }
+
+ } catch (SAXException | IOException | ParserConfigurationException e) {
+ s_logger.error("Unexpected exception caught while parsing ovf file:" + ovfFilePath, e);
+ throw new CloudRuntimeException(e);
+ }
+
+ List disksTO = new ArrayList();
+ for (OVFFile of : vf) {
+ if (StringUtils.isBlank(of._id)){
+ s_logger.error("The ovf file info is incomplete file info");
+ throw new CloudRuntimeException("The ovf file info has incomplete file info");
+ }
+ OVFDisk cdisk = getDisk(of._id, vd);
+ if (cdisk == null && !of.isIso){
+ s_logger.error("The ovf file info has incomplete disk info");
+ throw new CloudRuntimeException("The ovf file info has incomplete disk info");
+ }
+ Long capacity = cdisk == null ? of._size : cdisk._capacity;
+ String controller = cdisk == null ? "" : cdisk._controller._name;
+ String controllerSubType = cdisk == null ? "" : cdisk._controller._subType;
+ String dataDiskPath = ovfFile.getParent() + File.separator + of._href;
+ File f = new File(dataDiskPath);
+ if (!f.exists() || f.isDirectory()) {
+ s_logger.error("One of the attached disk or iso does not exists " + dataDiskPath);
+ throw new CloudRuntimeException("One of the attached disk or iso as stated on OVF does not exists " + dataDiskPath);
+ }
+ disksTO.add(new DatadiskTO(dataDiskPath, capacity, of._size, of._id, of.isIso, of._bootable, controller, controllerSubType));
+ }
+ //check if first disk is an iso move it to the end
+ DatadiskTO fd = disksTO.get(0);
+ if (fd.isIso()) {
+ disksTO.remove(0);
+ disksTO.add(fd);
+ }
+ return disksTO;
+ }
+
+ private OVFDiskController getControllerType(final NodeList itemList, final String diskId) {
+ for (int k = 0; k < itemList.getLength(); k++) {
+ Element item = (Element)itemList.item(k);
+ NodeList cn = item.getChildNodes();
+ for (int l = 0; l < cn.getLength(); l++) {
+ if (cn.item(l) instanceof Element) {
+ Element el = (Element)cn.item(l);
+ if ("rasd:HostResource".equals(el.getNodeName())
+ && (el.getTextContent().contains("ovf:/file/" + diskId) || el.getTextContent().contains("ovf:/disk/" + diskId))) {
+ Element oe = getParentNode(itemList, item);
+ Element voe = oe;
+ while (oe != null) {
+ voe = oe;
+ oe = getParentNode(itemList, voe);
+ }
+ return getController(voe);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private Element getParentNode(final NodeList itemList, final Element childItem) {
+ NodeList cn = childItem.getChildNodes();
+ String parent_id = null;
+ for (int l = 0; l < cn.getLength(); l++) {
+ if (cn.item(l) instanceof Element) {
+ Element el = (Element)cn.item(l);
+ if ("rasd:Parent".equals(el.getNodeName())) {
+ parent_id = el.getTextContent();
+ }
+ }
+ }
+ if (parent_id != null) {
+ for (int k = 0; k < itemList.getLength(); k++) {
+ Element item = (Element)itemList.item(k);
+ NodeList child = item.getChildNodes();
+ for (int l = 0; l < child.getLength(); l++) {
+ if (child.item(l) instanceof Element) {
+ Element el = (Element)child.item(l);
+ if ("rasd:InstanceID".equals(el.getNodeName()) && el.getTextContent().trim().equals(parent_id)) {
+ return item;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private OVFDiskController getController(Element controllerItem) {
+ OVFDiskController dc = new OVFDiskController();
+ NodeList child = controllerItem.getChildNodes();
+ for (int l = 0; l < child.getLength(); l++) {
+ if (child.item(l) instanceof Element) {
+ Element el = (Element)child.item(l);
+ if ("rasd:ElementName".equals(el.getNodeName())) {
+ dc._name = el.getTextContent();
+ }
+ if ("rasd:ResourceSubType".equals(el.getNodeName())) {
+ dc._subType = el.getTextContent();
+ }
+ }
+ }
+ return dc;
+ }
+
+ public void rewriteOVFFile(final String origOvfFilePath, final String newOvfFilePath, final String diskName) {
+ try {
+ final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(origOvfFilePath));
+ NodeList disks = doc.getElementsByTagName("Disk");
+ NodeList files = doc.getElementsByTagName("File");
+ NodeList items = doc.getElementsByTagName("Item");
+ String keepfile = null;
+ List toremove = new ArrayList();
+ for (int j = 0; j < files.getLength(); j++) {
+ Element file = (Element)files.item(j);
+ String href = file.getAttribute("ovf:href");
+ if (diskName.equals(href)) {
+ keepfile = file.getAttribute("ovf:id");
+ } else {
+ toremove.add(file);
+ }
+ }
+ String keepdisk = null;
+ for (int i = 0; i < disks.getLength(); i++) {
+ Element disk = (Element)disks.item(i);
+ String fileRef = disk.getAttribute("ovf:fileRef");
+ if (keepfile == null) {
+ s_logger.info("FATAL: OVA format error");
+ } else if (keepfile.equals(fileRef)) {
+ keepdisk = disk.getAttribute("ovf:diskId");
+ } else {
+ toremove.add(disk);
+ }
+ }
+ for (int k = 0; k < items.getLength(); k++) {
+ Element item = (Element)items.item(k);
+ NodeList cn = item.getChildNodes();
+ for (int l = 0; l < cn.getLength(); l++) {
+ if (cn.item(l) instanceof Element) {
+ Element el = (Element)cn.item(l);
+ if ("rasd:HostResource".equals(el.getNodeName())
+ && !(el.getTextContent().contains("ovf:/file/" + keepdisk) || el.getTextContent().contains("ovf:/disk/" + keepdisk))) {
+ toremove.add(item);
+ break;
+ }
+ }
+ }
+ }
+
+ for (Element rme : toremove) {
+ if (rme.getParentNode() != null) {
+ rme.getParentNode().removeChild(rme);
+ }
+ }
+
+ final StringWriter writer = new StringWriter();
+ final StreamResult result = new StreamResult(writer);
+ final TransformerFactory tf = TransformerFactory.newInstance();
+ final Transformer transformer = tf.newTransformer();
+ final DOMSource domSource = new DOMSource(doc);
+ transformer.transform(domSource, result);
+ PrintWriter outfile = new PrintWriter(newOvfFilePath);
+ outfile.write(writer.toString());
+ outfile.close();
+ } catch (SAXException | IOException | ParserConfigurationException | TransformerException e) {
+ s_logger.info("Unexpected exception caught while removing network elements from OVF:" + e.getMessage(), e);
+ throw new CloudRuntimeException(e);
+ }
+ }
+
+ OVFDisk getDisk(String fileRef, List disks) {
+ for (OVFDisk disk : disks) {
+ if (disk._fileRef.equals(fileRef)) {
+ return disk;
+ }
+ }
+ return null;
+ }
+
+ class OVFFile {
+ //
+ public String _href;
+ public String _id;
+ public Long _size;
+ public boolean _bootable;
+ public boolean isIso;
+ }
+
+ class OVFDisk {
+ //
+ public Long _capacity;
+ public String _capacityUnit;
+ public String _diskId;
+ public String _fileRef;
+ public Long _populatedSize;
+ public OVFDiskController _controller;
+ }
+
+ class OVFDiskController {
+ public String _name;
+ public String _subType;
+ }
+}
diff --git a/api/src/com/cloud/agent/api/to/DatadiskTO.java b/api/src/com/cloud/agent/api/to/DatadiskTO.java
new file mode 100644
index 000000000000..1d3f91e25dbe
--- /dev/null
+++ b/api/src/com/cloud/agent/api/to/DatadiskTO.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.cloud.agent.api.to;
+
+public class DatadiskTO {
+ private String path;
+ private long virtualSize;
+ private long fileSize;
+ boolean bootable;
+ private String diskId;
+ private boolean isIso;
+ private String diskController;
+ private String diskControllerSubType;
+
+ public DatadiskTO() {
+ }
+
+ public DatadiskTO(String path, long virtualSize, long fileSize, boolean bootable) {
+ this.path = path;
+ this.virtualSize = virtualSize;
+ this.fileSize = fileSize;
+ this.bootable = bootable;
+ }
+
+ public DatadiskTO(String path, long virtualSize, long fileSize, String diskId, boolean isIso, boolean bootable, String controller, String controllerSubType) {
+ this.path = path;
+ this.virtualSize = virtualSize;
+ this.fileSize = fileSize;
+ this.bootable = bootable;
+ this.diskId = diskId;
+ this.isIso = isIso;
+ this.diskController = controller;
+ this.diskControllerSubType = controllerSubType;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public Long getVirtualSize() {
+ return virtualSize;
+ }
+
+ public void setVirtualSize(Long virtualSize) {
+ this.virtualSize = virtualSize;
+ }
+
+ public Long getFileSize() {
+ return fileSize;
+ }
+
+ public boolean isBootable() {
+ return bootable;
+ }
+
+ public String getDiskId() {
+ return diskId;
+ }
+
+ public void setDiskId(String diskId) {
+ this.diskId = diskId;
+ }
+
+ public boolean isIso() {
+ return isIso;
+ }
+
+ public void setIso(boolean isIso) {
+ this.isIso = isIso;
+ }
+
+ public String getDiskController() {
+ return diskController;
+ }
+
+ public void setDiskController(String diskController) {
+ this.diskController = diskController;
+ }
+
+ public String getDiskControllerSubType() {
+ return diskControllerSubType;
+ }
+
+ public void setDiskControllerSubType(String diskControllerSubType) {
+ this.diskControllerSubType = diskControllerSubType;
+ }
+
+}
\ No newline at end of file
diff --git a/api/src/com/cloud/agent/api/to/DiskTO.java b/api/src/com/cloud/agent/api/to/DiskTO.java
index f982844486a9..7b3d10bc4dbe 100644
--- a/api/src/com/cloud/agent/api/to/DiskTO.java
+++ b/api/src/com/cloud/agent/api/to/DiskTO.java
@@ -27,6 +27,7 @@ public class DiskTO {
public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";
public static final String CHAP_TARGET_USERNAME = "chapTargetUsername";
public static final String CHAP_TARGET_SECRET = "chapTargetSecret";
+ public static final String SCSI_NAA_DEVICE_ID = "scsiNaaDeviceId";
public static final String MANAGED = "managed";
public static final String IQN = "iqn";
public static final String STORAGE_HOST = "storageHost";
@@ -36,6 +37,9 @@ public class DiskTO {
public static final String PROTOCOL_TYPE = "protocoltype";
public static final String PATH = "path";
public static final String UUID = "uuid";
+ public static final String VMDK = "vmdk";
+ public static final String EXPAND_DATASTORE = "expandDatastore";
+ public static final String TEMPLATE_RESIGN = "templateResign";
private DataTO data;
private Long diskSeq;
diff --git a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java
index edfb0aa7c17d..25e7b5f60b3a 100644
--- a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java
+++ b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java
@@ -48,6 +48,7 @@ public class FirewallRuleTO implements InternalIdentity {
boolean revoked;
boolean alreadyAdded;
private List sourceCidrList;
+ private List destCidrList;
FirewallRule.Purpose purpose;
private Integer icmpType;
private Integer icmpCode;
@@ -170,6 +171,7 @@ public FirewallRuleTO(FirewallRule rule, String srcVlanTag, String srcIp, Firewa
rule.getSourceCidrList(),
rule.getIcmpType(),
rule.getIcmpCode());
+ this.destCidrList = rule.getDestinationCidrList();
this.trafficType = trafficType;
this.defaultEgressPolicy = defaultEgressPolicy;
}
@@ -257,6 +259,10 @@ public List getSourceCidrList() {
return sourceCidrList;
}
+ public List getDestCidrList(){
+ return destCidrList;
+ }
+
public boolean isAlreadyAdded() {
return alreadyAdded;
}
diff --git a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java
index 4d5a2c05db0c..3a3dfa475021 100644
--- a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java
+++ b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java
@@ -45,6 +45,10 @@ public class LoadBalancerTO {
boolean revoked;
boolean alreadyAdded;
boolean inline;
+ String srcIpVlan;
+ String srcIpGateway;
+ String srcIpNetmask;
+ Long networkId;
DestinationTO[] destinations;
private StickinessPolicyTO[] stickinessPolicies;
private HealthCheckPolicyTO[] healthCheckPolicies;
@@ -82,6 +86,15 @@ public LoadBalancerTO(String id, String srcIp, int srcPort, String protocol, Str
this(id, srcIp, srcPort, protocol, algorithm, revoked, alreadyAdded, inline, argDestinations, stickinessPolicies, null, null, null);
}
+ public LoadBalancerTO(String id, List destinations) {
+ this.uuid = id;
+ int i = 0;
+ this.destinations = new DestinationTO[destinations.size()];
+ for (DestinationTO destination : destinations) {
+ this.destinations[i++] = new DestinationTO(destination.getDestIp(), destination.getDestPort(), destination.getMonitorState());
+ }
+ }
+
public LoadBalancerTO(String id, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, boolean inline,
List argDestinations, List stickinessPolicies, List healthCheckPolicies, LbSslCert sslCert,
String lbProtocol) {
@@ -194,21 +207,53 @@ public LbSslCert getSslCert() {
return this.sslCert;
}
+ public String getSrcIpVlan() {
+ return srcIpVlan;
+ }
+
+ public void setSrcIpVlan(String srcIpVlan) {
+ this.srcIpVlan = srcIpVlan;
+ }
+
+ public Long getNetworkId() {
+ return networkId;
+ }
+
+ public void setNetworkId(long id) {
+ this.networkId = id;
+ }
+
+ public String getSrcIpGateway() {
+ return srcIpGateway;
+ }
+
+ public void setSrcIpGateway(String srcIpGateway) {
+ this.srcIpGateway = srcIpGateway;
+ }
+
+ public String getSrcIpNetmask() {
+ return srcIpNetmask;
+ }
+
+ public void setSrcIpNetmask(String srcIpNetmask) {
+ this.srcIpNetmask = srcIpNetmask;
+ }
+
public static class StickinessPolicyTO {
- private String _methodName;
- private List> _paramsList;
+ private String methodName;
+ private List> params;
public String getMethodName() {
- return _methodName;
+ return methodName;
}
public List> getParams() {
- return _paramsList;
+ return params;
}
public StickinessPolicyTO(String methodName, List> paramsList) {
- this._methodName = methodName;
- this._paramsList = paramsList;
+ this.methodName = methodName;
+ this.params = paramsList;
}
}
@@ -219,7 +264,7 @@ public static class HealthCheckPolicyTO {
private int healthcheckInterval;
private int healthcheckThresshold;
private int unhealthThresshold;
- private boolean revoke = false;
+ private boolean revoked = false;
public HealthCheckPolicyTO(String pingPath, String description, int responseTime, int healthcheckInterval, int healthcheckThresshold, int unhealthThresshold,
boolean revoke) {
@@ -230,7 +275,7 @@ public HealthCheckPolicyTO(String pingPath, String description, int responseTime
this.healthcheckInterval = healthcheckInterval;
this.healthcheckThresshold = healthcheckThresshold;
this.unhealthThresshold = unhealthThresshold;
- this.revoke = revoke;
+ this.revoked = revoke;
}
public HealthCheckPolicyTO() {
@@ -262,11 +307,11 @@ public int getUnhealthThresshold() {
}
public void setRevoke(boolean revoke) {
- this.revoke = revoke;
+ this.revoked = revoke;
}
public boolean isRevoked() {
- return revoke;
+ return revoked;
}
}
@@ -285,6 +330,12 @@ public DestinationTO(String destIp, int destPort, boolean revoked, boolean alrea
this.alreadyAdded = alreadyAdded;
}
+ public DestinationTO(String destIp, int destPort, String monitorState) {
+ this.destIp = destIp;
+ this.destPort = destPort;
+ this.monitorState = monitorState;
+ }
+
protected DestinationTO() {
}
diff --git a/api/src/com/cloud/agent/api/to/NetworkTO.java b/api/src/com/cloud/agent/api/to/NetworkTO.java
index be11deaa1ec8..9c888059d93c 100644
--- a/api/src/com/cloud/agent/api/to/NetworkTO.java
+++ b/api/src/com/cloud/agent/api/to/NetworkTO.java
@@ -38,6 +38,8 @@ public class NetworkTO {
protected URI isolationUri;
protected boolean isSecurityGroupEnabled;
protected String name;
+ protected String ip6address;
+ protected String ip6cidr;
public NetworkTO() {
}
@@ -62,6 +64,14 @@ public void setIp(String ip) {
this.ip = ip;
}
+ public void setIp6Address(String addr) {
+ this.ip6address = addr;
+ }
+
+ public void setIp6Cidr(String cidr) {
+ this.ip6cidr = cidr;
+ }
+
public void setNetmask(String netmask) {
this.netmask = netmask;
}
@@ -114,6 +124,7 @@ public NetworkTO(String ip, String netmask, String mac) {
* the full information about what is needed.
*
* @param ip
+ * @param ip6address
* @param vlan
* @param netmask
* @param mac
@@ -130,10 +141,30 @@ public NetworkTO(String ip, String netmask, String mac, String gateway, String d
this.dns2 = dns2;
}
+ public NetworkTO(String ip, String netmask, String mac, String gateway, String dns1, String dns2, String ip6address,
+ String ip6cidr) {
+ this.ip = ip;
+ this.netmask = netmask;
+ this.mac = mac;
+ this.gateway = gateway;
+ this.dns1 = dns1;
+ this.dns2 = dns2;
+ this.ip6address = ip6address;
+ this.ip6cidr = ip6cidr;
+ }
+
public String getIp() {
return ip;
}
+ public String getIp6Address() {
+ return ip6address;
+ }
+
+ public String getIp6Cidr() {
+ return ip6cidr;
+ }
+
public String getNetmask() {
return netmask;
}
diff --git a/api/src/com/cloud/agent/api/to/NicTO.java b/api/src/com/cloud/agent/api/to/NicTO.java
index bd681f282cd5..3863e1bafe72 100644
--- a/api/src/com/cloud/agent/api/to/NicTO.java
+++ b/api/src/com/cloud/agent/api/to/NicTO.java
@@ -16,7 +16,10 @@
// under the License.
package com.cloud.agent.api.to;
+import com.cloud.offering.NetworkOffering;
+
import java.util.List;
+import java.util.Map;
public class NicTO extends NetworkTO {
int deviceId;
@@ -26,6 +29,7 @@ public class NicTO extends NetworkTO {
boolean pxeDisable;
String nicUuid;
List nicSecIps;
+ Map details;
public NicTO() {
super();
@@ -97,4 +101,12 @@ public String getNetworkUuid() {
public void setNetworkUuid(String uuid) {
super.setUuid(uuid);
}
+
+ public Map getDetails() {
+ return details;
+ }
+
+ public void setDetails(final Map details) {
+ this.details = details;
+ }
}
diff --git a/api/src/com/cloud/agent/api/to/SwiftTO.java b/api/src/com/cloud/agent/api/to/SwiftTO.java
index c7a986603021..b89dfea40e0c 100644
--- a/api/src/com/cloud/agent/api/to/SwiftTO.java
+++ b/api/src/com/cloud/agent/api/to/SwiftTO.java
@@ -26,17 +26,19 @@ public class SwiftTO implements DataStoreTO, SwiftUtil.SwiftClientCfg {
String userName;
String key;
+ String storagePolicy;
private static final String pathSeparator = "/";
public SwiftTO() {
}
- public SwiftTO(Long id, String url, String account, String userName, String key) {
+ public SwiftTO(Long id, String url, String account, String userName, String key, String storagePolicy) {
this.id = id;
this.url = url;
this.account = account;
this.userName = userName;
this.key = key;
+ this.storagePolicy = storagePolicy;
}
public Long getId() {
@@ -63,6 +65,11 @@ public String getKey() {
return key;
}
+ @Override
+ public String getStoragePolicy() {
+ return this.storagePolicy;
+ }
+
@Override
public DataStoreRole getRole() {
return DataStoreRole.Image;
diff --git a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java
index c367ec9e07d8..84a6bf5fc16e 100644
--- a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java
+++ b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java
@@ -18,6 +18,7 @@
import java.util.List;
import java.util.Map;
+import java.util.HashMap;
import com.cloud.template.VirtualMachineTemplate.BootloaderType;
import com.cloud.vm.VirtualMachine;
@@ -69,6 +70,9 @@ public class VirtualMachineTO {
String configDriveIsoRootFolder = null;
String configDriveIsoFile = null;
+ Double cpuQuotaPercentage = null;
+
+ Map guestOsDetails = new HashMap();
public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader,
String os, boolean enableHA, boolean limitCpuUse, String vncPassword) {
@@ -331,4 +335,19 @@ public void setConfigDriveIsoFile(String configDriveIsoFile) {
this.configDriveIsoFile = configDriveIsoFile;
}
+ public Map getGuestOsDetails() {
+ return guestOsDetails;
+ }
+
+ public void setGuestOsDetails(Map guestOsDetails) {
+ this.guestOsDetails = guestOsDetails;
+ }
+
+ public Double getCpuQuotaPercentage() {
+ return cpuQuotaPercentage;
+ }
+
+ public void setCpuQuotaPercentage(Double cpuQuotaPercentage) {
+ this.cpuQuotaPercentage = cpuQuotaPercentage;
+ }
}
diff --git a/api/src/com/cloud/capacity/Capacity.java b/api/src/com/cloud/capacity/Capacity.java
index 2fbc1d6eef1d..ba04a82a5dea 100644
--- a/api/src/com/cloud/capacity/Capacity.java
+++ b/api/src/com/cloud/capacity/Capacity.java
@@ -32,6 +32,8 @@ public interface Capacity extends InternalIdentity, Identity {
public static final short CAPACITY_TYPE_LOCAL_STORAGE = 9;
public static final short CAPACITY_TYPE_GPU = 19;
+ public static final short CAPACITY_TYPE_CPU_CORE = 90;
+
public Long getHostOrPoolId();
public Long getDataCenterId();
@@ -49,4 +51,6 @@ public interface Capacity extends InternalIdentity, Identity {
public long getReservedCapacity();
public Float getUsedPercentage();
+
+ public Long getAllocatedCapacity();
}
diff --git a/api/src/com/cloud/configuration/ConfigurationService.java b/api/src/com/cloud/configuration/ConfigurationService.java
index b13122208ee9..5af44ed18f44 100644
--- a/api/src/com/cloud/configuration/ConfigurationService.java
+++ b/api/src/com/cloud/configuration/ConfigurationService.java
@@ -19,7 +19,9 @@
import java.util.List;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
+import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
+import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
@@ -160,6 +162,19 @@ public interface ConfigurationService {
*/
Pod createPod(long zoneId, String name, String startIp, String endIp, String gateway, String netmask, String allocationState);
+ /**
+ * Creates a mutual exclusive IP range in the pod with same gateway, netmask.
+ * @param cmd - The command specifying pod ID, start IP, end IP, gateway, netmask.
+ * @return The new range if successful, null otherwise.
+ */
+ Pod createPodIpRange(CreateManagementNetworkIpRangeCmd cmd);
+
+ /**
+ * Deletes a mutually exclusive IP range in the pod.
+ * @param cmd - The command specifying pod ID, start IP, end IP.
+ */
+ void deletePodIpRange(DeleteManagementNetworkIpRangeCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException;
+
/**
* Edits a pod in the database. Will not allow you to edit pods that are being used anywhere in the system.
*
diff --git a/api/src/com/cloud/configuration/Resource.java b/api/src/com/cloud/configuration/Resource.java
index 5550e29eca49..76f2930e6150 100644
--- a/api/src/com/cloud/configuration/Resource.java
+++ b/api/src/com/cloud/configuration/Resource.java
@@ -37,7 +37,9 @@ public enum ResourceType { // Primary and Secondary storage are allocated_storag
private String name;
private ResourceOwnerType[] supportedOwners;
private int ordinal;
- public static final long bytesToGiB = 1024 * 1024 * 1024;
+ public static final long bytesToKiB = 1024;
+ public static final long bytesToMiB = bytesToKiB * 1024;
+ public static final long bytesToGiB = bytesToMiB * 1024;
ResourceType(String name, int ordinal, ResourceOwnerType... supportedOwners) {
this.name = name;
@@ -71,6 +73,15 @@ public boolean supportsOwner(ResourceOwnerType ownerType) {
public int getOrdinal() {
return ordinal;
}
+
+ public static ResourceType fromOrdinal(int ordinal) {
+ for (ResourceType r : ResourceType.values()) {
+ if (r.ordinal == ordinal) {
+ return r;
+ }
+ }
+ return null;
+ }
}
public static class ResourceOwnerType {
diff --git a/api/src/com/cloud/dc/DataCenter.java b/api/src/com/cloud/dc/DataCenter.java
index 5b3d3c01f300..7d434c5f2315 100644
--- a/api/src/com/cloud/dc/DataCenter.java
+++ b/api/src/com/cloud/dc/DataCenter.java
@@ -18,15 +18,14 @@
import com.cloud.org.Grouping;
import org.apache.cloudstack.acl.InfrastructureEntity;
-import org.apache.cloudstack.api.Identity;
-import org.apache.cloudstack.api.InternalIdentity;
+import org.apache.cloudstack.kernel.Partition;
import java.util.Map;
/**
*
*/
-public interface DataCenter extends InfrastructureEntity, Grouping, Identity, InternalIdentity {
+public interface DataCenter extends InfrastructureEntity, Grouping, Partition {
public enum NetworkType {
Basic, Advanced,
diff --git a/api/src/com/cloud/dc/StorageNetworkIpRange.java b/api/src/com/cloud/dc/StorageNetworkIpRange.java
index 2b50ca1594e8..03d4f44de484 100644
--- a/api/src/com/cloud/dc/StorageNetworkIpRange.java
+++ b/api/src/com/cloud/dc/StorageNetworkIpRange.java
@@ -21,20 +21,19 @@
import org.apache.cloudstack.api.InternalIdentity;
public interface StorageNetworkIpRange extends InfrastructureEntity, InternalIdentity, Identity {
-
Integer getVlan();
- String getPodUuid();
+ String getGateway();
+
+ String getNetmask();
String getStartIp();
String getEndIp();
- String getNetworkUuid();
-
String getZoneUuid();
- String getNetmask();
+ String getPodUuid();
- String getGateway();
+ String getNetworkUuid();
}
diff --git a/api/src/com/cloud/deploy/DataCenterDeployment.java b/api/src/com/cloud/deploy/DataCenterDeployment.java
index f046b66ef068..76faf25f7260 100644
--- a/api/src/com/cloud/deploy/DataCenterDeployment.java
+++ b/api/src/com/cloud/deploy/DataCenterDeployment.java
@@ -19,6 +19,9 @@
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.vm.ReservationContext;
+import java.util.ArrayList;
+import java.util.List;
+
public class DataCenterDeployment implements DeploymentPlan {
long _dcId;
Long _podId;
@@ -29,6 +32,7 @@ public class DataCenterDeployment implements DeploymentPlan {
ExcludeList _avoids = null;
boolean _recreateDisks;
ReservationContext _context;
+ List preferredHostIds = new ArrayList<>();
public DataCenterDeployment(long dataCenterId) {
this(dataCenterId, null, null, null, null, null);
@@ -93,4 +97,14 @@ public ReservationContext getReservationContext() {
return _context;
}
+ @Override
+ public void setPreferredHosts(List hostIds) {
+ this.preferredHostIds = new ArrayList<>(hostIds);
+ }
+
+ @Override
+ public List getPreferredHosts() {
+ return this.preferredHostIds;
+ }
+
}
diff --git a/api/src/com/cloud/deploy/DeploymentClusterPlanner.java b/api/src/com/cloud/deploy/DeploymentClusterPlanner.java
index 6c09a6d51061..a668b79187dc 100644
--- a/api/src/com/cloud/deploy/DeploymentClusterPlanner.java
+++ b/api/src/com/cloud/deploy/DeploymentClusterPlanner.java
@@ -29,6 +29,7 @@ public interface DeploymentClusterPlanner extends DeploymentPlanner {
static final String ClusterCPUCapacityDisableThresholdCK = "cluster.cpu.allocated.capacity.disablethreshold";
static final String ClusterMemoryCapacityDisableThresholdCK = "cluster.memory.allocated.capacity.disablethreshold";
+ static final String ClusterThresholdEnabledCK = "cluster.threshold.enabled";
static final ConfigKey ClusterCPUCapacityDisableThreshold =
new ConfigKey(
@@ -46,6 +47,15 @@ public interface DeploymentClusterPlanner extends DeploymentPlanner {
"0.85",
"Percentage (as a value between 0 and 1) of memory utilization above which allocators will disable using the cluster for low memory available. Keep the corresponding notification threshold lower than this to be notified beforehand.",
true, ConfigKey.Scope.Cluster, null);
+ static final ConfigKey ClusterThresholdEnabled =
+ new ConfigKey(
+ "Advanced",
+ Boolean.class,
+ ClusterThresholdEnabledCK,
+ "true",
+ "Enable/Disable cluster thresholds. If disabled, an instance can start in a cluster even though the threshold may be crossed.",
+ false,
+ ConfigKey.Scope.Global);
/**
* This is called to determine list of possible clusters where a virtual
diff --git a/api/src/com/cloud/deploy/DeploymentPlan.java b/api/src/com/cloud/deploy/DeploymentPlan.java
index 456d5b85899d..b57fec0cf419 100644
--- a/api/src/com/cloud/deploy/DeploymentPlan.java
+++ b/api/src/com/cloud/deploy/DeploymentPlan.java
@@ -19,6 +19,8 @@
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.vm.ReservationContext;
+import java.util.List;
+
/**
*/
public interface DeploymentPlan {
@@ -65,4 +67,8 @@ public interface DeploymentPlan {
Long getPhysicalNetworkId();
ReservationContext getReservationContext();
+
+ void setPreferredHosts(List hostIds);
+
+ List getPreferredHosts();
}
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index 3cc4eac81f12..907b93eca103 100644
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -16,6 +16,9 @@
// under the License.
package com.cloud.event;
+import java.util.HashMap;
+import java.util.Map;
+
import com.cloud.dc.DataCenter;
import com.cloud.dc.Pod;
import com.cloud.dc.StorageNetworkIpRange;
@@ -54,10 +57,10 @@
import com.cloud.offering.ServiceOffering;
import com.cloud.projects.Project;
import com.cloud.server.ResourceTag;
-import com.cloud.storage.StoragePool;
import com.cloud.storage.GuestOS;
import com.cloud.storage.GuestOSHypervisor;
import com.cloud.storage.Snapshot;
+import com.cloud.storage.StoragePool;
import com.cloud.storage.Volume;
import com.cloud.storage.snapshot.SnapshotPolicy;
import com.cloud.template.VirtualMachineTemplate;
@@ -68,12 +71,11 @@
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RolePermission;
+import org.apache.cloudstack.annotation.Annotation;
import org.apache.cloudstack.config.Configuration;
+import org.apache.cloudstack.ha.HAConfig;
import org.apache.cloudstack.usage.Usage;
-import java.util.HashMap;
-import java.util.Map;
-
public class EventTypes {
//map of Event and corresponding entity for which Event is applicable
@@ -128,6 +130,7 @@ public class EventTypes {
public static final String EVENT_NETWORK_CREATE = "NETWORK.CREATE";
public static final String EVENT_NETWORK_DELETE = "NETWORK.DELETE";
public static final String EVENT_NETWORK_UPDATE = "NETWORK.UPDATE";
+ public static final String EVENT_NETWORK_MIGRATE = "NETWORK.MIGRATE";
public static final String EVENT_FIREWALL_OPEN = "FIREWALL.OPEN";
public static final String EVENT_FIREWALL_CLOSE = "FIREWALL.CLOSE";
public static final String EVENT_FIREWALL_UPDATE = "FIREWALL.UPDATE";
@@ -176,6 +179,11 @@ public class EventTypes {
public static final String EVENT_ROLE_PERMISSION_UPDATE = "ROLE.PERMISSION.UPDATE";
public static final String EVENT_ROLE_PERMISSION_DELETE = "ROLE.PERMISSION.DELETE";
+ // CA events
+ public static final String EVENT_CA_CERTIFICATE_ISSUE = "CA.CERTIFICATE.ISSUE";
+ public static final String EVENT_CA_CERTIFICATE_REVOKE = "CA.CERTIFICATE.REVOKE";
+ public static final String EVENT_CA_CERTIFICATE_PROVISION = "CA.CERTIFICATE.PROVISION";
+
// Account events
public static final String EVENT_ACCOUNT_ENABLE = "ACCOUNT.ENABLE";
public static final String EVENT_ACCOUNT_DISABLE = "ACCOUNT.DISABLE";
@@ -190,6 +198,7 @@ public class EventTypes {
public static final String EVENT_USER_CREATE = "USER.CREATE";
public static final String EVENT_USER_DELETE = "USER.DELETE";
public static final String EVENT_USER_DISABLE = "USER.DISABLE";
+ public static final String EVENT_USER_MOVE = "USER.MOVE";
public static final String EVENT_USER_UPDATE = "USER.UPDATE";
public static final String EVENT_USER_ENABLE = "USER.ENABLE";
public static final String EVENT_USER_LOCK = "USER.LOCK";
@@ -233,6 +242,8 @@ public class EventTypes {
// Snapshots
public static final String EVENT_SNAPSHOT_CREATE = "SNAPSHOT.CREATE";
+ public static final String EVENT_SNAPSHOT_ON_PRIMARY = "SNAPSHOT.ON_PRIMARY";
+ public static final String EVENT_SNAPSHOT_OFF_PRIMARY = "SNAPSHOT.OFF_PRIMARY";
public static final String EVENT_SNAPSHOT_DELETE = "SNAPSHOT.DELETE";
public static final String EVENT_SNAPSHOT_REVERT = "SNAPSHOT.REVERT";
public static final String EVENT_SNAPSHOT_POLICY_CREATE = "SNAPSHOTPOLICY.CREATE";
@@ -289,6 +300,9 @@ public class EventTypes {
public static final String EVENT_VLAN_IP_RANGE_DEDICATE = "VLAN.IP.RANGE.DEDICATE";
public static final String EVENT_VLAN_IP_RANGE_RELEASE = "VLAN.IP.RANGE.RELEASE";
+ public static final String EVENT_MANAGEMENT_IP_RANGE_CREATE = "MANAGEMENT.IP.RANGE.CREATE";
+ public static final String EVENT_MANAGEMENT_IP_RANGE_DELETE = "MANAGEMENT.IP.RANGE.DELETE";
+
public static final String EVENT_STORAGE_IP_RANGE_CREATE = "STORAGE.IP.RANGE.CREATE";
public static final String EVENT_STORAGE_IP_RANGE_DELETE = "STORAGE.IP.RANGE.DELETE";
public static final String EVENT_STORAGE_IP_RANGE_UPDATE = "STORAGE.IP.RANGE.UPDATE";
@@ -317,6 +331,12 @@ public class EventTypes {
public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD = "HOST.OOBM.CHANGEPASSWORD";
public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_POWERSTATE_TRANSITION = "HOST.OOBM.POWERSTATE.TRANSITION";
+ // HA
+ public static final String EVENT_HA_RESOURCE_ENABLE = "HA.RESOURCE.ENABLE";
+ public static final String EVENT_HA_RESOURCE_DISABLE = "HA.RESOURCE.DISABLE";
+ public static final String EVENT_HA_RESOURCE_CONFIGURE = "HA.RESOURCE.CONFIGURE";
+ public static final String EVENT_HA_STATE_TRANSITION = "HA.STATE.TRANSITION";
+
// Maintenance
public static final String EVENT_MAINTENANCE_CANCEL = "MAINT.CANCEL";
public static final String EVENT_MAINTENANCE_CANCEL_PRIMARY_STORAGE = "MAINT.CANCEL.PS";
@@ -391,6 +411,10 @@ public class EventTypes {
public static final String EVENT_EXTERNAL_LB_DEVICE_DELETE = "PHYSICAL.LOADBALANCER.DELETE";
public static final String EVENT_EXTERNAL_LB_DEVICE_CONFIGURE = "PHYSICAL.LOADBALANCER.CONFIGURE";
+ // external NCC device events
+ public static final String EVENT_EXTERNAL_NCC_DEVICE_ADD = "PHYSICAL.NCC.ADD";
+ public static final String EVENT_EXTERNAL_NCC_DEVICE_DELETE = "PHYSICAL.NCC.DELETE";
+
// external switch management device events (E.g.: Cisco Nexus 1000v Virtual Supervisor Module.
public static final String EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_ADD = "SWITCH.MGMT.ADD";
public static final String EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_DELETE = "SWITCH.MGMT.DELETE";
@@ -441,6 +465,8 @@ public class EventTypes {
// vm snapshot events
public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE";
public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE";
+ public static final String EVENT_VM_SNAPSHOT_ON_PRIMARY = "VMSNAPSHOT.ON_PRIMARY";
+ public static final String EVENT_VM_SNAPSHOT_OFF_PRIMARY = "VMSNAPSHOT.OFF_PRIMARY";
public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERTTO";
// external network device events
@@ -545,6 +571,19 @@ public class EventTypes {
//Usage related events
public static final String EVENT_USAGE_REMOVE_USAGE_RECORDS = "USAGE.REMOVE.USAGE.RECORDS";
+ // Netscaler Service Package events
+ public static final String EVENT_NETSCALER_SERVICEPACKAGE_ADD = "NETSCALER.SERVICEPACKAGE.ADD";
+ public static final String EVENT_NETSCALER_SERVICEPACKAGE_DELETE = "NETSCALER.SERVICEPACKAGE.DELETE";
+
+ public static final String EVENT_NETSCALER_VM_START = "NETSCALERVM.START";
+ public static final String EVENT_NETSCALER_VM_STOP = "NETSCALERVM.STOP";
+
+ public static final String EVENT_ANNOTATION_CREATE = "ANNOTATION.CREATE";
+ public static final String EVENT_ANNOTATION_REMOVE = "ANNOTATION.REMOVE";
+
+ public static final String EVENT_TEMPLATE_DIRECT_DOWNLOAD_FAILURE = "TEMPLATE.DIRECT.DOWNLOAD.FAILURE";
+ public static final String EVENT_ISO_DIRECT_DOWNLOAD_FAILURE = "ISO.DIRECT.DOWNLOAD.FAILURE";
+
static {
// TODO: need a way to force author adding event types to declare the entity details as well, with out braking
@@ -679,6 +718,8 @@ public class EventTypes {
// Snapshots
entityEventDetails.put(EVENT_SNAPSHOT_CREATE, Snapshot.class);
entityEventDetails.put(EVENT_SNAPSHOT_DELETE, Snapshot.class);
+ entityEventDetails.put(EVENT_SNAPSHOT_ON_PRIMARY, Snapshot.class);
+ entityEventDetails.put(EVENT_SNAPSHOT_OFF_PRIMARY, Snapshot.class);
entityEventDetails.put(EVENT_SNAPSHOT_POLICY_CREATE, SnapshotPolicy.class);
entityEventDetails.put(EVENT_SNAPSHOT_POLICY_UPDATE, SnapshotPolicy.class);
entityEventDetails.put(EVENT_SNAPSHOT_POLICY_DELETE, SnapshotPolicy.class);
@@ -733,6 +774,9 @@ public class EventTypes {
entityEventDetails.put(EVENT_VLAN_IP_RANGE_DEDICATE, Vlan.class);
entityEventDetails.put(EVENT_VLAN_IP_RANGE_RELEASE, Vlan.class);
+ entityEventDetails.put(EVENT_MANAGEMENT_IP_RANGE_CREATE, Pod.class);
+ entityEventDetails.put(EVENT_MANAGEMENT_IP_RANGE_DELETE, Pod.class);
+
entityEventDetails.put(EVENT_STORAGE_IP_RANGE_CREATE, StorageNetworkIpRange.class);
entityEventDetails.put(EVENT_STORAGE_IP_RANGE_DELETE, StorageNetworkIpRange.class);
entityEventDetails.put(EVENT_STORAGE_IP_RANGE_UPDATE, StorageNetworkIpRange.class);
@@ -761,6 +805,12 @@ public class EventTypes {
entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD, Host.class);
entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_POWERSTATE_TRANSITION, Host.class);
+ // HA
+ entityEventDetails.put(EVENT_HA_RESOURCE_ENABLE, HAConfig.class);
+ entityEventDetails.put(EVENT_HA_RESOURCE_DISABLE, HAConfig.class);
+ entityEventDetails.put(EVENT_HA_RESOURCE_CONFIGURE, HAConfig.class);
+ entityEventDetails.put(EVENT_HA_STATE_TRANSITION, HAConfig.class);
+
// Maintenance
entityEventDetails.put(EVENT_MAINTENANCE_CANCEL, Host.class);
entityEventDetails.put(EVENT_MAINTENANCE_CANCEL_PRIMARY_STORAGE, Host.class);
@@ -918,6 +968,15 @@ public class EventTypes {
//Usage
entityEventDetails.put(EVENT_USAGE_REMOVE_USAGE_RECORDS, Usage.class);
+ // Netscaler Service Packages
+ entityEventDetails.put(EVENT_NETSCALER_SERVICEPACKAGE_ADD, "NETSCALER.SERVICEPACKAGE.CREATE");
+ entityEventDetails.put(EVENT_NETSCALER_SERVICEPACKAGE_DELETE, "NETSCALER.SERVICEPACKAGE.DELETE");
+
+ entityEventDetails.put(EVENT_ANNOTATION_CREATE, Annotation.class);
+ entityEventDetails.put(EVENT_ANNOTATION_REMOVE, Annotation.class);
+
+ entityEventDetails.put(EVENT_TEMPLATE_DIRECT_DOWNLOAD_FAILURE, VirtualMachineTemplate.class);
+ entityEventDetails.put(EVENT_ISO_DIRECT_DOWNLOAD_FAILURE, "Iso");
}
public static String getEntityForEvent(String eventName) {
diff --git a/api/src/com/cloud/exception/UnavailableCommandException.java b/api/src/com/cloud/exception/UnavailableCommandException.java
new file mode 100644
index 000000000000..d5b7faa8f369
--- /dev/null
+++ b/api/src/com/cloud/exception/UnavailableCommandException.java
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.exception;
+
+import com.cloud.utils.SerialVersionUID;
+
+public class UnavailableCommandException extends PermissionDeniedException {
+
+ private static final long serialVersionUID = SerialVersionUID.UnavailableCommandException;
+
+ protected UnavailableCommandException() {
+ super();
+ }
+
+ public UnavailableCommandException(String msg) {
+ super(msg);
+ }
+
+ public UnavailableCommandException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java
index 689ed12b64e3..1ecd48d74ce9 100644
--- a/api/src/com/cloud/host/Host.java
+++ b/api/src/com/cloud/host/Host.java
@@ -16,22 +16,22 @@
// under the License.
package com.cloud.host;
-import java.util.Date;
-
-import org.apache.cloudstack.api.Identity;
-import org.apache.cloudstack.api.InternalIdentity;
-
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.resource.ResourceState;
import com.cloud.utils.fsm.StateObject;
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.ha.HAResource;
+import org.apache.cloudstack.kernel.Partition;
+
+import java.util.Date;
/**
* Host represents one particular host server.
*/
-public interface Host extends StateObject, Identity, InternalIdentity {
+public interface Host extends StateObject, Identity, Partition, HAResource {
public enum Type {
Storage(false), Routing(false), SecondaryStorage(false), SecondaryStorageCmdExecutor(false), ConsoleProxy(true), ExternalFirewall(false), ExternalLoadBalancer(
- false), ExternalVirtualSwitchSupervisor(false), PxeServer(false), BaremetalPxe(false), BaremetalDhcp(false), TrafficMonitor(false),
+ false), ExternalVirtualSwitchSupervisor(false), PxeServer(false), BaremetalPxe(false), BaremetalDhcp(false), TrafficMonitor(false), NetScalerControlCenter(false),
ExternalDhcp(false), SecondaryStorageVM(true), LocalSecondaryStorage(false), L2Networking(false);
boolean _virtual;
@@ -202,5 +202,7 @@ public static String[] toStrings(Host.Type... types) {
boolean isInMaintenanceStates();
+ boolean isDisabled();
+
ResourceState getResourceState();
}
diff --git a/api/src/com/cloud/host/Status.java b/api/src/com/cloud/host/Status.java
index 73e6cc9185a9..e381115db416 100644
--- a/api/src/com/cloud/host/Status.java
+++ b/api/src/com/cloud/host/Status.java
@@ -150,12 +150,14 @@ public static String[] toStrings(Status... states) {
s_fsm.addTransition(Status.Down, Event.ManagementServerDown, Status.Down);
s_fsm.addTransition(Status.Down, Event.AgentDisconnected, Status.Down);
s_fsm.addTransition(Status.Down, Event.PingTimeout, Status.Down);
+ s_fsm.addTransition(Status.Down, Event.HostDown, Status.Down);
s_fsm.addTransition(Status.Alert, Event.AgentConnected, Status.Connecting);
s_fsm.addTransition(Status.Alert, Event.Ping, Status.Up);
s_fsm.addTransition(Status.Alert, Event.Remove, Status.Removed);
s_fsm.addTransition(Status.Alert, Event.ManagementServerDown, Status.Alert);
s_fsm.addTransition(Status.Alert, Event.AgentDisconnected, Status.Alert);
s_fsm.addTransition(Status.Alert, Event.ShutdownRequested, Status.Disconnected);
+ s_fsm.addTransition(Status.Alert, Event.HostDown, Status.Down);
s_fsm.addTransition(Status.Rebalancing, Event.RebalanceFailed, Status.Disconnected);
s_fsm.addTransition(Status.Rebalancing, Event.RebalanceCompleted, Status.Connecting);
s_fsm.addTransition(Status.Rebalancing, Event.ManagementServerDown, Status.Disconnected);
diff --git a/api/src/com/cloud/hypervisor/HypervisorGuru.java b/api/src/com/cloud/hypervisor/HypervisorGuru.java
index 6a09dd257afc..45e19ee2674b 100644
--- a/api/src/com/cloud/hypervisor/HypervisorGuru.java
+++ b/api/src/com/cloud/hypervisor/HypervisorGuru.java
@@ -33,7 +33,7 @@
public interface HypervisorGuru extends Adapter {
static final ConfigKey VmwareFullClone = new ConfigKey("Advanced", Boolean.class, "vmware.create.full.clone", "true",
- "If set to true, creates guest VMs as full clones on ESX", false);
+ "If set to true, creates guest VMs as full clones on ESX", false);
HypervisorType getHypervisorType();
/**
@@ -45,7 +45,7 @@ public interface HypervisorGuru extends Adapter {
VirtualMachineTO implement(VirtualMachineProfile vm);
/**
- * Give hypervisor guru opportunity to decide if certain command needs to be delegated to other host, mainly to secondary storage VM host
+ * Gives hypervisor guru opportunity to decide if certain commands need to be delegated to another host, for instance, we may have the opportunity to change from a system VM (is considered a host) to a real host to execute commands.
*
* @param hostId original hypervisor host
* @param cmd command that is going to be sent, hypervisor guru usually needs to register various context objects into the command object
diff --git a/api/src/com/cloud/network/IpAddress.java b/api/src/com/cloud/network/IpAddress.java
index 2061771ed37e..2447809d66f5 100644
--- a/api/src/com/cloud/network/IpAddress.java
+++ b/api/src/com/cloud/network/IpAddress.java
@@ -92,4 +92,8 @@ enum Purpose {
public Date getCreated();
+ State getRuleState();
+
+ void setRuleState(State ruleState);
+
}
diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java
index 7cc5441603ae..75196a469d3e 100644
--- a/api/src/com/cloud/network/Network.java
+++ b/api/src/com/cloud/network/Network.java
@@ -38,14 +38,16 @@
public interface Network extends ControlledEntity, StateObject, InternalIdentity, Identity, Serializable, Displayable {
public enum GuestType {
- Shared, Isolated
+ Shared, Isolated, L2
}
+ public String updatingInSequence ="updatingInSequence";
+
public static class Service {
private static List supportedServices = new ArrayList();
public static final Service Vpn = new Service("Vpn", Capability.SupportedVpnProtocols, Capability.VpnTypes);
- public static final Service Dhcp = new Service("Dhcp");
+ public static final Service Dhcp = new Service("Dhcp", Capability.ExtraDhcpOptions);
public static final Service Dns = new Service("Dns", Capability.AllowDnsSuffixModification);
public static final Service Gateway = new Service("Gateway");
public static final Service Firewall = new Service("Firewall", Capability.SupportedProtocols, Capability.MultipleIps, Capability.TrafficStatistics,
@@ -58,7 +60,8 @@ public static class Service {
public static final Service PortForwarding = new Service("PortForwarding");
public static final Service SecurityGroup = new Service("SecurityGroup");
public static final Service NetworkACL = new Service("NetworkACL", Capability.SupportedProtocols);
- public static final Service Connectivity = new Service("Connectivity", Capability.DistributedRouter, Capability.RegionLevelVpc, Capability.StretchedL2Subnet);
+ public static final Service Connectivity = new Service("Connectivity", Capability.DistributedRouter, Capability.RegionLevelVpc, Capability.StretchedL2Subnet,
+ Capability.NoVlan, Capability.PublicAccess);
private final String name;
private final Capability[] caps;
@@ -139,6 +142,8 @@ public static class Provider {
public static final Provider GloboDns = new Provider("GloboDns", true);
// add Big Switch Bcf Provider
public static final Provider BigSwitchBcf = new Provider("BigSwitchBcf", false);
+ //Add ConfigDrive provider
+ public static final Provider ConfigDrive = new Provider("ConfigDrive", false);
private final String name;
private final boolean isExternal;
@@ -213,6 +218,9 @@ public static class Capability {
public static final Capability DistributedRouter = new Capability("DistributedRouter");
public static final Capability StretchedL2Subnet = new Capability("StretchedL2Subnet");
public static final Capability RegionLevelVpc = new Capability("RegionLevelVpc");
+ public static final Capability NoVlan = new Capability("NoVlan");
+ public static final Capability PublicAccess = new Capability("PublicAccess");
+ public static final Capability ExtraDhcpOptions = new Capability("ExtraDhcpOptions");
private final String name;
@@ -272,12 +280,26 @@ private State(String description) {
public class IpAddresses {
private String ip4Address;
private String ip6Address;
+ private String macAddress;
+
+ public String getMacAddress() {
+ return macAddress;
+ }
+
+ public void setMacAddress(String macAddress) {
+ this.macAddress = macAddress;
+ }
public IpAddresses(String ip4Address, String ip6Address) {
setIp4Address(ip4Address);
setIp6Address(ip6Address);
}
+ public IpAddresses(String ipAddress, String ip6Address, String macAddress) {
+ this(ipAddress, ip6Address);
+ setMacAddress(macAddress);
+ }
+
public String getIp4Address() {
return ip4Address;
}
@@ -329,6 +351,8 @@ public void setIp6Address(String ip6Address) {
boolean isRedundant();
+ boolean isRollingRestart();
+
long getRelated();
URI getBroadcastUri();
@@ -370,4 +394,6 @@ public void setIp6Address(String ip6Address) {
void setNetworkACLId(Long networkACLId);
boolean isStrechedL2Network();
+
+ String getExternalId();
}
diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java
index 780f97d22f4e..a5bf5e446105 100644
--- a/api/src/com/cloud/network/NetworkModel.java
+++ b/api/src/com/cloud/network/NetworkModel.java
@@ -17,6 +17,8 @@
package com.cloud.network;
+import com.google.common.collect.ImmutableMap;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -27,6 +29,7 @@
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.Network.Capability;
+import com.cloud.network.Network.IpAddresses;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.Networks.TrafficType;
@@ -38,6 +41,7 @@
import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile;
import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.framework.config.ConfigKey;
/**
* The NetworkModel presents a read-only view into the Network data such as L2 networks,
@@ -46,6 +50,34 @@
* participants in the orchestration can use this interface to query the data.
*/
public interface NetworkModel {
+ String METATDATA_DIR = "metadata";
+ String USERDATA_DIR = "userdata";
+ String USERDATA_FILE = "user_data";
+ String PASSWORD_DIR = "password";
+ String PASSWORD_FILE = "vm_password";
+ String PASSWORD_CHECKSUM_FILE = "vm-password-md5checksum";
+ String SERVICE_OFFERING_FILE = "service-offering";
+ String AVAILABILITY_ZONE_FILE = "availability-zone";
+ String LOCAL_HOSTNAME_FILE = "local-hostname";
+ String LOCAL_IPV4_FILE = "local-ipv4";
+ String PUBLIC_HOSTNAME_FILE = "public-hostname";
+ String PUBLIC_IPV4_FILE = "public-ipv4";
+ String INSTANCE_ID_FILE = "instance-id";
+ String VM_ID_FILE = "vm-id";
+ String PUBLIC_KEYS_FILE = "public-keys";
+ String CLOUD_IDENTIFIER_FILE = "cloud-identifier";
+ int CONFIGDATA_DIR = 0;
+ int CONFIGDATA_FILE = 1;
+ int CONFIGDATA_CONTENT = 2;
+ ImmutableMap openStackFileMapping = ImmutableMap.of(
+ AVAILABILITY_ZONE_FILE, "availability_zone",
+ LOCAL_HOSTNAME_FILE, "hostname",
+ VM_ID_FILE, "uuid",
+ PUBLIC_HOSTNAME_FILE, "name"
+ );
+
+ static final ConfigKey MACIdentifier = new ConfigKey("Advanced",Integer.class, "mac.identifier", "0",
+ "This value will be used while generating the mac addresses for isolated and shared networks. The hexadecimal equivalent value will be present at the 2nd octet of the mac address. Default value is null which means this feature is disabled.Its scope is global.", true, ConfigKey.Scope.Global);
/**
* Lists IP addresses that belong to VirtualNetwork VLANs
@@ -154,6 +186,8 @@ public interface NetworkModel {
boolean checkIpForService(IpAddress ip, Service service, Long networkId);
+ boolean providerSupportsCapability(Set providers, Service service, Capability cap);
+
void checkCapabilityForProvider(Set providers, Service service, Capability cap, String capValue);
Provider getDefaultUniqueProviderForService(String serviceName);
@@ -254,7 +288,7 @@ public interface NetworkModel {
void checkIp6Parameters(String startIPv6, String endIPv6, String ip6Gateway, String ip6Cidr) throws InvalidParameterValueException;
- void checkRequestedIpAddresses(long networkId, String ip4, String ip6) throws InvalidParameterValueException;
+ void checkRequestedIpAddresses(long networkId, IpAddresses ips) throws InvalidParameterValueException;
String getStartIpv6Address(long id);
@@ -278,7 +312,9 @@ public interface NetworkModel {
boolean getNetworkEgressDefaultPolicy(Long networkId);
- List generateVmData(String userData, String serviceOffering, String zoneName,
- String vmName, long vmId, String publicKey, String password, Boolean isWindows);
+ List generateVmData(String userData, String serviceOffering, long datacenterId,
+ String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows);
+
+ String getValidNetworkCidr(Network guestNetwork);
}
diff --git a/api/src/com/cloud/network/NetworkProfile.java b/api/src/com/cloud/network/NetworkProfile.java
index ab033edaa534..d8733ca6c501 100644
--- a/api/src/com/cloud/network/NetworkProfile.java
+++ b/api/src/com/cloud/network/NetworkProfile.java
@@ -57,6 +57,7 @@ public class NetworkProfile implements Network {
private Long networkAclId;
private final String guruName;
private boolean strechedL2Subnet;
+ private String externalId;
public NetworkProfile(Network network) {
id = network.getId();
@@ -91,6 +92,7 @@ public NetworkProfile(Network network) {
guruName = network.getGuruName();
strechedL2Subnet = network.isStrechedL2Network();
isRedundant = network.isRedundant();
+ externalId = network.getExternalId();
}
public String getDns1() {
@@ -153,6 +155,11 @@ public boolean isRedundant() {
return this.isRedundant;
}
+ @Override
+ public boolean isRollingRestart() {
+ return false;
+ }
+
@Override
public String getName() {
return name;
@@ -300,4 +307,9 @@ public boolean isStrechedL2Network() {
return false;
}
+ @Override
+ public String getExternalId() {
+ return externalId;
+ }
+
}
diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java
index c1b68eb3a463..d76d65972026 100644
--- a/api/src/com/cloud/network/NetworkService.java
+++ b/api/src/com/cloud/network/NetworkService.java
@@ -19,6 +19,7 @@
import java.util.List;
import java.util.Map;
+import org.apache.cloudstack.api.command.admin.address.ReleasePodIpCmdByAdmin;
import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd;
import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd;
import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd;
@@ -26,6 +27,7 @@
import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
+import org.apache.cloudstack.api.response.AcquirePodIpCmdResponse;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException;
@@ -34,10 +36,12 @@
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network.Service;
import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.vpc.Vpc;
import com.cloud.offering.NetworkOffering;
import com.cloud.user.Account;
import com.cloud.user.User;
import com.cloud.utils.Pair;
+import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.Nic;
import com.cloud.vm.NicSecondaryIp;
@@ -66,7 +70,7 @@ IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long ne
boolean deleteNetwork(long networkId, boolean forced);
- boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
+ boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup, boolean makeRedundant) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
int getActiveNicsInNetwork(long networkId);
@@ -77,7 +81,25 @@ IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long ne
IpAddress getIp(long id);
Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, String domainSuffix, Long networkOfferingId,
- Boolean changeCidr, String guestVmCidr, Boolean displayNetwork, String newUUID);
+ Boolean changeCidr, String guestVmCidr, Boolean displayNetwork, String newUUID, boolean updateInSequence, boolean forced);
+
+ /**
+ * Migrate a network from one physical network to another physical network
+ * @param networkId of the network that needs to be migrated
+ * @param networkOfferingId new network offering id for the network
+ * @param resume if previous migration failed try to resume of just fail directly because anomaly is detected
+ * @return the migrated network
+ */
+ Network migrateGuestNetwork(long networkId, long networkOfferingId, Account callerAccount, User callerUser, boolean resume);
+
+ /**
+ * Migrate a vpc from on physical network to another physical network
+ * @param vpcId the id of the vpc that needs to be migrated
+ * @param vpcNetworkofferingId the new vpc offering id
+ * @param resume if previous migration failed try to resume of just fail directly because anomaly is detected
+ * @return the migrated vpc
+ */
+ Vpc migrateVpcNetwork(long vpcId, long vpcNetworkofferingId, Map networkToOffering, Account account, User callerUser, boolean resume);
PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String networkSpeed, List isolationMethods, String broadcastDomainRange, Long domainId,
List tags, String name);
@@ -180,4 +202,10 @@ Network createPrivateNetwork(String networkName, String displayText, long physic
IpAddress updateIP(Long id, String customId, Boolean displayIp);
boolean configureNicSecondaryIp(NicSecondaryIp secIp, boolean isZoneSgEnabled);
+
+ List extends NicSecondaryIp> listVmNicSecondaryIps(ListNicsCmd listNicsCmd);
+
+ AcquirePodIpCmdResponse allocatePodIp(Account account, String zoneId, String podId) throws ResourceAllocationException, ConcurrentOperationException;
+
+ boolean releasePodIp(ReleasePodIpCmdByAdmin ip) throws CloudRuntimeException;
}
diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java
index f027cf9fe995..06f4236eb7ae 100644
--- a/api/src/com/cloud/network/Networks.java
+++ b/api/src/com/cloud/network/Networks.java
@@ -75,6 +75,10 @@ public URI toUri(T value) {
throw new CloudRuntimeException("Unable to convert to broadcast URI: " + value);
}
}
+ @Override
+ public String getValueFrom(URI uri) {
+ return uri.getAuthority();
+ }
},
Vswitch("vs", String.class), LinkLocal(null, null), Vnet("vnet", Long.class), Storage("storage", Integer.class), Lswitch("lswitch", String.class) {
@Override
@@ -242,6 +246,7 @@ public static String getValue(String uriString) throws URISyntaxException {
* encode a string into a BroadcastUri
* @param candidate the input string
* @return an URI containing an appropriate (possibly given) scheme and the value
+ *
*/
public static URI fromString(String candidate) {
try {
diff --git a/api/src/com/cloud/network/PhysicalNetwork.java b/api/src/com/cloud/network/PhysicalNetwork.java
index bdf098f3abba..48e416c4b460 100644
--- a/api/src/com/cloud/network/PhysicalNetwork.java
+++ b/api/src/com/cloud/network/PhysicalNetwork.java
@@ -16,12 +16,16 @@
// under the License.
package com.cloud.network;
-import java.util.List;
-
+import com.cloud.exception.CloudException;
+import com.cloud.utils.Pair;
+import com.cloud.utils.StringUtils;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
-import com.cloud.utils.Pair;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
/**
*
@@ -32,8 +36,101 @@ public enum State {
Disabled, Enabled;
}
- public enum IsolationMethod {
- VLAN, L3, GRE, STT, BCF_SEGMENT, MIDO, SSP, VXLAN, ODL, L3VPN, VSP, VCS;
+ public class IsolationMethod {
+ protected static final String UNKNOWN_PROVIDER = "Unknown";
+ static Set registeredIsolationMethods = new HashSet<>();
+
+ String methodPrefix;
+ String provider;
+
+ public IsolationMethod(String prfx) {
+ this(prfx, UNKNOWN_PROVIDER);
+ }
+
+ public IsolationMethod(String prfx, String prvdr) {
+ methodPrefix = prfx;
+ provider = StringUtils.isNotBlank(prvdr)? prvdr : UNKNOWN_PROVIDER;
+ registeredIsolationMethods.add(this);
+ }
+
+ /**
+ * gets a IsolationMethod object that defines this prefix and if any it returns the first one found that has a known provider. If none has a known provider
+ * it will return the one with the unknown provider. if none is found it return null.
+ *
+ * @param prfx
+ * @return
+ */
+ public static IsolationMethod getIsolationMethod(String prfx) throws IsolationMethodNotRegistered {
+ IsolationMethod rc = null;
+ for (IsolationMethod method: registeredIsolationMethods) {
+ if (method.methodPrefix.equals(prfx)) {
+ rc = method;
+ if(! rc.getProvider().equals(UNKNOWN_PROVIDER)) {
+ break;
+ }
+ }
+ }
+ if (rc == null) {
+ throw new IsolationMethodNotRegistered("No registration of prefix '" + prfx + "' found.");
+ }
+ return rc;
+ }
+
+ public static IsolationMethod getIsolationMethod(String prfx, String provider) throws IsolationMethodNotRegistered {
+ for (IsolationMethod method: registeredIsolationMethods) {
+ if (method.methodPrefix.equals(prfx) && method.provider.equals(provider)) {
+ return method;
+ }
+ }
+ throw new IsolationMethodNotRegistered("No registration of prefix '" + prfx + "' for provider '" + provider + "' found.");
+ }
+
+ static class IsolationMethodNotRegistered extends CloudException {
+ IsolationMethodNotRegistered (String message) {
+ super(message);
+ }
+ }
+
+ public String getMethodPrefix() {
+ return methodPrefix;
+ }
+
+ public String getProvider() {
+ return provider;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ IsolationMethod that = (IsolationMethod)o;
+ return Objects.equals(methodPrefix, that.methodPrefix) && Objects.equals(provider, that.provider);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(methodPrefix, provider);
+ }
+
+ @Override
+ public String toString() {
+ return methodPrefix;
+ }
+
+ public static boolean remove(String prfx, String prvdr) {
+ prvdr = StringUtils.isNotBlank(prvdr)? prvdr : UNKNOWN_PROVIDER;
+
+ try {
+ return remove(getIsolationMethod(prfx, prvdr));
+ } catch (IsolationMethodNotRegistered isolationMethodNotRegistered) {
+ return false;
+ }
+ }
+ public static boolean remove(IsolationMethod method) {
+ return registeredIsolationMethods.remove(method);
+ }
}
public enum BroadcastDomainRange {
diff --git a/api/src/com/cloud/network/VirtualRouterProvider.java b/api/src/com/cloud/network/VirtualRouterProvider.java
index 8e2fa70d8910..aca526b1832b 100644
--- a/api/src/com/cloud/network/VirtualRouterProvider.java
+++ b/api/src/com/cloud/network/VirtualRouterProvider.java
@@ -21,7 +21,7 @@
public interface VirtualRouterProvider extends InternalIdentity, Identity {
public enum Type {
- VirtualRouter, ElasticLoadBalancerVm, VPCVirtualRouter, InternalLbVm
+ VirtualRouter, ElasticLoadBalancerVm, VPCVirtualRouter, InternalLbVm, NetScalerVm
}
public Type getType();
diff --git a/api/src/com/cloud/network/element/DhcpServiceProvider.java b/api/src/com/cloud/network/element/DhcpServiceProvider.java
index 2bd6ebcba35a..12830f8cec0f 100644
--- a/api/src/com/cloud/network/element/DhcpServiceProvider.java
+++ b/api/src/com/cloud/network/element/DhcpServiceProvider.java
@@ -16,6 +16,8 @@
// under the License.
package com.cloud.network.element;
+import java.util.Map;
+
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
@@ -33,4 +35,6 @@ boolean configDhcpSupportForSubnet(Network network, NicProfile nic, VirtualMachi
throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException;
boolean removeDhcpSupportForSubnet(Network network) throws ResourceUnavailableException;
+
+ boolean setExtraDhcpOptions(Network network, long nicId, Map dhcpOptions);
}
diff --git a/api/src/com/cloud/network/element/DnsServiceProvider.java b/api/src/com/cloud/network/element/DnsServiceProvider.java
new file mode 100644
index 000000000000..7abce537221c
--- /dev/null
+++ b/api/src/com/cloud/network/element/DnsServiceProvider.java
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network.element;
+
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.VirtualMachineProfile;
+
+public interface DnsServiceProvider extends NetworkElement {
+ boolean addDnsEntry(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context)
+ throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException;
+
+ boolean configDnsSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context)
+ throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException;
+
+ boolean removeDnsSupportForSubnet(Network network) throws ResourceUnavailableException;
+}
diff --git a/api/src/com/cloud/network/element/RedundantResource.java b/api/src/com/cloud/network/element/RedundantResource.java
new file mode 100644
index 000000000000..6ed2d67e7c9d
--- /dev/null
+++ b/api/src/com/cloud/network/element/RedundantResource.java
@@ -0,0 +1,28 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network.element;
+
+import com.cloud.network.Network;
+
+/**
+ * Created by bharat on 11/08/15.
+ */
+public interface RedundantResource {
+ public void configureResource(Network network);
+ public int getResourceCount(Network network);
+ public void finalize(Network network, boolean success);
+}
diff --git a/api/src/com/cloud/network/element/UserDataServiceProvider.java b/api/src/com/cloud/network/element/UserDataServiceProvider.java
index 45ab0d877a3e..bf6d7e819e91 100644
--- a/api/src/com/cloud/network/element/UserDataServiceProvider.java
+++ b/api/src/com/cloud/network/element/UserDataServiceProvider.java
@@ -26,7 +26,7 @@
import com.cloud.vm.VirtualMachineProfile;
public interface UserDataServiceProvider extends NetworkElement {
- public boolean addPasswordAndUserdata(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context)
+ boolean addPasswordAndUserdata(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context)
throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException;
boolean savePassword(Network network, NicProfile nic, VirtualMachineProfile vm) throws ResourceUnavailableException;
diff --git a/api/src/com/cloud/network/router/VirtualRouter.java b/api/src/com/cloud/network/router/VirtualRouter.java
index 0114a962146f..84c85ce66758 100644
--- a/api/src/com/cloud/network/router/VirtualRouter.java
+++ b/api/src/com/cloud/network/router/VirtualRouter.java
@@ -23,7 +23,11 @@
*/
public interface VirtualRouter extends VirtualMachine {
public enum Role {
- VIRTUAL_ROUTER, LB, INTERNAL_LB_VM
+ VIRTUAL_ROUTER, LB, INTERNAL_LB_VM, NETSCALER_VM
+ }
+
+ public enum UpdateState {
+ UPDATE_NEEDED, UPDATE_IN_PROGRESS, UPDATE_COMPLETE, UPDATE_FAILED
}
Role getRole();
diff --git a/api/src/com/cloud/network/rules/FirewallRule.java b/api/src/com/cloud/network/rules/FirewallRule.java
index 4346e2f665d7..6a46c7da03dc 100644
--- a/api/src/com/cloud/network/rules/FirewallRule.java
+++ b/api/src/com/cloud/network/rules/FirewallRule.java
@@ -79,6 +79,8 @@ enum TrafficType {
List getSourceCidrList();
+ List getDestinationCidrList();
+
Long getRelated();
FirewallRuleType getType();
diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java
index 3eca14d65436..0b4afeef9458 100644
--- a/api/src/com/cloud/network/rules/RulesService.java
+++ b/api/src/com/cloud/network/rules/RulesService.java
@@ -81,6 +81,6 @@ Pair, Integer> searchStaticNatRules(Long ipId, Long
boolean disableStaticNat(long ipId) throws ResourceUnavailableException, NetworkRuleConflictException, InsufficientAddressCapacityException;
- PortForwardingRule updatePortForwardingRule(long id, Integer privatePort, Long virtualMachineId, Ip vmGuestIp, String customId, Boolean forDisplay);
+ PortForwardingRule updatePortForwardingRule(long id, Integer privatePort, Integer privateEndPort, Long virtualMachineId, Ip vmGuestIp, String customId, Boolean forDisplay);
}
diff --git a/api/src/com/cloud/network/vpc/Vpc.java b/api/src/com/cloud/network/vpc/Vpc.java
index dd607fe6caa9..9f40562423d8 100644
--- a/api/src/com/cloud/network/vpc/Vpc.java
+++ b/api/src/com/cloud/network/vpc/Vpc.java
@@ -87,4 +87,8 @@ public enum State {
* @return true if VPC spans multiple zones in the region
*/
boolean isRegionLevelVpc();
+
+ boolean isRollingRestart();
+
+ void setRollingRestart(boolean rollingRestart);
}
diff --git a/api/src/com/cloud/network/vpc/VpcOffering.java b/api/src/com/cloud/network/vpc/VpcOffering.java
index fb4b151fb4ca..c0da6bf967a5 100644
--- a/api/src/com/cloud/network/vpc/VpcOffering.java
+++ b/api/src/com/cloud/network/vpc/VpcOffering.java
@@ -52,7 +52,7 @@ public enum State {
boolean isDefault();
/**
- * @return service offering id used by VPC virutal router
+ * @return service offering id used by VPC virtual router
*/
Long getServiceOfferingId();
diff --git a/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java b/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java
index decf8c437330..5426d181e70f 100644
--- a/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java
+++ b/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java
@@ -33,7 +33,7 @@ public interface RemoteAccessVpnService {
RemoteAccessVpn createRemoteAccessVpn(long vpnServerAddressId, String ipRange, boolean openFirewall, Boolean forDisplay) throws NetworkRuleConflictException;
- boolean destroyRemoteAccessVpnForIp(long ipId, Account caller) throws ResourceUnavailableException;
+ boolean destroyRemoteAccessVpnForIp(long ipId, Account caller, boolean forceCleanup) throws ResourceUnavailableException;
RemoteAccessVpn startRemoteAccessVpn(long vpnServerAddressId, boolean openFirewall) throws ResourceUnavailableException;
@@ -43,7 +43,7 @@ public interface RemoteAccessVpnService {
List extends VpnUser> listVpnUsers(long vpnOwnerId, String userName);
- boolean applyVpnUsers(long vpnOwnerId, String userName);
+ boolean applyVpnUsers(long vpnOwnerId, String userName) throws ResourceUnavailableException;
Pair, Integer> searchForRemoteAccessVpns(ListRemoteAccessVpnsCmd cmd);
diff --git a/api/src/com/cloud/offering/NetworkOffering.java b/api/src/com/cloud/offering/NetworkOffering.java
index f1ef69c2f68e..33b165bfa298 100644
--- a/api/src/com/cloud/offering/NetworkOffering.java
+++ b/api/src/com/cloud/offering/NetworkOffering.java
@@ -38,7 +38,7 @@ public enum State {
}
public enum Detail {
- InternalLbProvider, PublicLbProvider
+ InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering
}
public final static String SystemPublicNetwork = "System-Public-Network";
@@ -57,6 +57,10 @@ public enum Detail {
public final static String DefaultIsolatedNetworkOfferingForVpcNetworks = "DefaultIsolatedNetworkOfferingForVpcNetworks";
public final static String DefaultIsolatedNetworkOfferingForVpcNetworksNoLB = "DefaultIsolatedNetworkOfferingForVpcNetworksNoLB";
public final static String DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB = "DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB";
+ public final static String DefaultL2NetworkOffering = "DefaultL2NetworkOffering";
+ public final static String DefaultL2NetworkOfferingVlan = "DefaultL2NetworkOfferingVlan";
+ public final static String DefaultL2NetworkOfferingConfigDrive = "DefaultL2NetworkOfferingConfigDrive";
+ public final static String DefaultL2NetworkOfferingConfigDriveVlan = "DefaultL2NetworkOfferingConfigDriveVlan";
/**
* @return name for the network offering.
@@ -78,6 +82,8 @@ public enum Detail {
*/
Integer getMulticastRateMbps();
+ boolean getForVpc();
+
TrafficType getTrafficType();
boolean getSpecifyVlan();
@@ -131,4 +137,8 @@ public enum Detail {
boolean isKeepAliveEnabled();
boolean getSupportsStrechedL2();
+
+ boolean getSupportsPublicAccess();
+
+ String getServicePackage();
}
diff --git a/api/src/com/cloud/offering/ServiceOffering.java b/api/src/com/cloud/offering/ServiceOffering.java
index 05ae2375c178..196d2b4eb47b 100644
--- a/api/src/com/cloud/offering/ServiceOffering.java
+++ b/api/src/com/cloud/offering/ServiceOffering.java
@@ -31,6 +31,7 @@ public interface ServiceOffering extends DiskOffering, InfrastructureEntity, Int
public static final String routerDefaultOffUniqueName = "Cloud.Com-SoftwareRouter";
public static final String elbVmDefaultOffUniqueName = "Cloud.Com-ElasticLBVm";
public static final String internalLbVmDefaultOffUniqueName = "Cloud.Com-InternalLBVm";
+ // leaving cloud.com references as these are identifyers and no real world addresses (check against DB)
public enum StorageType {
local, shared
diff --git a/api/src/com/cloud/org/Cluster.java b/api/src/com/cloud/org/Cluster.java
index 90fcb5729e48..4079c88dfde3 100644
--- a/api/src/com/cloud/org/Cluster.java
+++ b/api/src/com/cloud/org/Cluster.java
@@ -16,13 +16,11 @@
// under the License.
package com.cloud.org;
-import org.apache.cloudstack.api.Identity;
-import org.apache.cloudstack.api.InternalIdentity;
-
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.org.Managed.ManagedState;
+import org.apache.cloudstack.kernel.Partition;
-public interface Cluster extends Grouping, InternalIdentity, Identity {
+public interface Cluster extends Grouping, Partition {
public static enum ClusterType {
CloudManaged, ExternalManaged;
};
diff --git a/api/src/com/cloud/resource/ResourceService.java b/api/src/com/cloud/resource/ResourceService.java
index 7050b97e0feb..854b53591d63 100644
--- a/api/src/com/cloud/resource/ResourceService.java
+++ b/api/src/com/cloud/resource/ResourceService.java
@@ -53,7 +53,7 @@ public interface ResourceService {
Host reconnectHost(ReconnectHostCmd cmd);
/**
- * We will automatically create a cloud.com cluster to attach to the external cluster and return a hyper host to perform
+ * We will automatically create an Apache CloudStack cluster to attach to the external cluster and return a hyper host to perform
* host related operation within the cluster
*
* @param cmd
diff --git a/api/src/com/cloud/resource/ResourceState.java b/api/src/com/cloud/resource/ResourceState.java
index 5d2c962f989a..d952afa0b7dd 100644
--- a/api/src/com/cloud/resource/ResourceState.java
+++ b/api/src/com/cloud/resource/ResourceState.java
@@ -93,6 +93,7 @@ public static String[] toString(ResourceState... states) {
s_fsm.addTransition(ResourceState.Enabled, Event.InternalCreated, ResourceState.Enabled);
s_fsm.addTransition(ResourceState.Enabled, Event.Disable, ResourceState.Disabled);
s_fsm.addTransition(ResourceState.Enabled, Event.AdminAskMaintenace, ResourceState.PrepareForMaintenance);
+ s_fsm.addTransition(ResourceState.Enabled, Event.InternalEnterMaintenance, ResourceState.Maintenance);
s_fsm.addTransition(ResourceState.Disabled, Event.Enable, ResourceState.Enabled);
s_fsm.addTransition(ResourceState.Disabled, Event.Disable, ResourceState.Disabled);
s_fsm.addTransition(ResourceState.Disabled, Event.InternalCreated, ResourceState.Disabled);
@@ -109,5 +110,7 @@ public static String[] toString(ResourceState... states) {
s_fsm.addTransition(ResourceState.ErrorInMaintenance, Event.InternalEnterMaintenance, ResourceState.Maintenance);
s_fsm.addTransition(ResourceState.ErrorInMaintenance, Event.AdminCancelMaintenance, ResourceState.Enabled);
s_fsm.addTransition(ResourceState.Error, Event.InternalCreated, ResourceState.Error);
+ s_fsm.addTransition(ResourceState.Disabled, Event.DeleteHost, ResourceState.Disabled);
+
}
}
diff --git a/api/src/com/cloud/server/ManagementService.java b/api/src/com/cloud/server/ManagementService.java
index 449e1085239c..56f36a8d90ca 100644
--- a/api/src/com/cloud/server/ManagementService.java
+++ b/api/src/com/cloud/server/ManagementService.java
@@ -390,7 +390,7 @@ public interface ManagementService {
* @return Ternary, List extends Host>, Map> List of all Hosts to which a VM
* can be migrated, list of Hosts with enough capacity and hosts requiring storage motion for migration.
*/
- Ternary, Integer>, List extends Host>, Map> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize);
+ Ternary, Integer>, List extends Host>, Map> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize, String keyword);
/**
* List storage pools for live migrating of a volume. The API returns list of all pools in the cluster to which the
diff --git a/api/src/com/cloud/server/ResourceTag.java b/api/src/com/cloud/server/ResourceTag.java
index ce09fdf955b0..0bd5d734e30e 100644
--- a/api/src/com/cloud/server/ResourceTag.java
+++ b/api/src/com/cloud/server/ResourceTag.java
@@ -38,6 +38,7 @@ public enum ResourceObjectType {
SecurityGroupRule(true, false),
PublicIpAddress(true, true),
Project(true, false),
+ Account(true, false),
Vpc(true, true),
NetworkACL(true, true),
StaticRoute(true, false),
@@ -57,7 +58,10 @@ public enum ResourceObjectType {
AutoScaleVmGroup(false, true),
LBStickinessPolicy(false, true),
LBHealthCheckPolicy(false, true),
- SnapshotPolicy(false, true);
+ SnapshotPolicy(false, true),
+ GuestOs(false, true),
+ NetworkOffering(false, true),
+ VpcOffering(true, false);
ResourceObjectType(boolean resourceTagsSupport, boolean resourceMetadataSupport) {
diff --git a/api/src/com/cloud/storage/ImageStore.java b/api/src/com/cloud/storage/ImageStore.java
index ec693c4e4939..c019b17421dd 100644
--- a/api/src/com/cloud/storage/ImageStore.java
+++ b/api/src/com/cloud/storage/ImageStore.java
@@ -41,4 +41,11 @@ public interface ImageStore extends Identity, InternalIdentity {
* @return data store protocol
*/
String getProtocol();
+
+ /**
+ *
+ * @return uri
+ */
+ String getUrl();
+
}
diff --git a/api/src/com/cloud/storage/Snapshot.java b/api/src/com/cloud/storage/Snapshot.java
index 7f0168efd8e3..2f3a59541d9a 100644
--- a/api/src/com/cloud/storage/Snapshot.java
+++ b/api/src/com/cloud/storage/Snapshot.java
@@ -16,14 +16,13 @@
// under the License.
package com.cloud.storage;
-import java.util.Date;
-
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.utils.fsm.StateObject;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
-import com.cloud.hypervisor.Hypervisor.HypervisorType;
-import com.cloud.utils.fsm.StateObject;
+import java.util.Date;
public interface Snapshot extends ControlledEntity, Identity, InternalIdentity, StateObject {
public enum Type {
@@ -67,6 +66,10 @@ enum Event {
CreateRequested, OperationNotPerformed, BackupToSecondary, BackedupToSecondary, DestroyRequested, CopyingRequested, OperationSucceeded, OperationFailed
}
+ enum LocationType {
+ PRIMARY, SECONDARY
+ }
+
public static final long MANUAL_POLICY_ID = 0L;
@Override
@@ -76,6 +79,8 @@ enum Event {
String getName();
+ long getSnapshotId();
+
Date getCreated();
Type getRecurringType();
@@ -89,4 +94,5 @@ enum Event {
short getsnapshotType();
+ LocationType getLocationType(); // This type is in reference to the location where the snapshot resides (ex. primary storage, archive on secondary storage, etc.)
}
diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java
index 25ae5ca4dc92..9093dc34f148 100644
--- a/api/src/com/cloud/storage/Storage.java
+++ b/api/src/com/cloud/storage/Storage.java
@@ -113,36 +113,44 @@ public static enum TemplateType {
SYSTEM, /* routing, system vm template */
BUILTIN, /* buildin template */
PERHOST, /* every host has this template, don't need to install it in secondary storage */
- USER /* User supplied template/iso */
+ USER, /* User supplied template/iso */
+ DATADISK, /* Template corresponding to a datadisk(non root disk) present in an OVA */
+ ISODISK /* Template corresponding to a iso (non root disk) present in an OVA */
}
public static enum StoragePoolType {
- Filesystem(false), // local directory
- NetworkFilesystem(true), // NFS
- IscsiLUN(true), // shared LUN, with a clusterfs overlay
- Iscsi(true), // for e.g., ZFS Comstar
- ISO(false), // for iso image
- LVM(false), // XenServer local LVM SR
- CLVM(true),
- RBD(true), // http://libvirt.org/storage.html#StorageBackendRBD
- SharedMountPoint(true),
- VMFS(true), // VMware VMFS storage
- PreSetup(true), // for XenServer, Storage Pool is set up by customers.
- EXT(false), // XenServer local EXT SR
- OCFS2(true),
- SMB(true),
- Gluster(true),
- ManagedNFS(true);
-
- boolean shared;
-
- StoragePoolType(boolean shared) {
+ Filesystem(false, true), // local directory
+ NetworkFilesystem(true, true), // NFS
+ IscsiLUN(true, false), // shared LUN, with a clusterfs overlay
+ Iscsi(true, false), // for e.g., ZFS Comstar
+ ISO(false, false), // for iso image
+ LVM(false, false), // XenServer local LVM SR
+ CLVM(true, false),
+ RBD(true, true), // http://libvirt.org/storage.html#StorageBackendRBD
+ SharedMountPoint(true, false),
+ VMFS(true, true), // VMware VMFS storage
+ PreSetup(true, true), // for XenServer, Storage Pool is set up by customers.
+ EXT(false, true), // XenServer local EXT SR
+ OCFS2(true, false),
+ SMB(true, false),
+ Gluster(true, false),
+ ManagedNFS(true, false);
+
+ private final boolean shared;
+ private final boolean overprovisioning;
+
+ StoragePoolType(boolean shared, boolean overprovisioning) {
this.shared = shared;
+ this.overprovisioning = overprovisioning;
}
public boolean isShared() {
return shared;
}
+
+ public boolean supportsOverProvisioning() {
+ return overprovisioning;
+ }
}
public static List getNonSharedStoragePoolTypes() {
diff --git a/api/src/com/cloud/storage/StoragePool.java b/api/src/com/cloud/storage/StoragePool.java
index 8e03c3348f3a..3a2d3bd8feec 100644
--- a/api/src/com/cloud/storage/StoragePool.java
+++ b/api/src/com/cloud/storage/StoragePool.java
@@ -104,4 +104,6 @@ public interface StoragePool extends Identity, InternalIdentity {
boolean isInMaintenance();
Hypervisor.HypervisorType getHypervisor();
+
+ boolean isManaged();
}
diff --git a/api/src/com/cloud/storage/VMTemplateStorageResourceAssoc.java b/api/src/com/cloud/storage/VMTemplateStorageResourceAssoc.java
index d40eafe7a15c..f43d5331222f 100644
--- a/api/src/com/cloud/storage/VMTemplateStorageResourceAssoc.java
+++ b/api/src/com/cloud/storage/VMTemplateStorageResourceAssoc.java
@@ -22,7 +22,7 @@
public interface VMTemplateStorageResourceAssoc extends InternalIdentity {
public static enum Status {
- UNKNOWN, DOWNLOAD_ERROR, NOT_DOWNLOADED, DOWNLOAD_IN_PROGRESS, DOWNLOADED, ABANDONED, UPLOADED, NOT_UPLOADED, UPLOAD_ERROR, UPLOAD_IN_PROGRESS, CREATING, CREATED
+ UNKNOWN, DOWNLOAD_ERROR, NOT_DOWNLOADED, DOWNLOAD_IN_PROGRESS, DOWNLOADED, ABANDONED, UPLOADED, NOT_UPLOADED, UPLOAD_ERROR, UPLOAD_IN_PROGRESS, CREATING, CREATED, BYPASSED
}
String getInstallPath();
diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java
index f70ead937189..133a59df8a6d 100644
--- a/api/src/com/cloud/storage/Volume.java
+++ b/api/src/com/cloud/storage/Volume.java
@@ -51,7 +51,8 @@ enum State {
NotUploaded("The volume entry is just created in DB, not yet uploaded"),
UploadInProgress("Volume upload is in progress"),
UploadError("Volume upload encountered some error"),
- UploadAbandoned("Volume upload is abandoned since the upload was never initiated within a specificed time");
+ UploadAbandoned("Volume upload is abandoned since the upload was never initiated within a specificed time"),
+ Attaching("The volume is attaching to a VM");
String _description;
@@ -118,6 +119,9 @@ public String getDescription() {
s_fsm.addTransition(new StateMachine2.Transition(UploadInProgress, Event.OperationTimeout, UploadError, null));
s_fsm.addTransition(new StateMachine2.Transition(UploadError, Event.DestroyRequested, Destroy, null));
s_fsm.addTransition(new StateMachine2.Transition(UploadAbandoned, Event.DestroyRequested, Destroy, null));
+ s_fsm.addTransition(new StateMachine2.Transition(Ready, Event.AttachRequested, Attaching, null));
+ s_fsm.addTransition(new StateMachine2.Transition(Attaching, Event.OperationSucceeded, Ready, null));
+ s_fsm.addTransition(new StateMachine2.Transition(Attaching, Event.OperationFailed, Ready, null));
}
}
@@ -139,6 +143,7 @@ enum Event {
DestroyRequested,
ExpungingRequested,
ResizeRequested,
+ AttachRequested,
OperationTimeout;
}
diff --git a/api/src/com/cloud/storage/VolumeApiService.java b/api/src/com/cloud/storage/VolumeApiService.java
index 7832b892072d..cf13cd671a91 100644
--- a/api/src/com/cloud/storage/VolumeApiService.java
+++ b/api/src/com/cloud/storage/VolumeApiService.java
@@ -18,6 +18,8 @@
*/
package com.cloud.storage;
+import java.net.MalformedURLException;
+
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
@@ -26,13 +28,10 @@
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
+import org.apache.cloudstack.api.response.GetUploadParamsResponse;
-import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.user.Account;
-import org.apache.cloudstack.api.response.GetUploadParamsResponse;
-
-import java.net.MalformedURLException;
public interface VolumeApiService {
/**
@@ -70,23 +69,22 @@ public interface VolumeApiService {
/**
* Uploads the volume to secondary storage
*
- * @param UploadVolumeCmdByAdmin cmd
- *
* @return Volume object
*/
- Volume uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException;
+ Volume uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException;
GetUploadParamsResponse uploadVolume(GetUploadParamsForVolumeCmd cmd) throws ResourceAllocationException, MalformedURLException;
- boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException;
+ boolean deleteVolume(long volumeId, Account caller);
Volume attachVolumeToVM(AttachVolumeCmd command);
- Volume detachVolumeFromVM(DetachVolumeCmd cmmd);
+ Volume detachVolumeFromVM(DetachVolumeCmd cmd);
- Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm) throws ResourceAllocationException;
+ Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm, Snapshot.LocationType locationType, boolean asyncBackup)
+ throws ResourceAllocationException;
- Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName) throws ResourceAllocationException;
+ Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, Snapshot.LocationType locationType) throws ResourceAllocationException;
Volume updateVolume(long volumeId, String path, String state, Long storageId, Boolean displayVolume, String customId, long owner, String chainInfo);
@@ -94,14 +92,14 @@ public interface VolumeApiService {
* Extracts the volume to a particular location.
*
* @param cmd
- * the command specifying url (where the volume needs to be extracted to), zoneId (zone where the volume
- * exists),
+ * the command specifying url (where the volume needs to be extracted to), zoneId (zone where the volume exists),
* id (the id of the volume)
- *
*/
String extractVolume(ExtractVolumeCmd cmd);
boolean isDisplayResourceEnabled(Long id);
void updateDisplay(Volume volume, Boolean displayVolume);
+
+ Snapshot allocSnapshotForVm(Long vmId, Long volumeId, String snapshotName) throws ResourceAllocationException;
}
diff --git a/api/src/com/cloud/storage/VolumeStats.java b/api/src/com/cloud/storage/VolumeStats.java
index 70c0b17f84ab..81fa7eabdd76 100644
--- a/api/src/com/cloud/storage/VolumeStats.java
+++ b/api/src/com/cloud/storage/VolumeStats.java
@@ -20,5 +20,10 @@ public interface VolumeStats {
/**
* @return bytes used by the volume
*/
- public long getBytesUsed();
+ long getVirtualSize();
+
+ /**
+ * @return bytes allocated
+ */
+ long getPhysicalSize();
}
diff --git a/api/src/com/cloud/storage/snapshot/SnapshotApiService.java b/api/src/com/cloud/storage/snapshot/SnapshotApiService.java
index fb48f4774546..eb1393543c0c 100644
--- a/api/src/com/cloud/storage/snapshot/SnapshotApiService.java
+++ b/api/src/com/cloud/storage/snapshot/SnapshotApiService.java
@@ -86,7 +86,7 @@ public interface SnapshotApiService {
boolean deleteSnapshotPolicies(DeleteSnapshotPoliciesCmd cmd);
- Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName) throws ResourceAllocationException;
+ Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, Snapshot.LocationType locationType) throws ResourceAllocationException;
/**
* Create a snapshot of a volume
@@ -108,5 +108,7 @@ public interface SnapshotApiService {
Snapshot revertSnapshot(Long snapshotId);
+ Snapshot backupSnapshotFromVmSnapshot(Long snapshotId, Long vmId, Long volumeId, Long vmSnapshotId);
+
SnapshotPolicy updateSnapshotPolicy(UpdateSnapshotPolicyCmd updateSnapshotPolicyCmd);
}
diff --git a/api/src/com/cloud/template/VirtualMachineTemplate.java b/api/src/com/cloud/template/VirtualMachineTemplate.java
index 54d61a4597bd..564f3b987bec 100644
--- a/api/src/com/cloud/template/VirtualMachineTemplate.java
+++ b/api/src/com/cloud/template/VirtualMachineTemplate.java
@@ -133,6 +133,8 @@ public enum TemplateFilter {
boolean isDynamicallyScalable();
+ Long getParentTemplateId();
+
long getUpdatedCount();
void incrUpdatedCount();
diff --git a/api/src/com/cloud/user/AccountService.java b/api/src/com/cloud/user/AccountService.java
index 959a710d6d9f..9683d9fa3303 100644
--- a/api/src/com/cloud/user/AccountService.java
+++ b/api/src/com/cloud/user/AccountService.java
@@ -21,6 +21,7 @@
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd;
import org.apache.cloudstack.api.command.admin.user.RegisterCmd;
import com.cloud.domain.Domain;
@@ -28,6 +29,7 @@
import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
+
public interface AccountService {
/**
@@ -124,6 +126,8 @@ User createUser(String userName, String password, String firstName, String lastN
void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException;
+ void checkAccess(User user, ControlledEntity entity);
+
void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName,
ControlledEntity... entities) throws PermissionDeniedException;
@@ -136,4 +140,5 @@ void checkAccess(Account account, AccessType accessType, boolean sameOwner, Stri
*/
UserAccount getUserAccountById(Long userId);
+ public Map getKeys(GetUserKeysCmd cmd);
}
diff --git a/api/src/com/cloud/user/ResourceLimitService.java b/api/src/com/cloud/user/ResourceLimitService.java
index fef16da942f6..2df9b037e3d1 100644
--- a/api/src/com/cloud/user/ResourceLimitService.java
+++ b/api/src/com/cloud/user/ResourceLimitService.java
@@ -23,9 +23,13 @@
import com.cloud.configuration.ResourceLimit;
import com.cloud.domain.Domain;
import com.cloud.exception.ResourceAllocationException;
+import org.apache.cloudstack.framework.config.ConfigKey;
public interface ResourceLimitService {
+ static final ConfigKey ResourceCountCheckInterval = new ConfigKey("Advanced", Long.class, "resourcecount.check.interval", "300",
+ "Time (in seconds) to wait before running resource recalculation and fixing task. Default is 300 seconds, Setting this to 0 disables execution of the task", false);
+
/**
* Updates an existing resource limit with the specified details. If a limit doesn't exist, will create one.
*
@@ -64,11 +68,11 @@ public interface ResourceLimitService {
* TODO
* @param domainId
* TODO
- * @param type
+ * @param resourceType
* TODO
* @return a list of limits that match the criteria
*/
- public List extends ResourceLimit> searchForLimits(Long id, Long accountId, Long domainId, Integer type, Long startIndex, Long pageSizeVal);
+ public List extends ResourceLimit> searchForLimits(Long id, Long accountId, Long domainId, ResourceType resourceType, Long startIndex, Long pageSizeVal);
/**
* Finds the resource limit for a specified account and type. If the account has an infinite limit, will check
@@ -100,6 +104,14 @@ public interface ResourceLimitService {
*/
public long findCorrectResourceLimitForDomain(Domain domain, ResourceType type);
+ /**
+ * Finds the default resource limit for a specified type.
+ *
+ * @param resourceType
+ * @return resource limit
+ */
+ public long findDefaultResourceLimitForDomain(ResourceType resourceType);
+
/**
* Increments the resource count
*
diff --git a/api/src/com/cloud/user/User.java b/api/src/com/cloud/user/User.java
index 0ecdcfa58d4e..c3ac66c69790 100644
--- a/api/src/com/cloud/user/User.java
+++ b/api/src/com/cloud/user/User.java
@@ -22,8 +22,9 @@
public interface User extends OwnedBy, InternalIdentity {
+ // UNKNOWN and NATIVE can be used interchangeably
public enum Source {
- LDAP, SAML2, SAML2DISABLED, UNKNOWN
+ LDAP, SAML2, SAML2DISABLED, UNKNOWN, NATIVE
}
public static final long UID_SYSTEM = 1;
diff --git a/api/src/com/cloud/vm/DiskProfile.java b/api/src/com/cloud/vm/DiskProfile.java
index a37f7aaf57b6..d9097748363b 100644
--- a/api/src/com/cloud/vm/DiskProfile.java
+++ b/api/src/com/cloud/vm/DiskProfile.java
@@ -139,6 +139,10 @@ public Long getTemplateId() {
return templateId;
}
+ public void setTemplateId(Long templateId) {
+ this.templateId = templateId;
+ }
+
/**
* @return disk offering id that the disk is based on.
*/
diff --git a/api/src/com/cloud/vm/NicExtraDhcpOption.java b/api/src/com/cloud/vm/NicExtraDhcpOption.java
new file mode 100644
index 000000000000..f5d9fa0c6b46
--- /dev/null
+++ b/api/src/com/cloud/vm/NicExtraDhcpOption.java
@@ -0,0 +1,41 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+public interface NicExtraDhcpOption extends InternalIdentity, Identity {
+
+ /**
+ * Returns the nic id for which the DHCP option applies
+ * @return nic id
+ */
+ long getNicId();
+
+ /**
+ * Returns the DHCP option code
+ * @return
+ */
+ int getCode();
+
+ /**
+ * Returns the Dhcp value
+ * @return
+ */
+ String getValue();
+}
diff --git a/api/src/com/cloud/vm/NicProfile.java b/api/src/com/cloud/vm/NicProfile.java
index 58e05124c89f..6ef9cfe5db16 100644
--- a/api/src/com/cloud/vm/NicProfile.java
+++ b/api/src/com/cloud/vm/NicProfile.java
@@ -114,6 +114,11 @@ public NicProfile(String requestedIPv4, String requestedIPv6) {
this.requestedIPv6 = requestedIPv6;
}
+ public NicProfile(String requestedIPv4, String requestedIPv6, String requestedMacAddress) {
+ this(requestedIPv4, requestedIPv6);
+ this.macAddress = requestedMacAddress;
+ }
+
public NicProfile(ReservationStrategy strategy, String iPv4Address, String macAddress, String iPv4gateway, String iPv4netmask) {
format = AddressFormat.Ip4;
this.iPv4Address = iPv4Address;
diff --git a/api/src/com/cloud/vm/NicSecondaryIp.java b/api/src/com/cloud/vm/NicSecondaryIp.java
index fb90dd351f68..2856e0aea756 100644
--- a/api/src/com/cloud/vm/NicSecondaryIp.java
+++ b/api/src/com/cloud/vm/NicSecondaryIp.java
@@ -32,8 +32,12 @@ public interface NicSecondaryIp extends ControlledEntity, Identity, InternalIden
long getNicId();
+ void setNicId(long nicId);
+
String getIp4Address();
+ String getIp6Address();
+
long getNetworkId();
long getVmId();
diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java
index 54206ed23952..74090ec40e65 100644
--- a/api/src/com/cloud/vm/UserVmService.java
+++ b/api/src/com/cloud/vm/UserVmService.java
@@ -50,6 +50,7 @@
import com.cloud.host.Host;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.Network.IpAddresses;
+import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.StoragePool;
import com.cloud.template.VirtualMachineTemplate;
@@ -75,14 +76,14 @@ public interface UserVmService {
/**
* Destroys one virtual machine
*
- * @param userId
- * the id of the user performing the action
* @param vmId
* the id of the virtual machine.
+ * @param expunge
+ * indicates if vm should be expunged
* @throws ConcurrentOperationException
* @throws ResourceUnavailableException
*/
- UserVm destroyVm(long vmId) throws ResourceUnavailableException, ConcurrentOperationException;
+ UserVm destroyVm(long vmId, boolean expunge) throws ResourceUnavailableException, ConcurrentOperationException;
/**
* Resets the password of a virtual machine.
@@ -194,7 +195,14 @@ UserVm startVirtualMachine(StartVMCmd cmd) throws StorageUnavailableException, E
* @param memory
* @param cpuNumber
* @param customId
+ * @param dhcpOptionMap
+ * - Maps the dhcp option code and the dhcp value to the network uuid
* @return UserVm object if successful.
+ * @param dataDiskTemplateToDiskOfferingMap
+ * - Datadisk template to Disk offering Map
+ * an optional parameter that creates additional data disks for the virtual machine
+ * For each of the templates in the map, a data disk will be created from the corresponding
+ * disk offering obtained from the map
*
* @throws InsufficientCapacityException
* if there is insufficient capacity to deploy the VM.
@@ -208,7 +216,8 @@ UserVm startVirtualMachine(StartVMCmd cmd) throws StorageUnavailableException, E
UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList,
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
- List affinityGroupIdList, Map customParameter, String customId) throws InsufficientCapacityException,
+ List affinityGroupIdList, Map customParameter, String customId, Map> dhcpOptionMap,
+ Map dataDiskTemplateToDiskOfferingMap) throws InsufficientCapacityException,
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
/**
@@ -267,6 +276,13 @@ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering s
* @param memory
* @param cpuNumber
* @param customId
+ * @param dhcpOptionMap
+ * - Maps the dhcp option code and the dhcp value to the network uuid
+ * @param dataDiskTemplateToDiskOfferingMap
+ * - Datadisk template to Disk offering Map
+ * an optional parameter that creates additional data disks for the virtual machine
+ * For each of the templates in the map, a data disk will be created from the corresponding
+ * disk offering obtained from the map
* @return UserVm object if successful.
*
* @throws InsufficientCapacityException
@@ -281,7 +297,8 @@ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering s
UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList,
List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
- List affinityGroupIdList, Map customParameters, String customId) throws InsufficientCapacityException,
+ List affinityGroupIdList, Map customParameters, String customId, Map> dhcpOptionMap,
+ Map dataDiskTemplateToDiskOfferingMap) throws InsufficientCapacityException,
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
/**
@@ -338,6 +355,13 @@ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOfferin
* @param memory
* @param cpuNumber
* @param customId
+ * @param dhcpOptionMap
+ * - Map that maps the DhcpOption code and their value on the Network uuid
+ * @param dataDiskTemplateToDiskOfferingMap
+ * - Datadisk template to Disk offering Map
+ * an optional parameter that creates additional data disks for the virtual machine
+ * For each of the templates in the map, a data disk will be created from the corresponding
+ * disk offering obtained from the map
* @return UserVm object if successful.
*
* @throws InsufficientCapacityException
@@ -352,7 +376,7 @@ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOfferin
UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner,
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList,
- Map customParameters, String customId)
+ Map customParameters, String customId, Map> dhcpOptionMap, Map dataDiskTemplateToDiskOfferingMap)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
@@ -482,4 +506,8 @@ UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws ResourceUnavailableException
*/
public boolean isDisplayResourceEnabled(Long vmId);
+ void collectVmDiskStatistics(UserVm userVm);
+
+ void collectVmNetworkStatistics (UserVm userVm);
+
}
diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java
index b45ac7c9be9f..a46edd78f447 100644
--- a/api/src/com/cloud/vm/VirtualMachine.java
+++ b/api/src/com/cloud/vm/VirtualMachine.java
@@ -16,26 +16,24 @@
// under the License.
package com.cloud.vm;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.Map;
-
-import org.apache.cloudstack.acl.ControlledEntity;
-import org.apache.cloudstack.api.Displayable;
-import org.apache.cloudstack.api.Identity;
-import org.apache.cloudstack.api.InternalIdentity;
-
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.utils.fsm.StateMachine2.Transition;
import com.cloud.utils.fsm.StateMachine2.Transition.Impact;
import com.cloud.utils.fsm.StateObject;
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.api.Displayable;
+import org.apache.cloudstack.kernel.Partition;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map;
/**
* VirtualMachine describes the properties held by a virtual machine
*
*/
-public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, InternalIdentity, Displayable, StateObject {
+public interface VirtualMachine extends RunningOn, ControlledEntity, Partition, Displayable, StateObject {
public enum PowerState {
PowerUnknown,
@@ -214,6 +212,7 @@ public enum Event {
public enum Type {
User(false), DomainRouter(true), ConsoleProxy(true), SecondaryStorageVm(true), ElasticIpVm(true), ElasticLoadBalancerVm(true), InternalLoadBalancerVm(true),
+ NetScalerVm(true),
/*
* UserBareMetal is only used for selecting VirtualMachineGuru, there is no
diff --git a/api/src/com/cloud/vm/VirtualMachineProfile.java b/api/src/com/cloud/vm/VirtualMachineProfile.java
index ed02dcb9c670..977e27eb14f2 100644
--- a/api/src/com/cloud/vm/VirtualMachineProfile.java
+++ b/api/src/com/cloud/vm/VirtualMachineProfile.java
@@ -56,6 +56,7 @@ public static class Param {
public static final Param VmSshPubKey = new Param("VmSshPubKey");
public static final Param ControlNic = new Param("ControlNic");
public static final Param ReProgramGuestNetworks = new Param("RestartNetwork");
+ public static final Param RollingRestart = new Param("RollingRestart");
public static final Param PxeSeverType = new Param("PxeSeverType");
public static final Param HaTag = new Param("HaTag");
public static final Param HaOperation = new Param("HaOperation");
@@ -173,4 +174,6 @@ public boolean equals(Object obj) {
Float getMemoryOvercommitRatio();
+ boolean isRollingRestart();
+
}
diff --git a/api/src/com/cloud/vm/VmDetailConstants.java b/api/src/com/cloud/vm/VmDetailConstants.java
index d34afc13a169..f24c4f587c40 100644
--- a/api/src/com/cloud/vm/VmDetailConstants.java
+++ b/api/src/com/cloud/vm/VmDetailConstants.java
@@ -23,4 +23,8 @@ public interface VmDetailConstants {
public static final String NESTED_VIRTUALIZATION_FLAG = "nestedVirtualizationFlag";
public static final String HYPERVISOR_TOOLS_VERSION = "hypervisortoolsversion";
public static final String DATA_DISK_CONTROLLER = "dataDiskController";
+ public static final String SVGA_VRAM_SIZE = "svga.vramSize";
+ public static final String CPU_NUMBER = "cpuNumber";
+ public static final String CPU_SPEED = "cpuSpeed";
+ public static final String MEMORY = "memory";
}
diff --git a/api/src/com/cloud/vm/VmNetworkStats.java b/api/src/com/cloud/vm/VmNetworkStats.java
new file mode 100644
index 000000000000..7f96fdfdfac0
--- /dev/null
+++ b/api/src/com/cloud/vm/VmNetworkStats.java
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+public interface VmNetworkStats {
+ // vm related network stats
+
+ public long getBytesSent();
+
+ public long getBytesReceived();
+
+}
diff --git a/api/src/com/cloud/vm/snapshot/VMSnapshot.java b/api/src/com/cloud/vm/snapshot/VMSnapshot.java
index 7713b2052ace..c398e583fae5 100644
--- a/api/src/com/cloud/vm/snapshot/VMSnapshot.java
+++ b/api/src/com/cloud/vm/snapshot/VMSnapshot.java
@@ -102,4 +102,6 @@ enum Event {
@Override
public long getAccountId();
+
+ public long getServiceOfferingId();
}
diff --git a/api/src/com/cloud/vm/snapshot/VMSnapshotService.java b/api/src/com/cloud/vm/snapshot/VMSnapshotService.java
index 12767b3db158..e376265acfa4 100644
--- a/api/src/com/cloud/vm/snapshot/VMSnapshotService.java
+++ b/api/src/com/cloud/vm/snapshot/VMSnapshotService.java
@@ -36,7 +36,7 @@ public interface VMSnapshotService {
VMSnapshot getVMSnapshotById(Long id);
- VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId, Boolean quiescevm);
+ VMSnapshot createVMSnapshot(Long vmId, Long vmSnapshotId, Boolean quiescevm);
VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDescription, Boolean snapshotMemory) throws ResourceAllocationException;
@@ -46,4 +46,11 @@ UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientServerCapacityExce
ConcurrentOperationException;
VirtualMachine getVMBySnapshotId(Long id);
+
+ /**
+ * Delete vm snapshots only from database. Introduced as a Vmware optimization in which vm snapshots are deleted when
+ * the vm gets deleted on hypervisor (no need to delete each vm snapshot before deleting vm, just mark them as deleted on DB)
+ * @param id vm id
+ */
+ boolean deleteVMSnapshotsFromDB(Long vmId);
}
diff --git a/api/src/org/apache/cloudstack/acl/RoleService.java b/api/src/org/apache/cloudstack/acl/RoleService.java
index 59eef51e782f..6130c62a7d45 100644
--- a/api/src/org/apache/cloudstack/acl/RoleService.java
+++ b/api/src/org/apache/cloudstack/acl/RoleService.java
@@ -17,36 +17,64 @@
package org.apache.cloudstack.acl;
-import org.apache.cloudstack.framework.config.ConfigKey;
-
import java.util.List;
+import org.apache.cloudstack.acl.RolePermission.Permission;
+import org.apache.cloudstack.framework.config.ConfigKey;
+
public interface RoleService {
ConfigKey EnableDynamicApiChecker = new ConfigKey<>("Advanced", Boolean.class, "dynamic.apichecker.enabled", "false",
- "If set to true, this enables the dynamic role-based api access checker and disables the default static role-based api access checker.",
- true);
+ "If set to true, this enables the dynamic role-based api access checker and disables the default static role-based api access checker.", true);
boolean isEnabled();
- Role findRole(final Long id);
- Role createRole(final String name, final RoleType roleType, final String description);
- boolean updateRole(final Role role, final String name, final RoleType roleType, final String description);
- boolean deleteRole(final Role role);
- RolePermission findRolePermission(final Long id);
- RolePermission findRolePermissionByUuid(final String uuid);
+ /**
+ * Searches for a role with the given ID. If the ID is null or less than zero, this method will return null.
+ * This method will also return null if no role is found with the provided ID.
+ * Moreover, we will check if the requested role is of 'Admin' type; roles with 'Admin' type should only be visible to 'root admins'.
+ * Therefore, if a non-'root admin' user tries to search for an 'Admin' role, this method will return null.
+ */
+ Role findRole(Long id);
+
+ Role createRole(String name, RoleType roleType, String description);
+
+ Role updateRole(Role role, String name, RoleType roleType, String description);
+
+ boolean deleteRole(Role role);
+
+ RolePermission findRolePermission(Long id);
+
+ RolePermission findRolePermissionByUuid(String uuid);
+
+ RolePermission createRolePermission(Role role, Rule rule, Permission permission, String description);
- RolePermission createRolePermission(final Role role, final Rule rule, final RolePermission.Permission permission, final String description);
/**
* updateRolePermission updates the order/position of an role permission
* @param role The role whose permissions needs to be re-ordered
* @param newOrder The new list of ordered role permissions
*/
- boolean updateRolePermission(final Role role, final List newOrder);
- boolean deleteRolePermission(final RolePermission rolePermission);
+ boolean updateRolePermission(Role role, List newOrder);
+ boolean updateRolePermission(Role role, RolePermission rolePermission, Permission permission);
+
+ boolean deleteRolePermission(RolePermission rolePermission);
+
+ /**
+ * List all roles configured in the database. Roles that have the type {@link RoleType#Admin} will not be shown for users that are not 'root admin'.
+ */
List listRoles();
- List findRolesByName(final String name);
- List findRolesByType(final RoleType roleType);
- List findAllPermissionsBy(final Long roleId);
+
+ /**
+ * Find all roles that have the giving {@link String} as part of their name.
+ * If the user calling the method is not a 'root admin', roles of type {@link RoleType#Admin} wil lbe removed of the returned list.
+ */
+ List findRolesByName(String name);
+
+ /**
+ * Find all roles by {@link RoleType}. If the role type is {@link RoleType#Admin}, the calling account must be a root admin, otherwise we return an empty list.
+ */
+ List findRolesByType(RoleType roleType);
+
+ List findAllPermissionsBy(Long roleId);
}
diff --git a/api/src/org/apache/cloudstack/alert/AlertService.java b/api/src/org/apache/cloudstack/alert/AlertService.java
index ad711ecea4e8..26c3f3cf3ab4 100644
--- a/api/src/org/apache/cloudstack/alert/AlertService.java
+++ b/api/src/org/apache/cloudstack/alert/AlertService.java
@@ -16,12 +16,12 @@
// under the License.
package org.apache.cloudstack.alert;
-import java.util.HashSet;
-import java.util.Set;
-
import com.cloud.capacity.Capacity;
import com.cloud.exception.InvalidParameterValueException;
+import java.util.HashSet;
+import java.util.Set;
+
public interface AlertService {
public static class AlertType {
private static Set defaultAlertTypes = new HashSet();
@@ -67,6 +67,8 @@ private AlertType(short type, String name, boolean isDefault) {
public static final AlertType ALERT_TYPE_SYNC = new AlertType((short)27, "ALERT.TYPE.SYNC", true);
public static final AlertType ALERT_TYPE_UPLOAD_FAILED = new AlertType((short)28, "ALERT.UPLOAD.FAILED", true);
public static final AlertType ALERT_TYPE_OOBM_AUTH_ERROR = new AlertType((short)29, "ALERT.OOBM.AUTHERROR", true);
+ public static final AlertType ALERT_TYPE_HA_ACTION = new AlertType((short)30, "ALERT.HA.ACTION", true);
+ public static final AlertType ALERT_TYPE_CA_CERT = new AlertType((short)31, "ALERT.CA.CERT", true);
public short getType() {
return type;
diff --git a/api/src/org/apache/cloudstack/annotation/Annotation.java b/api/src/org/apache/cloudstack/annotation/Annotation.java
new file mode 100644
index 000000000000..90e371e5071d
--- /dev/null
+++ b/api/src/org/apache/cloudstack/annotation/Annotation.java
@@ -0,0 +1,37 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.annotation;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+import java.util.Date;
+
+public interface Annotation extends InternalIdentity, Identity {
+
+ String getAnnotation();
+
+ String getEntityUuid();
+
+ AnnotationService.EntityType getEntityType();
+
+ String getUserUuid();
+
+ Date getCreated();
+
+ Date getRemoved();
+}
diff --git a/api/src/org/apache/cloudstack/annotation/AnnotationService.java b/api/src/org/apache/cloudstack/annotation/AnnotationService.java
new file mode 100644
index 000000000000..769a753b587b
--- /dev/null
+++ b/api/src/org/apache/cloudstack/annotation/AnnotationService.java
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.annotation;
+
+import org.apache.cloudstack.api.command.admin.annotation.AddAnnotationCmd;
+import org.apache.cloudstack.api.command.admin.annotation.ListAnnotationsCmd;
+import org.apache.cloudstack.api.command.admin.annotation.RemoveAnnotationCmd;
+import org.apache.cloudstack.api.response.AnnotationResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+
+public interface AnnotationService {
+ ListResponse searchForAnnotations(ListAnnotationsCmd cmd);
+
+ AnnotationResponse addAnnotation(AddAnnotationCmd addAnnotationCmd);
+ AnnotationResponse addAnnotation(String text, EntityType type, String uuid);
+
+ AnnotationResponse removeAnnotation(RemoveAnnotationCmd removeAnnotationCmd);
+
+ enum EntityType {
+ HOST("host"), DOMAIN("domain"), VM("vm_instance");
+ private String tableName;
+
+ EntityType(String tableName) {
+ this.tableName = tableName;
+ }
+ static public boolean contains(String representation) {
+ try {
+ /* EntityType tiep = */ valueOf(representation);
+ return true;
+ } catch (IllegalArgumentException iae) {
+ return false;
+ }
+ }
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/APICommand.java b/api/src/org/apache/cloudstack/api/APICommand.java
index d451e4b10a3a..c559be081165 100644
--- a/api/src/org/apache/cloudstack/api/APICommand.java
+++ b/api/src/org/apache/cloudstack/api/APICommand.java
@@ -16,8 +16,6 @@
// under the License.
package org.apache.cloudstack.api;
-import static java.lang.annotation.ElementType.TYPE;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -25,9 +23,12 @@
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import static java.lang.annotation.ElementType.TYPE;
+
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE})
public @interface APICommand {
+
Class extends BaseResponse> responseObject();
String name() default "";
diff --git a/api/src/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java b/api/src/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java
index df63d7471581..c82f4789367c 100644
--- a/api/src/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java
+++ b/api/src/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java
@@ -18,15 +18,15 @@
*/
package org.apache.cloudstack.api;
+import java.net.URL;
+import java.util.UUID;
+
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.log4j.Logger;
-import java.net.URL;
-import java.util.UUID;
-
public abstract class AbstractGetUploadParamsCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(AbstractGetUploadParamsCmd.class.getName());
@@ -42,7 +42,7 @@ public abstract class AbstractGetUploadParamsCmd extends BaseCmd {
+ "to be hosted on")
private Long zoneId;
- @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the MD5 checksum value of this volume/template")
+ @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the checksum value of this volume/template " + ApiConstants.CHECKSUM_PARAMETER_PREFIX_DESCRIPTION)
private String checksum;
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional accountName. Must be used with domainId.")
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 1d0b4a3756a7..03ee7fc1b20b 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -21,10 +21,13 @@ public class ApiConstants {
public static final String ACCOUNTS = "accounts";
public static final String ACCOUNT_TYPE = "accounttype";
public static final String ACCOUNT_ID = "accountid";
+ public static final String ACTIVITY = "activity";
public static final String ADDRESS = "address";
public static final String ALGORITHM = "algorithm";
public static final String ALLOCATED_ONLY = "allocatedonly";
+ public static final String ANNOTATION = "annotation";
public static final String API_KEY = "apikey";
+ public static final String ASYNC_BACKUP = "asyncbackup";
public static final String USER_API_KEY = "userapikey";
public static final String APPLIED = "applied";
public static final String LIST_LB_VMIPS = "lbvmips";
@@ -35,12 +38,15 @@ public class ApiConstants {
public static final String BIND_PASSWORD = "bindpass";
public static final String BYTES_READ_RATE = "bytesreadrate";
public static final String BYTES_WRITE_RATE = "byteswriterate";
+ public static final String BYPASS_VLAN_OVERLAP_CHECK = "bypassvlanoverlapcheck";
public static final String CATEGORY = "category";
public static final String CAN_REVERT = "canrevert";
+ public static final String CA_CERTIFICATES = "cacertificates";
public static final String CERTIFICATE = "certificate";
public static final String CERTIFICATE_CHAIN = "certchain";
public static final String CERTIFICATE_FINGERPRINT = "fingerprint";
public static final String CERTIFICATE_ID = "certid";
+ public static final String CSR = "csr";
public static final String PRIVATE_KEY = "privatekey";
public static final String DOMAIN_SUFFIX = "domainsuffix";
public static final String DNS_SEARCH_ORDER = "dnssearchorder";
@@ -48,11 +54,13 @@ public class ApiConstants {
public static final String CIDR = "cidr";
public static final String IP6_CIDR = "ip6cidr";
public static final String CIDR_LIST = "cidrlist";
+ public static final String DEST_CIDR_LIST = "destcidrlist";
public static final String CLEANUP = "cleanup";
- public static final String MAKEREDUNDANTE = "makeredundant";
+ public static final String MAKEREDUNDANT = "makeredundant";
public static final String CLUSTER_ID = "clusterid";
public static final String CLUSTER_NAME = "clustername";
public static final String CLUSTER_TYPE = "clustertype";
+ public static final String CN = "cn";
public static final String COMMAND = "command";
public static final String CMD_EVENT_TYPE = "cmdeventtype";
public static final String COMPONENT = "component";
@@ -71,14 +79,20 @@ public class ApiConstants {
public static final String MIN_IOPS = "miniops";
public static final String MAX_IOPS = "maxiops";
public static final String HYPERVISOR_SNAPSHOT_RESERVE = "hypervisorsnapshotreserve";
+ public static final String DATADISK_OFFERING_LIST = "datadiskofferinglist";
public static final String DESCRIPTION = "description";
public static final String DESTINATION_ZONE_ID = "destzoneid";
public static final String DETAILS = "details";
public static final String DEVICE_ID = "deviceid";
+ public static final String DIRECT_DOWNLOAD = "directdownload";
public static final String DISK_OFFERING_ID = "diskofferingid";
public static final String DISK_SIZE = "disksize";
+ public static final String UTILIZATION = "utilization";
public static final String DRIVER = "driver";
public static final String ROOT_DISK_SIZE = "rootdisksize";
+ public static final String DHCP_OPTIONS_NETWORK_LIST = "dhcpoptionsnetworklist";
+ public static final String DHCP_OPTIONS = "dhcpoptions";
+ public static final String DHCP_PREFIX = "dhcp:";
public static final String DISPLAY_NAME = "displayname";
public static final String DISPLAY_NETWORK = "displaynetwork";
public static final String DISPLAY_NIC = "displaynic";
@@ -94,6 +108,7 @@ public class ApiConstants {
public static final String DOMAIN_ID = "domainid";
public static final String DOMAIN__ID = "domainId";
public static final String DURATION = "duration";
+ public static final String ELIGIBLE = "eligible";
public static final String EMAIL = "email";
public static final String END_DATE = "enddate";
public static final String END_IP = "endip";
@@ -101,12 +116,18 @@ public class ApiConstants {
public static final String END_PORT = "endport";
public static final String ENTRY_TIME = "entrytime";
public static final String EXPIRES = "expires";
+ public static final String EXTRA_DHCP_OPTION = "extradhcpoption";
+ public static final String EXTRA_DHCP_OPTION_NAME = "extradhcpoptionname";
+ public static final String EXTRA_DHCP_OPTION_CODE = "extradhcpoptioncode";
+ public static final String EXTRA_DHCP_OPTION_VALUE = "extradhcpvalue";
+ public static final String FENCE = "fence";
public static final String FETCH_LATEST = "fetchlatest";
public static final String FIRSTNAME = "firstname";
public static final String FORCED = "forced";
public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage";
public static final String FORMAT = "format";
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
+ public static final String FOR_SYSTEM_VMS = "forsystemvms";
public static final String GATEWAY = "gateway";
public static final String IP6_GATEWAY = "ip6gateway";
public static final String GROUP = "group";
@@ -119,6 +140,9 @@ public class ApiConstants {
public static final String GUEST_CIDR_ADDRESS = "guestcidraddress";
public static final String GUEST_VLAN_RANGE = "guestvlanrange";
public static final String HA_ENABLE = "haenable";
+ public static final String HA_PROVIDER = "haprovider";
+ public static final String HA_STATE = "hastate";
+ public static final String HEALTH = "health";
public static final String HOST_ID = "hostid";
public static final String HOST_NAME = "hostname";
public static final String HYPERVISOR = "hypervisor";
@@ -131,6 +155,7 @@ public class ApiConstants {
public static final String INTERNAL_DNS1 = "internaldns1";
public static final String INTERNAL_DNS2 = "internaldns2";
public static final String INTERVAL_TYPE = "intervaltype";
+ public static final String LOCATION_TYPE = "locationtype";
public static final String IOPS_READ_RATE = "iopsreadrate";
public static final String IOPS_WRITE_RATE = "iopswriterate";
public static final String IP_ADDRESS = "ipaddress";
@@ -161,6 +186,7 @@ public class ApiConstants {
public static final String LUN = "lun";
public static final String LBID = "lbruleid";
public static final String MAX = "max";
+ public static final String MAC_ADDRESS = "macaddress";
public static final String MAX_SNAPS = "maxsnaps";
public static final String MEMORY = "memory";
public static final String MODE = "mode";
@@ -182,7 +208,9 @@ public class ApiConstants {
public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate";
public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled";
public static final String PARAMS = "params";
+ public static final String PARENT_ID = "parentid";
public static final String PARENT_DOMAIN_ID = "parentdomainid";
+ public static final String PARENT_TEMPLATE_ID = "parenttemplateid";
public static final String PASSWORD = "password";
public static final String SHOULD_UPDATE_PASSWORD = "update_passwd_on_host";
public static final String NEW_PASSWORD = "new_password";
@@ -190,6 +218,7 @@ public class ApiConstants {
public static final String SSHKEY_ENABLED = "sshkeyenabled";
public static final String PATH = "path";
public static final String POD_ID = "podid";
+ public static final String POD_NAME = "podname";
public static final String POD_IDS = "podids";
public static final String POLICY_ID = "policyid";
public static final String PORT = "port";
@@ -214,8 +243,11 @@ public class ApiConstants {
public static final String PUBLIC_END_PORT = "publicendport";
public static final String PUBLIC_ZONE = "publiczone";
public static final String RECEIVED_BYTES = "receivedbytes";
+ public static final String RECONNECT = "reconnect";
+ public static final String RECOVER = "recover";
public static final String REQUIRES_HVM = "requireshvm";
public static final String RESOURCE_TYPE = "resourcetype";
+ public static final String RESOURCE_TYPE_NAME = "resourcetypename";
public static final String RESPONSE = "response";
public static final String REVERTABLE = "revertable";
public static final String REGISTERED = "registered";
@@ -223,6 +255,7 @@ public class ApiConstants {
public static final String SCHEDULE = "schedule";
public static final String SCOPE = "scope";
public static final String SECRET_KEY = "usersecretkey";
+ public static final String SECONDARY_IP = "secondaryip";
public static final String SINCE = "since";
public static final String KEY = "key";
public static final String SEARCH_BASE = "searchbase";
@@ -232,6 +265,7 @@ public class ApiConstants {
public static final String SECURITY_GROUP_ID = "securitygroupid";
public static final String SENT = "sent";
public static final String SENT_BYTES = "sentbytes";
+ public static final String SERIAL = "serial";
public static final String SERVICE_OFFERING_ID = "serviceofferingid";
public static final String SESSIONKEY = "sessionkey";
public static final String SHOW_CAPACITIES = "showcapacities";
@@ -239,18 +273,21 @@ public class ApiConstants {
public static final String SIGNATURE = "signature";
public static final String SIGNATURE_VERSION = "signatureversion";
public static final String SIZE = "size";
+ public static final String SNAPSHOT = "snapshot";
public static final String SNAPSHOT_ID = "snapshotid";
public static final String SNAPSHOT_POLICY_ID = "snapshotpolicyid";
public static final String SNAPSHOT_TYPE = "snapshottype";
public static final String SNAPSHOT_QUIESCEVM = "quiescevm";
public static final String SOURCE_ZONE_ID = "sourcezoneid";
public static final String START_DATE = "startdate";
+ public static final String START_ID = "startid";
public static final String START_IP = "startip";
public static final String START_IPV6 = "startipv6";
public static final String START_PORT = "startport";
public static final String STATE = "state";
public static final String STATUS = "status";
public static final String STORAGE_TYPE = "storagetype";
+ public static final String STORAGE_POLICY = "storagepolicy";
public static final String STORAGE_MOTION_ENABLED = "storagemotionenabled";
public static final String STORAGE_CAPABILITIES = "storagecapabilities";
public static final String SYSTEM_VM_TYPE = "systemvmtype";
@@ -261,6 +298,7 @@ public class ApiConstants {
public static final String ISO_ID = "isoid";
public static final String TIMEOUT = "timeout";
public static final String TIMEZONE = "timezone";
+ public static final String TIMEZONEOFFSET = "timezoneoffset";
public static final String TYPE = "type";
public static final String TRUST_STORE = "truststore";
public static final String TRUST_STORE_PASSWORD = "truststorepass";
@@ -272,6 +310,7 @@ public class ApiConstants {
public static final String USERNAME = "username";
public static final String USER_SECURITY_GROUP_LIST = "usersecuritygrouplist";
public static final String USE_VIRTUAL_NETWORK = "usevirtualnetwork";
+ public static final String Update_IN_SEQUENCE ="updateinsequence";
public static final String VALUE = "value";
public static final String VIRTUAL_MACHINE_ID = "virtualmachineid";
public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids";
@@ -279,12 +318,14 @@ public class ApiConstants {
public static final String VIRTUAL_MACHINE_COUNT = "virtualmachinecount";
public static final String USAGE_ID = "usageid";
public static final String USAGE_TYPE = "usagetype";
+ public static final String INCLUDE_TAGS = "includetags";
public static final String VLAN = "vlan";
public static final String VLAN_RANGE = "vlanrange";
public static final String REMOVE_VLAN = "removevlan";
public static final String VLAN_ID = "vlanid";
public static final String ISOLATED_PVLAN = "isolatedpvlan";
+ public static final String ISOLATION_URI = "isolationuri";
public static final String VM_AVAILABLE = "vmavailable";
public static final String VM_LIMIT = "vmlimit";
public static final String VM_TOTAL = "vmtotal";
@@ -299,6 +340,7 @@ public class ApiConstants {
public static final String COUNT = "count";
public static final String TRAFFIC_TYPE = "traffictype";
public static final String NETWORK_OFFERING_ID = "networkofferingid";
+ public static final String TIER_NETWORK_OFFERINGS = "tiernetworkofferings";
public static final String NETWORK_IDS = "networkids";
public static final String NETWORK_ID = "networkid";
public static final String NIC_ID = "nicid";
@@ -342,6 +384,7 @@ public class ApiConstants {
public static final String ZONE_TOKEN = "zonetoken";
public static final String DHCP_PROVIDER = "dhcpprovider";
public static final String RESULT = "success";
+ public static final String RESUME = "resume";
public static final String LUN_ID = "lunId";
public static final String IQN = "iqn";
public static final String AGGREGATE_NAME = "aggregatename";
@@ -368,6 +411,7 @@ public class ApiConstants {
public static final String ROLE_NAME = "rolename";
public static final String PERMISSION = "permission";
public static final String RULE = "rule";
+ public static final String RULE_ID = "ruleid";
public static final String RULE_ORDER = "ruleorder";
public static final String USER = "user";
public static final String ACTIVE_ONLY = "activeonly";
@@ -385,6 +429,7 @@ public class ApiConstants {
public static final String CAPACITY_IOPS = "capacityiops";
public static final String NETWORK_SPEED = "networkspeed";
public static final String BROADCAST_DOMAIN_RANGE = "broadcastdomainrange";
+ public static final String BROADCAST_URI = "broadcasturi";
public static final String ISOLATION_METHOD = "isolationmethod";
public static final String ISOLATION_METHODS = "isolationmethods";
public static final String PHYSICAL_NETWORK_ID = "physicalnetworkid";
@@ -511,6 +556,8 @@ public class ApiConstants {
public static final String NICIRA_NVP_DEVICE_NAME = "niciradevicename";
public static final String NICIRA_NVP_GATEWAYSERVICE_UUID = "l3gatewayserviceuuid";
public static final String NICIRA_NVP_L2_GATEWAYSERVICE_UUID = "l2gatewayserviceuuid";
+ public static final String NSX_LOGICAL_SWITCH = "nsxlogicalswitch";
+ public static final String NSX_LOGICAL_SWITCH_PORT = "nsxlogicalswitchport";
public static final String S3_ACCESS_KEY = "accesskey";
public static final String S3_SECRET_KEY = "secretkey";
public static final String S3_END_POINT = "endpoint";
@@ -613,6 +660,7 @@ public class ApiConstants {
public static final String IAM_ALLOW_DENY = "permission";
public static final String ENTITY_TYPE = "entitytype";
public static final String ENTITY_ID = "entityid";
+ public static final String EXTERNAL_ID = "externalid";
public static final String ACCESS_TYPE = "accesstype";
public static final String RESOURCE_DETAILS = "resourcedetails";
@@ -633,20 +681,40 @@ public class ApiConstants {
public static final String REMAININGCAPACITY = "remainingcapacity";
public static final String MAXCAPACITY = "maxcapacity";
public static final String DISTRIBUTED_VPC_ROUTER = "distributedvpcrouter";
+ public static final String REDUNDANT_ROUTER = "redundantrouter";
public static final String REDUNDANT_VPC_ROUTER = "redundantvpcrouter";
public static final String READ_ONLY = "readonly";
public static final String SUPPORTS_REGION_LEVEL_VPC = "supportsregionLevelvpc";
public static final String SUPPORTS_STRECHED_L2_SUBNET = "supportsstrechedl2subnet";
+ public static final String SUPPORTS_PUBLIC_ACCESS = "supportspublicaccess";
public static final String REGION_LEVEL_VPC = "regionlevelvpc";
public static final String STRECHED_L2_SUBNET = "strechedl2subnet";
+ public static final String NETWORK_NAME = "networkname";
public static final String NETWORK_SPANNED_ZONES = "zonesnetworkspans";
public static final String METADATA = "metadata";
public static final String PHYSICAL_SIZE = "physicalsize";
public static final String OVM3_POOL = "ovm3pool";
public static final String OVM3_CLUSTER = "ovm3cluster";
public static final String OVM3_VIP = "ovm3vip";
+ public static final String CLEAN_UP_DETAILS = "cleanupdetails";
+ public static final String VIRTUAL_SIZE = "virtualsize";
+ public static final String NETSCALER_CONTROLCENTER_ID = "netscalercontrolcenterid";
+ public static final String NETSCALER_SERVICEPACKAGE_ID = "netscalerservicepackageid";
+ public static final String ZONE_ID_LIST = "zoneids";
+ public static final String DESTINATION_ZONE_ID_LIST = "destzoneids";
public static final String ADMIN = "admin";
+ public static final String CHECKSUM_PARAMETER_PREFIX_DESCRIPTION = "The parameter containing the checksum will be considered a MD5sum if it is not prefixed\n"
+ + " and just a plain ascii/utf8 representation of a hexadecimal string. If it is required to\n"
+ + " use another algorithm the hexadecimal string is to be prefixed with a string of the form,\n"
+ + " \"{}\", not including the double quotes. In this is the exact string\n"
+ + " representing the java supported algorithm, i.e. MD5 or SHA-256. Note that java does not\n"
+ + " contain an algorithm called SHA256 or one called sha-256, only SHA-256.";
+
+ public static final String HAS_ANNOTATION = "hasannotation";
+ public static final String LAST_ANNOTATED = "lastannotated";
+ public static final String LDAP_DOMAIN = "ldapdomain";
+
public enum HostDetails {
all, capacity, events, stats, min;
@@ -655,4 +723,8 @@ public enum HostDetails {
public enum VMDetails {
all, group, nics, stats, secgrp, tmpl, servoff, diskoff, iso, volume, min, affgrp;
}
+
+ public enum DomainDetails {
+ all, resource, min;
+ }
}
diff --git a/api/src/org/apache/cloudstack/api/ApiServerService.java b/api/src/org/apache/cloudstack/api/ApiServerService.java
index aeeb7b613cab..382b48a5e026 100644
--- a/api/src/org/apache/cloudstack/api/ApiServerService.java
+++ b/api/src/org/apache/cloudstack/api/ApiServerService.java
@@ -24,7 +24,7 @@
import com.cloud.exception.CloudAuthenticationException;
public interface ApiServerService {
- public boolean verifyRequest(Map requestParameters, Long userId) throws ServerApiException;
+ public boolean verifyRequest(Map requestParameters, Long userId, InetAddress remoteAddress) throws ServerApiException;
public Long fetchDomainId(String domainUUID);
@@ -43,7 +43,4 @@ public ResponseObject loginUser(HttpSession session, String username, String pas
public Class> getCmdClass(String cmdName);
- public String getJSONContentType();
-
- public boolean isSecureSessionCookieEnabled();
}
diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java
index 5be75196d39a..37dbeaab841a 100644
--- a/api/src/org/apache/cloudstack/api/BaseCmd.java
+++ b/api/src/org/apache/cloudstack/api/BaseCmd.java
@@ -17,32 +17,6 @@
package org.apache.cloudstack.api;
-import java.lang.reflect.Field;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import javax.inject.Inject;
-
-import com.cloud.utils.HttpUtils;
-import org.apache.cloudstack.acl.RoleService;
-import org.apache.log4j.Logger;
-
-import org.apache.cloudstack.acl.RoleType;
-import org.apache.cloudstack.affinity.AffinityGroupService;
-import org.apache.cloudstack.alert.AlertService;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
-import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
-import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
-import org.apache.cloudstack.query.QueryService;
-import org.apache.cloudstack.usage.UsageService;
-
import com.cloud.configuration.ConfigurationService;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
@@ -78,11 +52,35 @@
import com.cloud.user.AccountService;
import com.cloud.user.DomainService;
import com.cloud.user.ResourceLimitService;
+import com.cloud.utils.HttpUtils;
import com.cloud.utils.ReflectUtil;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.UUIDManager;
import com.cloud.vm.UserVmService;
import com.cloud.vm.snapshot.VMSnapshotService;
+import org.apache.cloudstack.acl.RoleService;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.affinity.AffinityGroupService;
+import org.apache.cloudstack.alert.AlertService;
+import org.apache.cloudstack.annotation.AnnotationService;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
+import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
+import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
+import org.apache.cloudstack.query.QueryService;
+import org.apache.cloudstack.usage.UsageService;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+import java.lang.reflect.Field;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
public abstract class BaseCmd {
private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName());
@@ -93,6 +91,7 @@ public abstract class BaseCmd {
public static Pattern newInputDateFormat = Pattern.compile("[\\d]+-[\\d]+-[\\d]+ [\\d]+:[\\d]+:[\\d]+");
private static final DateFormat s_outputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
protected static final Map, List> fieldsForCmdClass = new HashMap, List>();
+
public static enum HTTPMethod {
GET, POST, PUT, DELETE
}
@@ -192,6 +191,8 @@ public static enum CommandType {
public AlertService _alertSvc;
@Inject
public UUIDManager _uuidMgr;
+ @Inject
+ public AnnotationService annotationService;
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException, NetworkRuleConflictException;
diff --git a/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java b/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
index 5dc2b06f4c71..36767345a4bf 100644
--- a/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
+++ b/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
@@ -17,7 +17,6 @@
package org.apache.cloudstack.api;
import org.apache.log4j.Logger;
-
import org.apache.cloudstack.api.command.user.iso.UpdateIsoCmd;
import org.apache.cloudstack.api.response.GuestOSResponse;
import org.apache.cloudstack.api.response.TemplateResponse;
@@ -73,6 +72,11 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends BaseCmd {
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, description = "Details in key/value pairs using format details[i].keyname=keyvalue. Example: details[0].hypervisortoolsversion=xenserver61")
protected Map details;
+ @Parameter(name = ApiConstants.CLEAN_UP_DETAILS,
+ type = CommandType.BOOLEAN,
+ description = "optional boolean field, which indicates if details should be cleaned up or not (if set to true, details removed for this resource, details field ignored; if false or not set, no action)")
+ private Boolean cleanupDetails;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -129,4 +133,8 @@ public Map getDetails() {
Collection paramsCollection = this.details.values();
return (Map) (paramsCollection.toArray())[0];
}
-}
\ No newline at end of file
+
+ public boolean isCleanupDetails(){
+ return cleanupDetails == null ? false : cleanupDetails.booleanValue();
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
index 1cc5bc8ae012..4fb248cd1055 100644
--- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java
+++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
@@ -20,6 +20,7 @@
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
@@ -237,6 +238,8 @@ public interface ResponseGenerator {
VlanIpRangeResponse createVlanIpRangeResponse(Vlan vlan);
+ VlanIpRangeResponse createVlanIpRangeResponse(Class extends VlanIpRangeResponse> subClass, Vlan vlan);
+
IPAddressResponse createIPAddressResponse(ResponseView view, IpAddress ipAddress);
GuestVlanRangeResponse createDedicatedGuestVlanRangeResponse(GuestVlan result);
@@ -283,6 +286,8 @@ public interface ResponseGenerator {
Host findHostById(Long hostId);
+ DiskOffering findDiskOfferingById(Long diskOfferingId);
+
VpnUsersResponse createVpnUserResponse(VpnUser user);
RemoteAccessVpnResponse createRemoteAccessVpnResponse(RemoteAccessVpn vpn);
@@ -305,7 +310,11 @@ public interface ResponseGenerator {
TemplateResponse createTemplateUpdateResponse(ResponseView view, VirtualMachineTemplate result);
- List createTemplateResponses(ResponseView view, VirtualMachineTemplate result, Long zoneId, boolean readyOnly);
+ List createTemplateResponses(ResponseView view, VirtualMachineTemplate result,
+ Long zoneId, boolean readyOnly);
+
+ List createTemplateResponses(ResponseView view, VirtualMachineTemplate result,
+ List zoneIds, boolean readyOnly);
List createCapacityResponse(List extends Capacity> result, DecimalFormat format);
@@ -424,6 +433,10 @@ public interface ResponseGenerator {
UsageRecordResponse createUsageResponse(Usage usageRecord);
+ UsageRecordResponse createUsageResponse(Usage usageRecord, Map> resourceTagResponseMap);
+
+ public Map> getUsageResourceTags();
+
TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor);
VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot);
diff --git a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java
index 2e1fbd6f8614..074df8d5fc22 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java
@@ -184,7 +184,7 @@ public long getEntityOwnerId() {
@Override
public void execute() {
validateParams();
- CallContext.current().setEventDetails("Account Name: " + getAccountName() + ", Domain Id:" + getDomainId());
+ CallContext.current().setEventDetails("Account Name: " + getUsername() + ", Domain Id:" + getDomainId());
UserAccount userAccount =
_accountService.createUserAccount(getUsername(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimeZone(), getAccountName(), getAccountType(), getRoleId(),
getDomainId(), getNetworkDomain(), getDetails(), getAccountUUID(), getUserUUID());
diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java
index 994573d17966..87f0288dd01d 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java
@@ -34,7 +34,7 @@
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.9.0",
authorized = {RoleType.Admin})
-public class CreateRoleCmd extends BaseCmd {
+public class CreateRoleCmd extends RoleCmd {
public static final String APINAME = "createRole";
/////////////////////////////////////////////////////
@@ -83,16 +83,6 @@ public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
- private void setupResponse(final Role role) {
- final RoleResponse response = new RoleResponse();
- response.setId(role.getUuid());
- response.setRoleName(role.getName());
- response.setRoleType(role.getRoleType());
- response.setResponseName(getCommandName());
- response.setObjectName("role");
- setResponseObject(response);
- }
-
@Override
public void execute() {
CallContext.current().setEventDetails("Role: " + getRoleName() + ", type:" + getRoleType() + ", description: " + getRoleDescription());
diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java
index 5cf870bfc063..9025e89a93cd 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java
@@ -17,31 +17,25 @@
package org.apache.cloudstack.api.command.admin.acl;
-import com.cloud.exception.ConcurrentOperationException;
-import com.cloud.exception.InsufficientCapacityException;
-import com.cloud.exception.NetworkRuleConflictException;
-import com.cloud.exception.ResourceAllocationException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.user.Account;
-import com.google.common.base.Strings;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
-import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.RoleResponse;
+import org.apache.commons.lang3.StringUtils;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import com.cloud.user.Account;
+import com.google.common.base.Strings;
-@APICommand(name = ListRolesCmd.APINAME, description = "Lists dynamic roles in CloudStack", responseObject = RoleResponse.class,
- requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
- since = "4.9.0",
- authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin})
+@APICommand(name = ListRolesCmd.APINAME, description = "Lists dynamic roles in CloudStack", responseObject = RoleResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.9.0", authorized = {
+ RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin})
public class ListRolesCmd extends BaseCmd {
public static final String APINAME = "listRoles";
@@ -112,13 +106,13 @@ private void setupResponse(final List roles) {
}
@Override
- public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
- final List roles;
+ public void execute() {
+ List roles;
if (getId() != null && getId() > 0L) {
roles = Collections.singletonList(roleService.findRole(getId()));
- } else if (!Strings.isNullOrEmpty(getName())) {
+ } else if (StringUtils.isNotBlank(getName())) {
roles = roleService.findRolesByName(getName());
- } else if (getRoleType() != null){
+ } else if (getRoleType() != null) {
roles = roleService.findRolesByType(getRoleType());
} else {
roles = roleService.listRoles();
diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/RoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/RoleCmd.java
new file mode 100644
index 000000000000..9054ff5fadaf
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/acl/RoleCmd.java
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.acl;
+
+import org.apache.cloudstack.acl.Role;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.response.RoleResponse;
+
+public abstract class RoleCmd extends BaseCmd {
+
+ protected void setupResponse(final Role role) {
+ final RoleResponse response = new RoleResponse();
+ response.setId(role.getUuid());
+ response.setRoleName(role.getName());
+ response.setRoleType(role.getRoleType());
+ response.setDescription(role.getDescription());
+ response.setResponseName(getCommandName());
+ response.setObjectName("role");
+ setResponseObject(response);
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java
index e17fc6f5714b..f9519aeec5a1 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java
@@ -22,21 +22,20 @@
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.response.RoleResponse;
-import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
-@APICommand(name = UpdateRoleCmd.APINAME, description = "Updates a role", responseObject = SuccessResponse.class,
+@APICommand(name = UpdateRoleCmd.APINAME, description = "Updates a role", responseObject = RoleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.9.0",
authorized = {RoleType.Admin})
-public class UpdateRoleCmd extends BaseCmd {
+public class UpdateRoleCmd extends RoleCmd {
public static final String APINAME = "updateRole";
/////////////////////////////////////////////////////
@@ -100,9 +99,7 @@ public void execute() {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided");
}
CallContext.current().setEventDetails("Role: " + getRoleName() + ", type:" + getRoleType() + ", description: " + getRoleDescription());
- boolean result = roleService.updateRole(role, getRoleName(), getRoleType(), getRoleDescription());
- SuccessResponse response = new SuccessResponse(getCommandName());
- response.setSuccess(result);
- setResponseObject(response);
+ role = roleService.updateRole(role, getRoleName(), getRoleType(), getRoleDescription());
+ setupResponse(role);
}
}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java
index 055265c5ccc8..045464eab79a 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java
@@ -20,6 +20,7 @@
import com.cloud.user.Account;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RolePermission;
+import org.apache.cloudstack.acl.RolePermission.Permission;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
@@ -51,10 +52,18 @@ public class UpdateRolePermissionCmd extends BaseCmd {
description = "ID of the role", validations = {ApiArgValidator.PositiveNumber})
private Long roleId;
- @Parameter(name = ApiConstants.RULE_ORDER, type = CommandType.LIST, collectionType = CommandType.UUID, required = true, entityType = RolePermissionResponse.class,
+ @Parameter(name = ApiConstants.RULE_ORDER, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = RolePermissionResponse.class,
description = "The parent role permission uuid, use 0 to move this rule at the top of the list")
private List rulePermissionOrder;
+ @Parameter(name = ApiConstants.RULE_ID, type = CommandType.UUID, entityType = RolePermissionResponse.class,
+ description = "Role permission rule id", since="4.11")
+ private Long ruleId;
+
+ @Parameter(name = ApiConstants.PERMISSION, type = CommandType.STRING,
+ description = "Rule permission, can be: allow or deny", since="4.11")
+ private String rulePermission;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -67,6 +76,21 @@ public List getRulePermissionOrder() {
return rulePermissionOrder;
}
+ public Long getRuleId() {
+ return ruleId;
+ }
+
+ public Permission getRulePermission() {
+ if (this.rulePermission == null) {
+ return null;
+ }
+ if (!this.rulePermission.equalsIgnoreCase(Permission.ALLOW.toString()) &&
+ !this.rulePermission.equalsIgnoreCase(Permission.DENY.toString())) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Values for permission parameter should be: allow or deny");
+ }
+ return rulePermission.equalsIgnoreCase(Permission.ALLOW.toString()) ? Permission.ALLOW : Permission.DENY;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@@ -84,19 +108,35 @@ public long getEntityOwnerId() {
@Override
public void execute() {
final Role role = roleService.findRole(getRoleId());
+ boolean result = false;
if (role == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided");
}
- CallContext.current().setEventDetails("Reordering permissions for role id: " + role.getId());
- final List rolePermissionsOrder = new ArrayList<>();
- for (Long rolePermissionId : getRulePermissionOrder()) {
- final RolePermission rolePermission = roleService.findRolePermission(rolePermissionId);
+ if (getRulePermissionOrder() != null) {
+ if (getRuleId() != null || getRulePermission() != null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Parameters permission and ruleid must be mutually exclusive with ruleorder");
+ }
+ CallContext.current().setEventDetails("Reordering permissions for role id: " + role.getId());
+ final List rolePermissionsOrder = new ArrayList<>();
+ for (Long rolePermissionId : getRulePermissionOrder()) {
+ final RolePermission rolePermission = roleService.findRolePermission(rolePermissionId);
+ if (rolePermission == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Provided role permission(s) do not exist");
+ }
+ rolePermissionsOrder.add(rolePermission);
+ }
+ result = roleService.updateRolePermission(role, rolePermissionsOrder);
+ } else if (getRuleId() != null && getRulePermission() != null) {
+ if (getRulePermissionOrder() != null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Parameters permission and ruleid must be mutually exclusive with ruleorder");
+ }
+ RolePermission rolePermission = roleService.findRolePermission(getRuleId());
if (rolePermission == null) {
- throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Provided role permission(s) do not exist");
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid rule id provided");
}
- rolePermissionsOrder.add(rolePermission);
+ CallContext.current().setEventDetails("Updating permission for rule id: " + getRuleId() + " to: " + getRulePermission().toString());
+ result = roleService.updateRolePermission(role, rolePermission, getRulePermission());
}
- boolean result = roleService.updateRolePermission(role, rolePermissionsOrder);
SuccessResponse response = new SuccessResponse(getCommandName());
response.setSuccess(result);
setResponseObject(response);
diff --git a/api/src/org/apache/cloudstack/api/command/admin/address/AcquirePodIpCmdByAdmin.java b/api/src/org/apache/cloudstack/api/command/admin/address/AcquirePodIpCmdByAdmin.java
new file mode 100644
index 000000000000..fea0ca64d9c4
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/address/AcquirePodIpCmdByAdmin.java
@@ -0,0 +1,92 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.address;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.AcquirePodIpCmdResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+
+@APICommand(name = "acquirePodIpAddress", description = "Allocates IP addresses in respective Pod of a Zone", responseObject = AcquirePodIpCmdResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class AcquirePodIpCmdByAdmin extends BaseCmd {
+
+ public static final Logger s_logger = Logger.getLogger(AcquirePodIpCmdByAdmin.class.getName());
+ private static final String s_name = "acquirepodipaddress";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.STRING, entityType = ZoneResponse.class, required = true, description = "the ID of the zone")
+ private String zoneId;
+
+ @Parameter(name = ApiConstants.POD_ID, type = CommandType.STRING, entityType = ZoneResponse.class, required = false, description = "Pod ID")
+ private String podId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ private String getZoneId() {
+ return zoneId;
+ }
+
+ public String getPodId() {
+ return podId;
+ }
+
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, ResourceAllocationException, ConcurrentOperationException {
+ AcquirePodIpCmdResponse podIp = null;
+ podIp = _networkService.allocatePodIp(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getPodId());
+ if (podIp != null) {
+ podIp.setResponseName(getCommandName());
+ podIp.setObjectName(getCommandName());
+ setResponseObject(podIp);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to assign IP address");
+ }
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccount().getAccountId();
+ }
+
+}
\ No newline at end of file
diff --git a/api/src/org/apache/cloudstack/api/command/admin/address/ReleasePodIpCmdByAdmin.java b/api/src/org/apache/cloudstack/api/command/admin/address/ReleasePodIpCmdByAdmin.java
new file mode 100644
index 000000000000..750a85d57f2f
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/address/ReleasePodIpCmdByAdmin.java
@@ -0,0 +1,79 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements. See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership. The ASF licenses this file
+//to you under the Apache License, Version 2.0 (the
+//"License"); you may not use this file except in compliance
+//with the License. You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing,
+//software distributed under the License is distributed on an
+//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+//KIND, either express or implied. See the License for the
+//specific language governing permissions and limitations
+//under the License.
+package org.apache.cloudstack.api.command.admin.address;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd;
+import org.apache.cloudstack.api.response.AcquireIPAddressResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+
+import com.cloud.user.Account;
+
+@APICommand(name = "releasePodIpAddress", description = "Releases a Pod IP back to the Pod", responseObject = SuccessResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class ReleasePodIpCmdByAdmin extends BaseCmd {
+ public static final Logger s_logger = Logger.getLogger(ReleasePublicIpRangeCmd.class.getName());
+
+ private static final String s_name = "releasepodipresponse";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.ID, type = CommandType.LONG, entityType = AcquireIPAddressResponse.class, required = true, description = "UUID of the Pod IP")
+ private Long id;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public long getId() {
+ return id;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ @Override
+ public void execute() {
+ boolean result = _networkService.releasePodIp(this);
+ if (result) {
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ response.setDisplayText("IP is released sucessfully");
+ setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to release Pod ip ");
+ }
+ }
+}
\ No newline at end of file
diff --git a/api/src/org/apache/cloudstack/api/command/admin/annotation/AddAnnotationCmd.java b/api/src/org/apache/cloudstack/api/command/admin/annotation/AddAnnotationCmd.java
new file mode 100644
index 000000000000..07a73ce095f4
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/annotation/AddAnnotationCmd.java
@@ -0,0 +1,86 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.annotation;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.google.common.base.Preconditions;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.annotation.AnnotationService;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.AnnotationResponse;
+import org.apache.cloudstack.context.CallContext;
+
+@APICommand(name = AddAnnotationCmd.APINAME, description = "add an annotation.", responseObject = AnnotationResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.11", authorized = {RoleType.Admin})
+public class AddAnnotationCmd extends BaseCmd {
+
+ public static final String APINAME = "addAnnotation";
+
+ @Parameter(name = ApiConstants.ANNOTATION, type = CommandType.STRING, description = "the annotation text")
+ private String annotation;
+ @Parameter(name = ApiConstants.ENTITY_TYPE, type = CommandType.STRING, description = "the entity type (only HOST is allowed atm)")
+ private String entityType;
+ @Parameter(name = ApiConstants.ENTITY_ID, type = CommandType.STRING, description = "the id of the entity to annotate")
+ private String entityUuid;
+
+ public String getAnnotation() {
+ return annotation;
+ }
+
+ protected void setEntityType(String newType) {
+ entityType = newType;
+ }
+ public AnnotationService.EntityType getEntityType() {
+ return AnnotationService.EntityType.valueOf(entityType);
+ }
+
+ protected void setEntityUuid(String newUuid) {
+ entityUuid = newUuid;
+ }
+ public String getEntityUuid() {
+ return entityUuid;
+ }
+
+ @Override
+ public void execute()
+ throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException,
+ NetworkRuleConflictException {
+ Preconditions.checkNotNull(getEntityUuid(),"I have to have an entity to set an annotation on!");
+ Preconditions.checkState(AnnotationService.EntityType.contains(entityType),(java.lang.String)"'%s' is ot a valid EntityType to put annotations on", entityType);
+ AnnotationResponse annotationResponse = annotationService.addAnnotation(this);
+ annotationResponse.setResponseName(getCommandName());
+ this.setResponseObject(annotationResponse);
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccount().getAccountId();
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/annotation/ListAnnotationsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/annotation/ListAnnotationsCmd.java
new file mode 100644
index 000000000000..4657eb9e16a3
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/annotation/ListAnnotationsCmd.java
@@ -0,0 +1,81 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.annotation;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.utils.StringUtils;
+import com.google.common.base.Preconditions;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.AnnotationResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+
+@APICommand(name = ListAnnotationsCmd.APINAME, description = "Lists annotations.", responseObject = AnnotationResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.11", authorized = {RoleType.Admin})
+public class ListAnnotationsCmd extends BaseListCmd {
+
+ public static final String APINAME = "listAnnotations";
+
+ @Parameter(name = ApiConstants.ID, type = CommandType.STRING, description = "the id of the annotation")
+ private String uuid;
+ @Parameter(name = ApiConstants.ENTITY_TYPE, type = CommandType.STRING, description = "the entity type")
+ private String entityType;
+ @Parameter(name = ApiConstants.ENTITY_ID, type = CommandType.STRING, description = "the id of the entity for which to show annotations")
+ private String entityUuid;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public String getEntityType() {
+ return entityType;
+ }
+
+ public String getEntityUuid() {
+ return entityUuid;
+ }
+
+ @Override public void execute()
+ throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException,
+ NetworkRuleConflictException {
+ // preconditions to check:
+ // if entity type is null entity uuid can not have a value
+ Preconditions.checkArgument(StringUtils.isNotBlank(entityType) ? ! StringUtils.isNotBlank(uuid) : true,
+ "I can search for an anotation on an entity or for a specific annotation, not both");
+ // if uuid has a value entity type and entity uuid can not have a value
+ Preconditions.checkArgument(StringUtils.isNotBlank(uuid) ? entityType == null && entityUuid == null : true,
+ "I will either search for a specific annotation or for annotations on an entity, not both");
+
+ ListResponse response = annotationService.searchForAnnotations(this);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ response.setObjectName("annotations");
+ }
+
+ @Override public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/annotation/RemoveAnnotationCmd.java b/api/src/org/apache/cloudstack/api/command/admin/annotation/RemoveAnnotationCmd.java
new file mode 100644
index 000000000000..581ce45f2520
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/annotation/RemoveAnnotationCmd.java
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.annotation;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.AnnotationResponse;
+import org.apache.cloudstack.context.CallContext;
+
+@APICommand(name = RemoveAnnotationCmd.APINAME, description = "remove an annotation.", responseObject = AnnotationResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.11", authorized = {RoleType.Admin})
+public class RemoveAnnotationCmd extends BaseCmd {
+
+ public static final String APINAME = "removeAnnotation";
+
+ @Parameter(name = ApiConstants.ID, type = CommandType.STRING, required = true, description = "the id of the annotation")
+ private String uuid;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ @Override
+ public void execute()
+ throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException,
+ NetworkRuleConflictException {
+ AnnotationResponse annotationResponse = annotationService.removeAnnotation(this);
+ annotationResponse.setResponseName(getCommandName());
+ this.setResponseObject(annotationResponse);
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccount().getAccountId();
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ca/IssueCertificateCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ca/IssueCertificateCmd.java
new file mode 100644
index 000000000000..8926829205f6
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ca/IssueCertificateCmd.java
@@ -0,0 +1,162 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ca;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.CertificateResponse;
+import org.apache.cloudstack.ca.CAManager;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.ca.Certificate;
+import org.apache.cloudstack.utils.security.CertUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.event.EventTypes;
+import com.google.common.base.Strings;
+
+@APICommand(name = IssueCertificateCmd.APINAME,
+ description = "Issues a client certificate using configured or provided CA plugin",
+ responseObject = CertificateResponse.class,
+ requestHasSensitiveInfo = true,
+ responseHasSensitiveInfo = true,
+ since = "4.11.0",
+ authorized = {RoleType.Admin})
+public class IssueCertificateCmd extends BaseAsyncCmd {
+ private static final Logger LOG = Logger.getLogger(IssueCertificateCmd.class);
+
+ public static final String APINAME = "issueCertificate";
+
+ @Inject
+ private CAManager caManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.CSR, type = BaseCmd.CommandType.STRING, description = "The certificate signing request (in pem format), if CSR is not provided then configured/provided options are considered", length = 65535)
+ private String csr;
+
+ @Parameter(name = ApiConstants.DOMAIN, type = BaseCmd.CommandType.STRING, description = "Comma separated list of domains, the certificate should be issued for. When csr is not provided, the first domain is used as a subject/CN")
+ private String domains;
+
+ @Parameter(name = ApiConstants.IP_ADDRESS, type = BaseCmd.CommandType.STRING, description = "Comma separated list of IP addresses, the certificate should be issued for")
+ private String addresses;
+
+ @Parameter(name = ApiConstants.DURATION, type = CommandType.INTEGER, description = "Certificate validity duration in number of days, when not provided the default configured value will be used")
+ private Integer validityDuration;
+
+ @Parameter(name = ApiConstants.PROVIDER, type = BaseCmd.CommandType.STRING, description = "Name of the CA service provider, otherwise the default configured provider plugin will be used")
+ private String provider;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public String getCsr() {
+ return csr;
+ }
+
+ private List processList(final String string) {
+ final List list = new ArrayList<>();
+ if (!Strings.isNullOrEmpty(string)) {
+ for (final String address: string.split(",")) {
+ list.add(address.trim());
+ }
+ }
+ return list;
+ }
+
+ public List getAddresses() {
+ return processList(addresses);
+ }
+
+ public List getDomains() {
+ return processList(domains);
+ }
+
+ public Integer getValidityDuration() {
+ return validityDuration;
+ }
+
+ public String getProvider() {
+ return provider;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public void execute() {
+ if (Strings.isNullOrEmpty(getCsr()) && getDomains().isEmpty()) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please provide the domains or the CSR, none of them are provided");
+ }
+ final Certificate certificate = caManager.issueCertificate(getCsr(), getDomains(), getAddresses(), getValidityDuration(), getProvider());
+ if (certificate == null) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to issue client certificate with given provider");
+ }
+
+ final CertificateResponse certificateResponse = new CertificateResponse();
+ try {
+ certificateResponse.setCertificate(CertUtils.x509CertificateToPem(certificate.getClientCertificate()));
+ if (certificate.getPrivateKey() != null) {
+ certificateResponse.setPrivateKey(CertUtils.privateKeyToPem(certificate.getPrivateKey()));
+ }
+ if (certificate.getCaCertificates() != null) {
+ certificateResponse.setCaCertificate(CertUtils.x509CertificatesToPem(certificate.getCaCertificates()));
+ }
+ } catch (final IOException e) {
+ LOG.error("Failed to generate and convert client certificate(s) to PEM due to error: ", e);
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to process and return client certificate");
+ }
+ certificateResponse.setResponseName(getCommandName());
+ setResponseObject(certificateResponse);
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccount().getId();
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_CA_CERTIFICATE_ISSUE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "issuing certificate for domain(s)=" + domains + ", ip(s)=" + addresses;
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ca/ListCAProvidersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ca/ListCAProvidersCmd.java
new file mode 100644
index 000000000000..e1e8e3751633
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ca/ListCAProvidersCmd.java
@@ -0,0 +1,102 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ca;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.CAProviderResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.ca.CAManager;
+import org.apache.cloudstack.framework.ca.CAProvider;
+
+import com.cloud.user.Account;
+
+@APICommand(name = ListCAProvidersCmd.APINAME,
+ description = "Lists available certificate authority providers in CloudStack",
+ responseObject = CAProviderResponse.class,
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false,
+ since = "4.11.0",
+ authorized = {RoleType.Admin})
+public class ListCAProvidersCmd extends BaseCmd {
+ public static final String APINAME = "listCAProviders";
+
+ @Inject
+ private CAManager caManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "List CA service provider by name")
+ private String name;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public String getName() {
+ return name;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ private void setupResponse(final List providers) {
+ final ListResponse response = new ListResponse<>();
+ final List responses = new ArrayList<>();
+ for (final CAProvider provider : providers) {
+ if (provider == null || (getName() != null && !provider.getProviderName().equals(getName()))) {
+ continue;
+ }
+ final CAProviderResponse caProviderResponse = new CAProviderResponse();
+ caProviderResponse.setName(provider.getProviderName());
+ caProviderResponse.setDescription(provider.getDescription());
+ caProviderResponse.setObjectName("caprovider");
+ responses.add(caProviderResponse);
+ }
+ response.setResponses(responses);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() {
+ final List caProviders = caManager.getCaProviders();
+ setupResponse(caProviders);
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ca/ListCaCertificateCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ca/ListCaCertificateCmd.java
new file mode 100644
index 000000000000..1baa84179f03
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ca/ListCaCertificateCmd.java
@@ -0,0 +1,90 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ca;
+
+import java.io.IOException;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.CertificateResponse;
+import org.apache.cloudstack.ca.CAManager;
+
+import com.cloud.user.Account;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = ListCaCertificateCmd.APINAME,
+ description = "Lists the CA public certificate(s) as support by the configured/provided CA plugin",
+ responseObject = CertificateResponse.class,
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false,
+ since = "4.11.0",
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class ListCaCertificateCmd extends BaseCmd {
+ public static final String APINAME = "listCaCertificate";
+
+ @Inject
+ private CAManager caManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, description = "Name of the CA service provider, otherwise the default configured provider plugin will be used")
+ private String provider;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public String getProvider() {
+ return provider;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public void execute() {
+ final String caCertificates;
+ try {
+ caCertificates = caManager.getCaCertificate(getProvider());
+ } catch (final IOException e) {
+ throw new CloudRuntimeException("Failed to get CA certificates for given CA provider");
+ }
+ final CertificateResponse certificateResponse = new CertificateResponse("cacertificates");
+ certificateResponse.setCertificate(caCertificates);
+ certificateResponse.setResponseName(getCommandName());
+ setResponseObject(certificateResponse);
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_TYPE_NORMAL;
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ca/ProvisionCertificateCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ca/ProvisionCertificateCmd.java
new file mode 100644
index 000000000000..2745f071dd07
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ca/ProvisionCertificateCmd.java
@@ -0,0 +1,125 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ca;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiCommandJobType;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.ca.CAManager;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.event.EventTypes;
+import com.cloud.host.Host;
+
+@APICommand(name = ProvisionCertificateCmd.APINAME,
+ description = "Issues and propagates client certificate on a connected host/agent using configured CA plugin",
+ responseObject = SuccessResponse.class,
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false,
+ since = "4.11.0",
+ authorized = {RoleType.Admin})
+public class ProvisionCertificateCmd extends BaseAsyncCmd {
+ public static final String APINAME = "provisionCertificate";
+
+ @Inject
+ private CAManager caManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, required = true, entityType = HostResponse.class,
+ description = "The host/agent uuid to which the certificate has to be provisioned (issued and propagated)")
+ private Long hostId;
+
+ @Parameter(name = ApiConstants.RECONNECT, type = CommandType.BOOLEAN,
+ description = "Whether to attempt reconnection with host/agent after successful deployment of certificate. When option is not provided, configured global setting is used")
+ private Boolean reconnect;
+
+ @Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING,
+ description = "Name of the CA service provider, otherwise the default configured provider plugin will be used")
+ private String provider;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getHostId() {
+ return hostId;
+ }
+
+ public Boolean getReconnect() {
+ return reconnect;
+ }
+
+ public String getProvider() {
+ return provider;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public void execute() {
+ final Host host = _resourceService.getHost(getHostId());
+ if (host == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId());
+ }
+
+ boolean result = caManager.provisionCertificate(host, getReconnect(), getProvider());
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ response.setSuccess(result);
+ setResponseObject(response);
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccount().getId();
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_CA_CERTIFICATE_PROVISION;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "provisioning certificate for host id=" + hostId + " using provider=" + provider;
+ }
+
+ @Override
+ public ApiCommandJobType getInstanceType() {
+ return ApiCommandJobType.Host;
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ca/RevokeCertificateCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ca/RevokeCertificateCmd.java
new file mode 100644
index 000000000000..0f154f045df0
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ca/RevokeCertificateCmd.java
@@ -0,0 +1,116 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ca;
+
+import java.math.BigInteger;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.ca.CAManager;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.event.EventTypes;
+import com.google.common.base.Strings;
+
+@APICommand(name = RevokeCertificateCmd.APINAME,
+ description = "Revokes certificate using configured CA plugin",
+ responseObject = SuccessResponse.class,
+ requestHasSensitiveInfo = true,
+ responseHasSensitiveInfo = false,
+ since = "4.11.0",
+ authorized = {RoleType.Admin})
+public class RevokeCertificateCmd extends BaseAsyncCmd {
+
+ public static final String APINAME = "revokeCertificate";
+
+ @Inject
+ private CAManager caManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.SERIAL, type = BaseCmd.CommandType.STRING, required = true, description = "The certificate serial number, as a hex value")
+ private String serial;
+
+ @Parameter(name = ApiConstants.CN, type = BaseCmd.CommandType.STRING, description = "The certificate CN")
+ private String cn;
+
+ @Parameter(name = ApiConstants.PROVIDER, type = BaseCmd.CommandType.STRING, description = "Name of the CA service provider, otherwise the default configured provider plugin will be used")
+ private String provider;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public BigInteger getSerialBigInteger() {
+ if (Strings.isNullOrEmpty(serial)) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Certificate serial cannot be empty");
+ }
+ return new BigInteger(serial, 16);
+ }
+
+ public String getCn() {
+ return cn;
+ }
+
+ public String getProvider() {
+ return provider;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public void execute() {
+ boolean result = caManager.revokeCertificate(getSerialBigInteger(), getCn(), getProvider());
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ response.setSuccess(result);
+ setResponseObject(response);
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccount().getId();
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_CA_CERTIFICATE_REVOKE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "revoking certificate with serial id=" + serial + ", cn=" + cn;
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
index a34bc3eb6221..80ebaf43f647 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
@@ -19,6 +19,7 @@
import java.util.ArrayList;
import java.util.List;
+import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@@ -28,6 +29,7 @@
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
@@ -76,6 +78,18 @@ public class ListCfgsByCmd extends BaseListCmd {
description = "the ID of the Account to update the parameter value for corresponding account")
private Long accountId;
+ @Parameter(name = ApiConstants.DOMAIN_ID,
+ type = CommandType.UUID,
+ entityType = DomainResponse.class,
+ description = "the ID of the Domain to update the parameter value for corresponding domain")
+ private Long domainId;
+
+ @Parameter(name = ApiConstants.IMAGE_STORE_UUID,
+ type = CommandType.UUID,
+ entityType = ImageStoreResponse.class,
+ description = "the ID of the Image Store to update the parameter value for corresponding image store")
+ private Long imageStoreId;
+
// ///////////////////////////////////////////////////
// ///////////////// Accessors ///////////////////////
// ///////////////////////////////////////////////////
@@ -104,6 +118,14 @@ public Long getAccountId() {
return accountId;
}
+ public Long getDomainId() {
+ return domainId;
+ }
+
+ public Long getImageStoreId() {
+ return imageStoreId;
+ }
+
@Override
public Long getPageSizeVal() {
Long defaultPageSize = 500L;
@@ -147,6 +169,12 @@ public void execute() {
if (getAccountId() != null) {
cfgResponse.setScope("account");
}
+ if (getDomainId() != null) {
+ cfgResponse.setScope("domain");
+ }
+ if (getImageStoreId() != null){
+ cfgResponse.setScope("imagestore");
+ }
configResponses.add(cfgResponse);
}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
index 45f790fb70be..936f0cd69f1a 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
@@ -18,9 +18,10 @@
import com.google.common.base.Strings;
import org.apache.cloudstack.acl.RoleService;
+import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.log4j.Logger;
-
import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
@@ -29,6 +30,7 @@
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration;
@@ -75,6 +77,19 @@ public class UpdateCfgCmd extends BaseCmd {
description = "the ID of the Account to update the parameter value for corresponding account")
private Long accountId;
+ @Parameter(name = ApiConstants.DOMAIN_ID,
+ type = CommandType.UUID,
+ entityType = DomainResponse.class,
+ description = "the ID of the Domain to update the parameter value for corresponding domain")
+ private Long domainId;
+
+ @Parameter(name = ApiConstants.IMAGE_STORE_UUID,
+ type = CommandType.UUID,
+ entityType = ImageStoreResponse.class,
+ description = "the ID of the Image Store to update the parameter value for corresponding image store",
+ validations = ApiArgValidator.PositiveNumber)
+ private Long imageStoreId;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -107,6 +122,14 @@ public Long getAccountId() {
return accountId;
}
+ public Long getDomainId() {
+ return domainId;
+ }
+
+ public Long getImageStoreId() {
+ return imageStoreId;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@@ -145,6 +168,9 @@ public void execute() {
if (getAccountId() != null) {
response.setScope("account");
}
+ if (getDomainId() != null) {
+ response.setScope("domain");
+ }
response.setValue(value);
this.setResponseObject(response);
} else {
diff --git a/api/src/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificate.java b/api/src/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificate.java
new file mode 100755
index 000000000000..89c0c25c9ca0
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificate.java
@@ -0,0 +1,92 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.direct.download;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.exception.NetworkRuleConflictException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.direct.download.DirectDownloadManager;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+
+@APICommand(name = UploadTemplateDirectDownloadCertificate.APINAME,
+ description = "Upload a certificate for HTTPS direct template download on KVM hosts",
+ responseObject = SuccessResponse.class,
+ requestHasSensitiveInfo = true,
+ responseHasSensitiveInfo = true,
+ since = "4.11.0",
+ authorized = {RoleType.Admin})
+public class UploadTemplateDirectDownloadCertificate extends BaseCmd {
+
+ @Inject
+ DirectDownloadManager directDownloadManager;
+
+ private static final Logger LOG = Logger.getLogger(UploadTemplateDirectDownloadCertificate.class);
+ public static final String APINAME = "uploadTemplateDirectDownloadCertificate";
+
+ @Parameter(name = ApiConstants.CERTIFICATE, type = BaseCmd.CommandType.STRING, required = true, length = 65535,
+ description = "SSL certificate")
+ private String certificate;
+
+ @Parameter(name = ApiConstants.NAME , type = BaseCmd.CommandType.STRING, required = true,
+ description = "Name for the uploaded certificate")
+ private String name;
+
+ @Parameter(name = ApiConstants.HYPERVISOR, type = BaseCmd.CommandType.STRING, required = true, description = "Hypervisor type")
+ private String hypervisor;
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ if (!hypervisor.equalsIgnoreCase("kvm")) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Currently supporting KVM hosts only");
+ }
+
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ try {
+ LOG.debug("Uploading certificate " + name + " to agents for Direct Download");
+ boolean result = directDownloadManager.uploadCertificateToHosts(certificate, name, hypervisor);
+ response.setSuccess(result);
+ setResponseObject(response);
+ } catch (Exception e) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+ }
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccount().getId();
+ }
+}
+
+
diff --git a/api/src/org/apache/cloudstack/api/command/admin/domain/CreateDomainCmd.java b/api/src/org/apache/cloudstack/api/command/admin/domain/CreateDomainCmd.java
index 312c9ee4b095..fe1c20206b67 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/domain/CreateDomainCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/domain/CreateDomainCmd.java
@@ -17,7 +17,7 @@
package org.apache.cloudstack.api.command.admin.domain;
import org.apache.log4j.Logger;
-
+import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
@@ -31,7 +31,8 @@
import com.cloud.user.Account;
@APICommand(name = "createDomain", description = "Creates a domain", responseObject = DomainResponse.class,
- requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {
+ RoleType.Admin, RoleType.DomainAdmin })
public class CreateDomainCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(CreateDomainCmd.class.getName());
@@ -45,9 +46,9 @@ public class CreateDomainCmd extends BaseCmd {
private String domainName;
@Parameter(name = ApiConstants.PARENT_DOMAIN_ID,
- type = CommandType.UUID,
- entityType = DomainResponse.class,
- description = "assigns new domain a parent domain by domain ID of the parent. If no parent domain is specied, the ROOT domain is assumed.")
+ type = CommandType.UUID,
+ entityType = DomainResponse.class,
+ description = "assigns new domain a parent domain by domain ID of the parent. If no parent domain is specied, the ROOT domain is assumed.")
private Long parentDomainId;
@Parameter(name = ApiConstants.NETWORK_DOMAIN, type = CommandType.STRING, description = "Network domain for networks in the domain")
diff --git a/api/src/org/apache/cloudstack/api/command/admin/domain/DeleteDomainCmd.java b/api/src/org/apache/cloudstack/api/command/admin/domain/DeleteDomainCmd.java
index a6d2b0b10c19..037cf3d9ab4b 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/domain/DeleteDomainCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/domain/DeleteDomainCmd.java
@@ -18,8 +18,7 @@
import javax.inject.Inject;
-import org.apache.log4j.Logger;
-
+import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
@@ -30,13 +29,15 @@
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.region.RegionService;
+import org.apache.log4j.Logger;
import com.cloud.domain.Domain;
import com.cloud.event.EventTypes;
import com.cloud.user.Account;
@APICommand(name = "deleteDomain", description = "Deletes a specified domain", responseObject = SuccessResponse.class,
- requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {
+ RoleType.Admin, RoleType.DomainAdmin })
public class DeleteDomainCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(DeleteDomainCmd.class.getName());
private static final String s_name = "deletedomainresponse";
@@ -49,8 +50,8 @@ public class DeleteDomainCmd extends BaseAsyncCmd {
private Long id;
@Parameter(name = ApiConstants.CLEANUP,
- type = CommandType.BOOLEAN,
- description = "true if all domain resources (child domains, accounts) have to be cleaned up, false otherwise")
+ type = CommandType.BOOLEAN,
+ description = "true if all domain resources (child domains, accounts) have to be cleaned up, false otherwise")
private Boolean cleanup;
@Inject
diff --git a/api/src/org/apache/cloudstack/api/command/admin/domain/ListDomainsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/domain/ListDomainsCmd.java
index e382ed9b41c6..9c1ae2213285 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/domain/ListDomainsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/domain/ListDomainsCmd.java
@@ -16,10 +16,15 @@
// under the License.
package org.apache.cloudstack.api.command.admin.domain;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiConstants.DomainDetails;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject.ResponseView;
@@ -27,6 +32,7 @@
import org.apache.cloudstack.api.response.ListResponse;
import com.cloud.domain.Domain;
+import com.cloud.exception.InvalidParameterValueException;
@APICommand(name = "listDomains", description = "Lists domains and provides detailed information for listed domains", responseObject = DomainResponse.class, responseView = ResponseView.Restricted, entityType = {Domain.class},
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -53,6 +59,12 @@ public class ListDomainsCmd extends BaseListCmd {
description = "If set to false, list only resources belonging to the command's caller; if set to true - list resources that the caller is authorized to see. Default value is false")
private Boolean listAll;
+ @Parameter(name = ApiConstants.DETAILS,
+ type = CommandType.LIST,
+ collectionType = CommandType.STRING,
+ description = "comma separated list of domain details requested, value can be a list of [ all, resource, min]")
+ private List viewDetails;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -73,6 +85,25 @@ public boolean listAll() {
return listAll == null ? false : listAll;
}
+ public EnumSet getDetails() throws InvalidParameterValueException {
+ EnumSet dv;
+ if (viewDetails == null || viewDetails.size() <= 0) {
+ dv = EnumSet.of(DomainDetails.all);
+ } else {
+ try {
+ ArrayList dc = new ArrayList();
+ for (String detail : viewDetails) {
+ dc.add(DomainDetails.valueOf(detail));
+ }
+ dv = EnumSet.copyOf(dc);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidParameterValueException("The details parameter contains a non permitted value. The allowed values are " +
+ EnumSet.allOf(DomainDetails.class));
+ }
+ }
+ return dv;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/command/admin/guest/AddGuestOsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/guest/AddGuestOsCmd.java
index 3ba9669b305a..717bcfe81550 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/guest/AddGuestOsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/guest/AddGuestOsCmd.java
@@ -33,6 +33,11 @@
import com.cloud.storage.GuestOS;
import com.cloud.user.Account;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
@APICommand(name = "addGuestOs", description = "Add a new guest OS type", responseObject = GuestOSResponse.class,
since = "4.4.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class AddGuestOsCmd extends BaseAsyncCreateCmd {
@@ -53,8 +58,11 @@ public class AddGuestOsCmd extends BaseAsyncCreateCmd {
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = false, description = "Optional name for Guest OS")
private String osName;
+ @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required = true, description = "Map of (key/value pairs)")
+ private Map details;
+
-/////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -70,6 +78,22 @@ public String getOsName() {
return osName;
}
+ public Map getDetails() {
+ Map detailsMap = new HashMap();
+ if (!details.isEmpty()) {
+ Collection> servicesCollection = details.values();
+ Iterator> iter = servicesCollection.iterator();
+ while (iter.hasNext()) {
+ HashMap services = (HashMap)iter.next();
+ String key = services.get("key");
+ String value = services.get("value");
+ detailsMap.put(key, value);
+ }
+ }
+ return detailsMap;
+ }
+
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsCmd.java
index e4b1ecd57196..ff3b49d79be6 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsCmd.java
@@ -31,6 +31,11 @@
import com.cloud.storage.GuestOS;
import com.cloud.user.Account;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
@APICommand(name = "updateGuestOs", description = "Updates the information about Guest OS", responseObject = GuestOSResponse.class,
since = "4.4.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class UpdateGuestOsCmd extends BaseAsyncCmd {
@@ -49,6 +54,10 @@ public class UpdateGuestOsCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.OS_DISPLAY_NAME, type = CommandType.STRING, required = true, description = "Unique display name for Guest OS")
private String osDisplayName;
+ @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required = true, description = "Map of (key/value pairs)")
+ private Map details;
+
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -61,6 +70,21 @@ public String getOsDisplayName() {
return osDisplayName;
}
+ public Map getDetails() {
+ Map detailsMap = new HashMap();;
+ if (!details.isEmpty()) {
+ Collection> servicesCollection = details.values();
+ Iterator> iter = servicesCollection.iterator();
+ while (iter.hasNext()) {
+ HashMap services = (HashMap)iter.next();
+ String key = services.get("key");
+ String value = services.get("value");
+ detailsMap.put(key, value);
+ }
+ }
+ return detailsMap;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java
new file mode 100644
index 000000000000..f85dbb235045
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java
@@ -0,0 +1,127 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ha;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.HostHAResponse;
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.ha.HAConfigManager;
+import org.apache.cloudstack.ha.HAResource;
+
+import javax.inject.Inject;
+
+@APICommand(name = ConfigureHAForHostCmd.APINAME, description = "Configures HA for a host",
+ responseObject = HostHAResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ since = "4.11", authorized = {RoleType.Admin})
+public final class ConfigureHAForHostCmd extends BaseAsyncCmd {
+ public static final String APINAME = "configureHAForHost";
+
+ @Inject
+ private HAConfigManager haConfigManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
+ description = "ID of the host", required = true, validations = {ApiArgValidator.PositiveNumber})
+ private Long hostId;
+
+ @Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING,
+ description = "HA provider", required = true, validations = {ApiArgValidator.NotNullOrEmpty})
+ private String haProvider;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getHostId() {
+ return hostId;
+ }
+
+ public String getHaProvider() {
+ return haProvider;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ private void setupResponse(final boolean result, final String resourceUuid) {
+ final HostHAResponse response = new HostHAResponse();
+ response.setId(resourceUuid);
+ response.setProvider(getHaProvider().toLowerCase());
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ final Host host = _resourceService.getHost(getHostId());
+ if (host == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId());
+ }
+
+ final boolean result = haConfigManager.configureHA(host.getId(), HAResource.ResourceType.Host, getHaProvider());
+ if (!result) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to configure HA provider for the host");
+ }
+ CallContext.current().setEventDetails("Host Id:" + host.getId() + " HA configured with provider: " + getHaProvider());
+ CallContext.current().putContextParameter(Host.class, host.getUuid());
+
+ setupResponse(result, host.getUuid());
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_HA_RESOURCE_DISABLE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "configure HA for host: " + getHostId();
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ha/DisableHAForClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ha/DisableHAForClusterCmd.java
new file mode 100644
index 000000000000..053c978b831d
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ha/DisableHAForClusterCmd.java
@@ -0,0 +1,114 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ha;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.org.Cluster;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ClusterResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.ha.HAConfigManager;
+
+import javax.inject.Inject;
+
+@APICommand(name = DisableHAForClusterCmd.APINAME, description = "Disables HA cluster-wide",
+ responseObject = SuccessResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ since = "4.11", authorized = {RoleType.Admin})
+public final class DisableHAForClusterCmd extends BaseAsyncCmd {
+ public static final String APINAME = "disableHAForCluster";
+
+ @Inject
+ private HAConfigManager haConfigManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.CLUSTER_ID, type = BaseCmd.CommandType.UUID, entityType = ClusterResponse.class,
+ description = "ID of the cluster", required = true, validations = {ApiArgValidator.PositiveNumber})
+ private Long clusterId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getClusterId() {
+ return clusterId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccountId();
+ }
+
+ private void setupResponse(final boolean result) {
+ final SuccessResponse response = new SuccessResponse();
+ response.setSuccess(result);
+ response.setResponseName(getCommandName());
+ response.setObjectName("ha");
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ final Cluster cluster = _resourceService.getCluster(getClusterId());
+ if (cluster == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find cluster by ID: " + getClusterId());
+ }
+ final boolean result = haConfigManager.disableHA(cluster);
+ CallContext.current().setEventDetails("Cluster Id:" + cluster.getId() + " HA enabled: false");
+ CallContext.current().putContextParameter(Cluster.class, cluster.getUuid());
+
+ setupResponse(result);
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_HA_RESOURCE_DISABLE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "disable HA for cluster: " + getClusterId();
+ }
+
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ha/DisableHAForHostCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ha/DisableHAForHostCmd.java
new file mode 100644
index 000000000000..87ebe878cebe
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ha/DisableHAForHostCmd.java
@@ -0,0 +1,116 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ha;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.HostHAResponse;
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.ha.HAConfigManager;
+import org.apache.cloudstack.ha.HAResource;
+
+import javax.inject.Inject;
+
+@APICommand(name = DisableHAForHostCmd.APINAME, description = "Disables HA for a host",
+ responseObject = HostHAResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ since = "4.11", authorized = {RoleType.Admin})
+public final class DisableHAForHostCmd extends BaseAsyncCmd {
+ public static final String APINAME = "disableHAForHost";
+
+ @Inject
+ private HAConfigManager haConfigManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
+ description = "ID of the host", required = true, validations = {ApiArgValidator.PositiveNumber})
+ private Long hostId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getHostId() {
+ return hostId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccountId();
+ }
+
+ private void setupResponse(final boolean result, final String resourceUuid) {
+ final HostHAResponse response = new HostHAResponse();
+ response.setId(resourceUuid);
+ response.setEnabled(false);
+ response.setStatus(result);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ final Host host = _resourceService.getHost(getHostId());
+ if (host == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId());
+ }
+
+ final boolean result = haConfigManager.disableHA(host.getId(), HAResource.ResourceType.Host);
+ CallContext.current().setEventDetails("Host Id:" + host.getId() + " HA enabled: false");
+ CallContext.current().putContextParameter(Host.class, host.getUuid());
+
+ setupResponse(result, host.getUuid());
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_HA_RESOURCE_DISABLE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "disable HA for host: " + getHostId();
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ha/DisableHAForZoneCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ha/DisableHAForZoneCmd.java
new file mode 100644
index 000000000000..845c4a663b5a
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ha/DisableHAForZoneCmd.java
@@ -0,0 +1,115 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ha;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.ha.HAConfigManager;
+
+import javax.inject.Inject;
+
+@APICommand(name = DisableHAForZoneCmd.APINAME, description = "Disables HA for a zone",
+ responseObject = SuccessResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ since = "4.11", authorized = {RoleType.Admin})
+public final class DisableHAForZoneCmd extends BaseAsyncCmd {
+ public static final String APINAME = "disableHAForZone";
+
+ @Inject
+ private HAConfigManager haConfigManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
+ description = "ID of the zone", required = true, validations = {ApiArgValidator.PositiveNumber})
+ private Long zoneId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getZoneId() {
+ return zoneId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccountId();
+ }
+
+ private void setupResponse(final boolean result) {
+ final SuccessResponse response = new SuccessResponse();
+ response.setSuccess(result);
+ response.setResponseName(getCommandName());
+ response.setObjectName("ha");
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ final DataCenter dataCenter = _resourceService.getZone(getZoneId());
+ if (dataCenter == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find zone by ID: " + getZoneId());
+ }
+
+ final boolean result = haConfigManager.disableHA(dataCenter);
+ CallContext.current().setEventDetails("Zone Id:" + dataCenter.getId() + " HA enabled: false");
+ CallContext.current().putContextParameter(DataCenter.class, dataCenter.getUuid());
+
+ setupResponse(result);
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_HA_RESOURCE_DISABLE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "disable HA for zone: " + getZoneId();
+ }
+
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ha/EnableHAForClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ha/EnableHAForClusterCmd.java
new file mode 100644
index 000000000000..e06d0d2c1b07
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ha/EnableHAForClusterCmd.java
@@ -0,0 +1,114 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ha;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.org.Cluster;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ClusterResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.ha.HAConfigManager;
+
+import javax.inject.Inject;
+
+@APICommand(name = EnableHAForClusterCmd.APINAME, description = "Enables HA cluster-wide",
+ responseObject = SuccessResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ since = "4.11", authorized = {RoleType.Admin})
+public final class EnableHAForClusterCmd extends BaseAsyncCmd {
+ public static final String APINAME = "enableHAForCluster";
+
+ @Inject
+ private HAConfigManager haConfigManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.CLUSTER_ID, type = BaseCmd.CommandType.UUID, entityType = ClusterResponse.class,
+ description = "ID of the cluster", required = true, validations = {ApiArgValidator.PositiveNumber})
+ private Long clusterId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getClusterId() {
+ return clusterId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccountId();
+ }
+
+ private void setupResponse(final boolean result) {
+ final SuccessResponse response = new SuccessResponse();
+ response.setSuccess(result);
+ response.setResponseName(getCommandName());
+ response.setObjectName("ha");
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ final Cluster cluster = _resourceService.getCluster(getClusterId());
+ if (cluster == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find cluster by ID: " + getClusterId());
+ }
+
+ final boolean result = haConfigManager.enableHA(cluster);
+ CallContext.current().setEventDetails("Cluster Id:" + cluster.getId() + " HA enabled: true");
+ CallContext.current().putContextParameter(Cluster.class, cluster.getUuid());
+
+ setupResponse(result);
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_HA_RESOURCE_ENABLE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "enable HA for cluster: " + getClusterId();
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ha/EnableHAForHostCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ha/EnableHAForHostCmd.java
new file mode 100644
index 000000000000..b23841ad56f4
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ha/EnableHAForHostCmd.java
@@ -0,0 +1,116 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ha;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.HostHAResponse;
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.ha.HAConfigManager;
+import org.apache.cloudstack.ha.HAResource;
+
+import javax.inject.Inject;
+
+@APICommand(name = EnableHAForHostCmd.APINAME, description = "Enables HA for a host",
+ responseObject = HostHAResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ since = "4.11", authorized = {RoleType.Admin})
+public final class EnableHAForHostCmd extends BaseAsyncCmd {
+ public static final String APINAME = "enableHAForHost";
+
+ @Inject
+ private HAConfigManager haConfigManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
+ description = "ID of the host", required = true, validations = {ApiArgValidator.PositiveNumber})
+ private Long hostId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getHostId() {
+ return hostId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccountId();
+ }
+
+ private void setupResponse(final boolean result, final String resourceUuid) {
+ final HostHAResponse response = new HostHAResponse();
+ response.setId(resourceUuid);
+ response.setEnabled(true);
+ response.setStatus(result);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ final Host host = _resourceService.getHost(getHostId());
+ if (host == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId());
+ }
+ final boolean result = haConfigManager.enableHA(host.getId(), HAResource.ResourceType.Host);
+
+ CallContext.current().setEventDetails("Host Id:" + host.getId() + " HA enabled: true");
+ CallContext.current().putContextParameter(Host.class, host.getUuid());
+
+ setupResponse(result, host.getUuid());
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_HA_RESOURCE_ENABLE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "enable HA for host: " + getHostId();
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ha/EnableHAForZoneCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ha/EnableHAForZoneCmd.java
new file mode 100644
index 000000000000..443d303c2961
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ha/EnableHAForZoneCmd.java
@@ -0,0 +1,115 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ha;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.ha.HAConfigManager;
+
+import javax.inject.Inject;
+
+@APICommand(name = EnableHAForZoneCmd.APINAME, description = "Enables HA for a zone",
+ responseObject = SuccessResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ since = "4.11", authorized = {RoleType.Admin})
+public final class EnableHAForZoneCmd extends BaseAsyncCmd {
+ public static final String APINAME = "enableHAForZone";
+
+ @Inject
+ private HAConfigManager haConfigManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
+ description = "ID of the zone", required = true, validations = {ApiArgValidator.PositiveNumber})
+ private Long zoneId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getZoneId() {
+ return zoneId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccountId();
+ }
+
+ private void setupResponse(final boolean result) {
+ final SuccessResponse response = new SuccessResponse();
+ response.setSuccess(result);
+ response.setResponseName(getCommandName());
+ response.setObjectName("ha");
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ final DataCenter dataCenter = _resourceService.getZone(getZoneId());
+ if (dataCenter == null) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find zone by ID: " + getZoneId());
+ }
+
+ final boolean result = haConfigManager.enableHA(dataCenter);
+ CallContext.current().setEventDetails("Zone Id:" + dataCenter.getId() + " HA enabled: true");
+ CallContext.current().putContextParameter(DataCenter.class, dataCenter.getUuid());
+
+ setupResponse(result);
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_HA_RESOURCE_ENABLE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "enable HA for zone: " + getZoneId();
+ }
+
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ha/ListHostHAProvidersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ha/ListHostHAProvidersCmd.java
new file mode 100644
index 000000000000..64b9a6a8e5cd
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ha/ListHostHAProvidersCmd.java
@@ -0,0 +1,106 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ha;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+import com.google.common.base.Enums;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.HAProviderResponse;
+import org.apache.cloudstack.api.response.HostHAResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.ha.HAConfigManager;
+import org.apache.cloudstack.ha.HAResource;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@APICommand(name = ListHostHAProvidersCmd.APINAME, description = "Lists HA providers", responseObject = HostHAResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ since = "4.11", authorized = {RoleType.Admin})
+public final class ListHostHAProvidersCmd extends BaseCmd {
+ public static final String APINAME = "listHostHAProviders";
+
+ @Inject
+ private HAConfigManager haConfigManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, required = true,
+ description = "Hypervisor type of the resource", validations = {ApiArgValidator.NotNullOrEmpty})
+ private String hypervisorType;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public HAResource.ResourceSubType getHypervisorType() {
+ return HAResource.ResourceSubType.valueOf(hypervisorType);
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ private void setupResponse(final List hostHAProviderList) {
+ final ListResponse response = new ListResponse<>();
+ final List hostHAResponses = new ArrayList<>();
+ for (final String provider : hostHAProviderList) {
+ final HAProviderResponse haProviderResponse = new HAProviderResponse();
+ haProviderResponse.setProvider(provider);
+ hostHAResponses.add(haProviderResponse);
+ }
+ response.setResponses(hostHAResponses);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ if (!Enums.getIfPresent(HAResource.ResourceSubType.class, hypervisorType).isPresent()) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid or unsupported host hypervisor type provided. Supported types are: " + Arrays.toString(HAResource.ResourceSubType.values()));
+ }
+ final List hostHAProviders = haConfigManager.listHAProviders(HAResource.ResourceType.Host, getHypervisorType());
+ setupResponse(hostHAProviders);
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ha/ListHostHAResourcesCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ha/ListHostHAResourcesCmd.java
new file mode 100644
index 000000000000..75a900c2198d
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/ha/ListHostHAResourcesCmd.java
@@ -0,0 +1,109 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.ha;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.HostHAResponse;
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.ha.HAConfig;
+import org.apache.cloudstack.ha.HAConfigManager;
+import org.apache.cloudstack.ha.HAResource;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
+
+@APICommand(name = ListHostHAResourcesCmd.APINAME, description = "Lists host HA resources", responseObject = HostHAResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ since = "4.11", authorized = {RoleType.Admin})
+public final class ListHostHAResourcesCmd extends BaseCmd {
+ public static final String APINAME = "listHostHAResources";
+
+ @Inject
+ private HAConfigManager haConfigManager;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
+ description = "List by host ID", validations = {ApiArgValidator.PositiveNumber})
+ private Long hostId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getHostId() {
+ return hostId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ private void setupResponse(final List hostHAConfigList) {
+ final ListResponse response = new ListResponse<>();
+ final List hostHAResponses = new ArrayList<>();
+ for (final HAConfig config : hostHAConfigList) {
+ final Host host = _resourceService.getHost(config.getResourceId());
+ if (host == null) {
+ continue;
+ }
+ final HostHAResponse hostHAResponse = new HostHAResponse();
+ hostHAResponse.setId(host.getUuid());
+ hostHAResponse.setEnabled(config.isEnabled());
+ hostHAResponse.setHaState(config.getState());
+ hostHAResponse.setProvider(config.getHaProvider());
+ hostHAResponses.add(hostHAResponse);
+ }
+ response.setResponses(hostHAResponses);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ final List hostHAConfig = haConfigManager.listHAResources(getHostId(), HAResource.ResourceType.Host);
+ setupResponse(hostHAConfig);
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/FindHostsForMigrationCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/FindHostsForMigrationCmd.java
index dbb94384523e..ad9b6af34364 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/host/FindHostsForMigrationCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/host/FindHostsForMigrationCmd.java
@@ -76,7 +76,7 @@ public void execute() {
Map hostsRequiringStorageMotion;
Ternary, Integer>, List extends Host>, Map> hostsForMigration =
- _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
+ _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal(), this.getKeyword());
result = hostsForMigration.first();
List extends Host> hostsWithCapacity = hostsForMigration.second();
hostsRequiringStorageMotion = hostsForMigration.third();
diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
index 3391fdca1e34..9a5d3115b597 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
@@ -209,7 +209,7 @@ protected ListResponse getHostResponses() {
} else {
Pair, Integer> result;
Ternary, Integer>, List extends Host>, Map> hostsForMigration =
- _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
+ _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal(), null);
result = hostsForMigration.first();
List extends Host> hostsWithCapacity = hostsForMigration.second();
List hostResponses = new ArrayList();
diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
index c6f6530dc503..aa0a690e2a98 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
@@ -16,10 +16,10 @@
// under the License.
package org.apache.cloudstack.api.command.admin.host;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
+import com.cloud.host.Host;
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
@@ -28,9 +28,9 @@
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.log4j.Logger;
-import com.cloud.host.Host;
-import com.cloud.user.Account;
+import java.util.List;
@APICommand(name = "updateHost", description = "Updates a host.", responseObject = HostResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -62,6 +62,9 @@ public class UpdateHostCmd extends BaseCmd {
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the new uri for the secondary storage: nfs://host/path")
private String url;
+ @Parameter(name = ApiConstants.ANNOTATION, type = CommandType.STRING, description = "Add an annotation to this host", since = "4.11", authorized = {RoleType.Admin})
+ private String annotation;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -86,6 +89,10 @@ public String getUrl() {
return url;
}
+ public String getAnnotation() {
+ return annotation;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@@ -109,6 +116,9 @@ public void execute() {
Host result;
try {
result = _resourceService.updateHost(this);
+ if(getAnnotation() != null) {
+ annotationService.addAnnotation(getAnnotation(), AnnotationService.EntityType.HOST, result.getUuid());
+ }
HostResponse hostResponse = _responseGenerator.createHostResponse(result);
hostResponse.setResponseName(getCommandName());
this.setResponseObject(hostResponse);
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java
new file mode 100644
index 000000000000..f7957469cd13
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.network;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.PodResponse;
+
+import com.cloud.dc.Pod;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+
+@APICommand(name = CreateManagementNetworkIpRangeCmd.APINAME,
+ description = "Creates a Management network IP range.",
+ responseObject = PodResponse.class,
+ since = "4.11.0.0",
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false,
+ authorized = {RoleType.Admin})
+public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd {
+ public static final Logger s_logger = Logger.getLogger(CreateManagementNetworkIpRangeCmd.class);
+
+ public static final String APINAME = "createManagementNetworkIpRange";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+ @Parameter(name = ApiConstants.POD_ID,
+ type = CommandType.UUID,
+ entityType = PodResponse.class,
+ required = true,
+ description = "UUID of POD, where the IP range belongs to.",
+ validations = {ApiArgValidator.PositiveNumber})
+ private Long podId;
+
+ @Parameter(name = ApiConstants.GATEWAY,
+ type = CommandType.STRING,
+ required = true,
+ description = "The gateway for the management network.",
+ validations = {ApiArgValidator.NotNullOrEmpty})
+ private String gateway;
+
+ @Parameter(name = ApiConstants.NETMASK,
+ type = CommandType.STRING,
+ required = true,
+ description = "The netmask for the management network.",
+ validations = {ApiArgValidator.NotNullOrEmpty})
+ private String netmask;
+
+ @Parameter(name = ApiConstants.START_IP,
+ type = CommandType.STRING,
+ required = true,
+ description = "The starting IP address.",
+ validations = {ApiArgValidator.NotNullOrEmpty})
+ private String startIp;
+
+ @Parameter(name = ApiConstants.END_IP,
+ type = CommandType.STRING,
+ description = "The ending IP address.")
+ private String endIp;
+
+ @Parameter(name = ApiConstants.FOR_SYSTEM_VMS,
+ type = CommandType.BOOLEAN,
+ description = "Specify if range is dedicated for CPVM and SSVM.")
+ private Boolean forSystemVms;
+
+ @Parameter(name = ApiConstants.VLAN,
+ type = CommandType.STRING,
+ description = "Optional. The vlan id the ip range sits on, default to Null when it is not specificed which means you network is not on any Vlan")
+ private String vlan;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getPodId() {
+ return podId;
+ }
+
+ public String getGateWay() {
+ return gateway;
+ }
+
+ public String getNetmask() {
+ return netmask;
+ }
+
+ public String getStartIp() {
+ return startIp;
+ }
+
+ public String getEndIp() {
+ return endIp;
+ }
+
+ public Boolean isForSystemVms() {
+ return forSystemVms == null ? Boolean.FALSE : forSystemVms;
+ }
+
+ public String getVlan() {
+ if (vlan == null || vlan.isEmpty()) {
+ vlan = "untagged";
+ }
+ return vlan;
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_MANAGEMENT_IP_RANGE_CREATE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "Creating management ip range from " + getStartIp() + " to " + getEndIp() + " and gateway=" + getGateWay() + ", netmask=" + getNetmask() + " of pod=" + getPodId();
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
+ ResourceAllocationException {
+ Pod result = _configService.createPodIpRange(this);
+ if (result != null) {
+ PodResponse response = _responseGenerator.createPodResponse(result, false);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Pod IP Range.");
+ }
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkCmdByAdmin.java b/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkCmdByAdmin.java
index 6cf9e2308dcd..6d346e9a4dbe 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkCmdByAdmin.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkCmdByAdmin.java
@@ -40,6 +40,9 @@ public class CreateNetworkCmdByAdmin extends CreateNetworkCmd {
@Parameter(name=ApiConstants.VLAN, type=CommandType.STRING, description="the ID or VID of the network")
private String vlan;
+ @Parameter(name=ApiConstants.BYPASS_VLAN_OVERLAP_CHECK, type=CommandType.BOOLEAN, description="when true bypasses VLAN id/range overlap check during network creation for shared networks")
+ private Boolean bypassVlanOverlapCheck;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -48,6 +51,13 @@ public String getVlan() {
return vlan;
}
+ public Boolean getBypassVlanOverlapCheck() {
+ if (bypassVlanOverlapCheck != null) {
+ return bypassVlanOverlapCheck;
+ }
+ return false;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java
index a09c9797b68a..7c8c46a9c9e0 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java
@@ -112,8 +112,14 @@ public class CreateNetworkOfferingCmd extends BaseCmd {
description = "true if network offering supports persistent networks; defaulted to false if not specified")
private Boolean isPersistent;
+ @Parameter(name = ApiConstants.FOR_VPC,
+ type = CommandType.BOOLEAN,
+ description = "true if network offering is meant to be used for VPC, false otherwise.")
+ private Boolean forVpc;
+
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, since = "4.2.0", description = "Network offering details in key/value pairs."
- + " Supported keys are internallbprovider/publiclbprovider with service provider as a value")
+ + " Supported keys are internallbprovider/publiclbprovider with service provider as a value, and"
+ + " promiscuousmode/macaddresschanges/forgedtransmits with true/false as value to accept/reject the security settings if available for a nic/portgroup")
protected Map details;
@Parameter(name = ApiConstants.EGRESS_DEFAULT_POLICY,
@@ -195,6 +201,10 @@ public Boolean getIsPersistent() {
return isPersistent == null ? false : isPersistent;
}
+ public Boolean getForVpc() {
+ return forVpc;
+ }
+
public Boolean getEgressDefaultPolicy() {
if (egressDefaultPolicy == null) {
return true;
@@ -273,10 +283,23 @@ public Map getDetails() {
}
Collection paramsCollection = details.values();
- Map params = (Map)(paramsCollection.toArray())[0];
+ Object objlist[]= paramsCollection.toArray();
+ Map params = (Map)(objlist[0]);
+ for(int i=1; i< objlist.length; i++)
+ {
+ params.putAll((Map)(objlist[i]));
+ }
+
return params;
}
+ public String getServicePackageId() {
+ Map data = getDetails();
+ if (data == null)
+ return null;
+ return data.get(NetworkOffering.Detail.servicepackageuuid+ "");
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java
new file mode 100644
index 000000000000..d6481846f431
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java
@@ -0,0 +1,139 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.network;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.PodResponse;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+
+@APICommand(name = DeleteManagementNetworkIpRangeCmd.APINAME,
+ description = "Deletes a management network IP range. This action is only allowed when no IPs in this range are allocated.",
+ responseObject = SuccessResponse.class,
+ since = "4.11.0.0",
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false,
+ authorized = {RoleType.Admin})
+public class DeleteManagementNetworkIpRangeCmd extends BaseAsyncCmd {
+ public static final Logger s_logger = Logger.getLogger(DeleteManagementNetworkIpRangeCmd.class);
+
+ public static final String APINAME = "deleteManagementNetworkIpRange";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.POD_ID,
+ type = CommandType.UUID,
+ entityType = PodResponse.class,
+ required = true,
+ description = "UUID of POD, where the IP range belongs to.",
+ validations = ApiArgValidator.PositiveNumber)
+ private Long podId;
+
+ @Parameter(name = ApiConstants.START_IP,
+ type = CommandType.STRING,
+ required = true,
+ description = "The starting IP address.",
+ validations = ApiArgValidator.NotNullOrEmpty)
+ private String startIp;
+
+ @Parameter(name = ApiConstants.END_IP,
+ type = CommandType.STRING,
+ required = true,
+ description = "The ending IP address.",
+ validations = ApiArgValidator.NotNullOrEmpty)
+ private String endIp;
+
+ @Parameter(name = ApiConstants.VLAN,
+ type = CommandType.STRING,
+ required = true,
+ description = "The vlan id the ip range sits on")
+ private String vlan;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getPodId() {
+ return podId;
+ }
+
+ public String getStartIp() {
+ return startIp;
+ }
+
+ public String getEndIp() {
+ return endIp;
+ }
+
+ public String getVlan() {
+ return vlan;
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_MANAGEMENT_IP_RANGE_DELETE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "Deleting management ip range from " + getStartIp() + " to " + getEndIp() + " of Pod: " + getPodId();
+ }
+
+ @Override
+ public void execute() {
+ try {
+ _configService.deletePodIpRange(this);
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ this.setResponseObject(response);
+ } catch (ResourceUnavailableException ex) {
+ s_logger.warn("Exception: ", ex);
+ throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
+ } catch (ConcurrentOperationException ex) {
+ s_logger.warn("Exception: ", ex);
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
+ } catch (Exception e) {
+ s_logger.warn("Failed to delete management ip range from " + getStartIp() + " to " + getEndIp() + " of Pod: " + getPodId(), e);
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+ }
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+}
\ No newline at end of file
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java
new file mode 100644
index 000000000000..298d9b043e8f
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java
@@ -0,0 +1,163 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.network;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.NetworkOfferingResponse;
+import org.apache.cloudstack.api.response.NetworkResponse;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.network.Network;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.user.Account;
+import com.cloud.user.User;
+
+@APICommand(name = MigrateNetworkCmd.APINAME, description = "moves a network to another physical network",
+ responseObject = NetworkResponse.class,
+ responseView = ResponseView.Restricted,
+ entityType = {Network.class},
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false,
+ since = "4.11.0",
+ authorized = {RoleType.Admin})
+public class MigrateNetworkCmd extends BaseAsyncCmd {
+ public static final Logger s_logger = Logger.getLogger(MigrateNetworkCmd.class.getName());
+
+ public static final String APINAME = "migrateNetwork";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+ @ACL(accessType = AccessType.OperateEntry)
+ @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class,
+ required=true, description="the ID of the network")
+ protected Long id;
+
+ @Parameter(name = ApiConstants.NETWORK_OFFERING_ID, type = CommandType.UUID, entityType = NetworkOfferingResponse.class, description = "network offering ID")
+ private Long networkOfferingId;
+
+ @Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed")
+ private Boolean resume;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ public Long getNetworkOfferingId() {
+ return networkOfferingId;
+ }
+
+ public Boolean getResume() {
+ return resume != null ? resume : false;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ Network network = _networkService.getNetwork(id);
+ if (network == null) {
+ throw new InvalidParameterValueException("Networkd id=" + id + " doesn't exist");
+ } else {
+ return _networkService.getNetwork(id).getAccountId();
+ }
+ }
+
+ @Override
+ public void execute() {
+ User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId());
+ Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId());
+ Network network = _networkService.getNetwork(id);
+ if (network == null) {
+ throw new InvalidParameterValueException("Couldn't find network by id");
+ }
+
+ Network result =
+ _networkService.migrateGuestNetwork(getId(), getNetworkOfferingId(), callerAccount, callerUser, getResume());
+
+ if (result != null) {
+ NetworkResponse response = _responseGenerator.createNetworkResponse(ResponseView.Restricted, result);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update network");
+ }
+ }
+
+ @Override
+ public String getEventDescription() {
+ StringBuilder eventMsg = new StringBuilder("Migrating network: " + getId());
+ if (getNetworkOfferingId() != null) {
+ Network network = _networkService.getNetwork(getId());
+ if (network == null) {
+ throw new InvalidParameterValueException("Network id=" + id + " doesn't exist");
+ }
+ if (network.getNetworkOfferingId() != getNetworkOfferingId()) {
+ NetworkOffering oldOff = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId());
+ NetworkOffering newOff = _entityMgr.findById(NetworkOffering.class, getNetworkOfferingId());
+ if (newOff == null) {
+ throw new InvalidParameterValueException("Network offering id supplied is invalid");
+ }
+
+ eventMsg.append(". Original network offering id: " + oldOff.getUuid() + ", new network offering id: " + newOff.getUuid());
+ }
+ }
+
+ return eventMsg.toString();
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_NETWORK_MIGRATE;
+ }
+
+ @Override
+ public String getSyncObjType() {
+ return BaseAsyncCmd.networkSyncObject;
+ }
+
+ @Override
+ public Long getSyncObjId() {
+ return id;
+ }
+
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java
new file mode 100644
index 000000000000..a5611c67aa4c
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java
@@ -0,0 +1,154 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.network;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ResponseObject;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.VpcOfferingResponse;
+import org.apache.cloudstack.api.response.VpcResponse;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.event.EventTypes;
+import com.cloud.network.vpc.Vpc;
+import com.cloud.user.Account;
+import com.cloud.user.User;
+
+@APICommand(name = MigrateVPCCmd.APINAME,
+ description = "moves a vpc to another physical network",
+ responseObject = VpcResponse.class,
+ responseView = ResponseObject.ResponseView.Restricted,
+ entityType = {Vpc.class},
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false,
+ since = "4.11.0",
+ authorized = {RoleType.Admin})
+public class MigrateVPCCmd extends BaseAsyncCmd {
+ public static final Logger s_logger = Logger.getLogger(MigrateVPCCmd.class.getName());
+
+ public static final String APINAME = "migrateVPC";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+ @ACL(accessType = SecurityChecker.AccessType.OperateEntry)
+ @Parameter(name= ApiConstants.VPC_ID, type=CommandType.UUID, entityType = VpcResponse.class,
+ required=true, description = "the ID of the vpc")
+ protected Long id;
+
+ @Parameter(name = ApiConstants.VPC_OFF_ID, type = CommandType.UUID, entityType = VpcOfferingResponse.class, required=true, description = "vpc offering ID")
+ private Long vpcOfferingId;
+
+ @Parameter(name = ApiConstants.TIER_NETWORK_OFFERINGS, type = CommandType.MAP, description = "network offering ids for each network in the vpc. Example: tierNetworkOfferings[0].networkId=networkId1&tierNetworkOfferings[0].networkOfferingId=newNetworkofferingId1&tierNetworkOfferings[1].networkId=networkId2&tierNetworkOfferings[1].networkOfferingId=newNetworkofferingId2")
+ private Map> tierNetworkOfferings;
+
+ @Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed")
+ private Boolean resume;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ public Long getVpcOfferingId() {
+ return vpcOfferingId;
+ }
+
+ public Boolean getResume() {
+ return resume == null ? false : resume;
+ }
+
+ public Map getTierNetworkOfferings() {
+ HashMap flatMap = new HashMap<>();
+
+ if (tierNetworkOfferings == null) {
+ return flatMap;
+ }
+
+ for (HashMap map : tierNetworkOfferings.values()) {
+ flatMap.put(map.get("networkid"), map.get("networkofferingid"));
+ }
+
+ return flatMap;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public void execute() {
+ User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId());
+ Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId());
+
+ Vpc result =
+ _networkService.migrateVpcNetwork(getId(), getVpcOfferingId(), getTierNetworkOfferings(), callerAccount, callerUser, getResume());
+
+ if (result != null) {
+ VpcResponse response = _responseGenerator.createVpcResponse(ResponseObject.ResponseView.Restricted, result);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate vpc");
+ }
+ }
+
+ @Override
+ public String getEventDescription() { return "Migrating vpc: " + getId() + " to new vpc offering (" + vpcOfferingId + ")"; }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_NETWORK_MIGRATE;
+ }
+
+ @Override
+ public String getSyncObjType() {
+ return BaseAsyncCmd.networkSyncObject;
+ }
+
+ @Override
+ public Long getSyncObjId() {
+ return id;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccount().getId();
+ }
+
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkCmdByAdmin.java b/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkCmdByAdmin.java
index 269f43ec9596..388348c592c1 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkCmdByAdmin.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkCmdByAdmin.java
@@ -49,7 +49,7 @@ public void execute() throws InsufficientCapacityException, ConcurrentOperationE
}
Network result = _networkService.updateGuestNetwork(getId(), getNetworkName(), getDisplayText(), callerAccount,
- callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr(), getGuestVmCidr(), getDisplayNetwork(), getCustomId());
+ callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr(), getGuestVmCidr(), getDisplayNetwork(), getCustomId(), getUpdateInSequence(),getForced());
if (result != null) {
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java
index 411da4fd36b5..5c58530fe1f9 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java
@@ -69,6 +69,9 @@ public class UpdateNetworkOfferingCmd extends BaseCmd {
description = "maximum number of concurrent connections supported by the network offering")
private Integer maxConnections;
+ @Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "the tags for the network offering.", length = 4096)
+ private String tags;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -105,6 +108,10 @@ public Boolean getKeepAliveEnabled() {
return keepAliveEnabled;
}
+ public String getTags() {
+ return tags;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java
index ea2e3cdb76b5..0499a6e4577c 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java
@@ -74,7 +74,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE
CallContext.current().setEventDetails("Host Id: " + host.getId() + " Password: " + getPassword().charAt(0) + "****");
CallContext.current().putContextParameter(Host.class, host.getUuid());
- final OutOfBandManagementResponse response = outOfBandManagementService.changeOutOfBandManagementPassword(host, getPassword());
+ final OutOfBandManagementResponse response = outOfBandManagementService.changePassword(host, getPassword());
response.setResponseName(getCommandName());
setResponseObject(response);
}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java
index db224108df07..d9c6c9f439e4 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java
@@ -83,7 +83,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId());
}
CallContext.current().putContextParameter(Host.class, host.getUuid());
- final OutOfBandManagementResponse response = outOfBandManagementService.configureOutOfBandManagement(host, getHostPMOptions());
+ final OutOfBandManagementResponse response = outOfBandManagementService.configure(host, getHostPMOptions());
response.setId(host.getUuid());
response.setResponseName(getCommandName());
setResponseObject(response);
diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java
index 8d6bdd350d00..7593a3cbc522 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java
@@ -80,7 +80,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE
CallContext.current().setEventDetails("Host Id: " + host.getId() + " Action: " + powerOperation.toString());
CallContext.current().putContextParameter(Host.class, host.getUuid());
- final OutOfBandManagementResponse response = outOfBandManagementService.executeOutOfBandManagementPowerOperation(host, powerOperation, getActionTimeout());
+ final OutOfBandManagementResponse response = outOfBandManagementService.executePowerOperation(host, powerOperation, getActionTimeout());
response.setResponseName(getCommandName());
setResponseObject(response);
}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/resource/ListCapacityCmd.java b/api/src/org/apache/cloudstack/api/command/admin/resource/ListCapacityCmd.java
index d79ff07fbccf..76ca3a79b11d 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/resource/ListCapacityCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/resource/ListCapacityCmd.java
@@ -17,6 +17,8 @@
package org.apache.cloudstack.api.command.admin.resource;
import java.text.DecimalFormat;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import org.apache.log4j.Logger;
@@ -65,7 +67,8 @@ public class ListCapacityCmd extends BaseListCmd {
@Parameter(name = ApiConstants.TYPE, type = CommandType.INTEGER, description = "lists capacity by type" + "* CAPACITY_TYPE_MEMORY = 0" + "* CAPACITY_TYPE_CPU = 1"
+ "* CAPACITY_TYPE_STORAGE = 2" + "* CAPACITY_TYPE_STORAGE_ALLOCATED = 3" + "* CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP = 4" + "* CAPACITY_TYPE_PRIVATE_IP = 5"
- + "* CAPACITY_TYPE_SECONDARY_STORAGE = 6" + "* CAPACITY_TYPE_VLAN = 7" + "* CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP = 8" + "* CAPACITY_TYPE_LOCAL_STORAGE = 9.")
+ + "* CAPACITY_TYPE_SECONDARY_STORAGE = 6" + "* CAPACITY_TYPE_VLAN = 7" + "* CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP = 8" + "* CAPACITY_TYPE_LOCAL_STORAGE = 9"
+ + "* CAPACITY_TYPE_GPU = 19" + "* CAPACITY_TYPE_CPU_CORE = 90.")
private Integer type;
@Parameter(name = ApiConstants.SORT_BY, type = CommandType.STRING, since = "3.0.0", description = "Sort the results. Available values: Usage")
@@ -127,6 +130,17 @@ public void execute() {
ListResponse response = new ListResponse();
List capacityResponses = _responseGenerator.createCapacityResponse(result, s_percentFormat);
+ Collections.sort(capacityResponses, new Comparator() {
+ public int compare(CapacityResponse resp1, CapacityResponse resp2) {
+ int res = resp1.getZoneName().compareTo(resp2.getZoneName());
+ if (res != 0) {
+ return res;
+ } else {
+ return resp1.getCapacityType().compareTo(resp2.getCapacityType());
+ }
+ }
+ });
+
response.setResponses(capacityResponses);
response.setResponseName(getCommandName());
this.setResponseObject(response);
diff --git a/api/src/org/apache/cloudstack/api/command/admin/template/CopyTemplateCmdByAdmin.java b/api/src/org/apache/cloudstack/api/command/admin/template/CopyTemplateCmdByAdmin.java
index 11c00e3a4b70..e0c798c78491 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/template/CopyTemplateCmdByAdmin.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/template/CopyTemplateCmdByAdmin.java
@@ -40,11 +40,20 @@ public class CopyTemplateCmdByAdmin extends CopyTemplateCmd {
@Override
public void execute() throws ResourceAllocationException{
try {
+ if (destZoneId == null && (destZoneIds == null || destZoneIds.size() == 0))
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
+ "Either destzoneid or destzoneids parameters have to be specified.");
+
+ if (destZoneId != null && destZoneIds != null && destZoneIds.size() != 0)
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
+ "Both destzoneid and destzoneids cannot be specified at the same time.");
+
CallContext.current().setEventDetails(getEventDescription());
VirtualMachineTemplate template = _templateService.copyTemplate(this);
if (template != null){
- List listResponse = _responseGenerator.createTemplateResponses(ResponseView.Full, template, getDestinationZoneId(), false);
+ List listResponse = _responseGenerator.createTemplateResponses(ResponseView.Full, template,
+ getDestinationZoneIds(), false);
TemplateResponse response = new TemplateResponse();
if (listResponse != null && !listResponse.isEmpty()) {
response = listResponse.get(0);
diff --git a/api/src/org/apache/cloudstack/api/command/admin/template/RegisterTemplateCmdByAdmin.java b/api/src/org/apache/cloudstack/api/command/admin/template/RegisterTemplateCmdByAdmin.java
index 68d53f9df6fa..ba4772b66971 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/template/RegisterTemplateCmdByAdmin.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/template/RegisterTemplateCmdByAdmin.java
@@ -40,10 +40,13 @@ public class RegisterTemplateCmdByAdmin extends RegisterTemplateCmd {
@Override
public void execute() throws ResourceAllocationException{
try {
+ validateParameters();
+
VirtualMachineTemplate template = _templateService.registerTemplate(this);
if (template != null){
ListResponse response = new ListResponse();
- List templateResponses = _responseGenerator.createTemplateResponses(ResponseView.Full, template, zoneId, false);
+ List templateResponses = _responseGenerator.createTemplateResponses(ResponseView.Full, template,
+ zoneIds, false);
response.setResponses(templateResponses);
response.setResponseName(getCommandName());
setResponseObject(response);
diff --git a/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java
index 4cceb3b5f9fc..90bc4f2153a1 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java
@@ -19,6 +19,8 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.apache.log4j.Logger;
@@ -31,6 +33,7 @@
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.UsageRecordResponse;
+import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.usage.Usage;
import com.cloud.utils.Pair;
@@ -76,6 +79,9 @@ public class GetUsageRecordsCmd extends BaseListCmd {
@Parameter(name = ApiConstants.USAGE_ID, type = CommandType.STRING, description = "List usage records for the specified usage UUID. Can be used only together with TYPE parameter.")
private String usageId;
+ @Parameter(name = ApiConstants.INCLUDE_TAGS, type = CommandType.BOOLEAN, description = "Flag to enable display of Tags for a resource")
+ private Boolean includeTags;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -115,6 +121,10 @@ public void setAccountName(String accountName) {
this.accountName = accountName;
}
+ public Boolean getIncludeTags() {
+ return includeTags;
+ }
+
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
@@ -150,12 +160,18 @@ public void execute() {
Pair, Integer> usageRecords = _usageService.getUsageRecords(this);
ListResponse response = new ListResponse();
List usageResponses = new ArrayList();
+ Map> resourceTagResponseMap = null;
if (usageRecords != null) {
+ //read the resource tags details for all the resources in usage data and store in Map
+ if(null != includeTags && includeTags) {
+ resourceTagResponseMap = _responseGenerator.getUsageResourceTags();
+ }
for (Usage usageRecord : usageRecords.first()) {
- UsageRecordResponse usageResponse = _responseGenerator.createUsageResponse(usageRecord);
+ UsageRecordResponse usageResponse = _responseGenerator.createUsageResponse(usageRecord, resourceTagResponseMap);
usageResponse.setObjectName("usagerecord");
usageResponses.add(usageResponse);
}
+
response.setResponses(usageResponses, usageRecords.second());
}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/GetUserKeysCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/GetUserKeysCmd.java
new file mode 100644
index 000000000000..f93c6e11728a
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/user/GetUserKeysCmd.java
@@ -0,0 +1,77 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.user;
+
+
+import com.cloud.user.Account;
+import com.cloud.user.User;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.RegisterResponse;
+import org.apache.cloudstack.api.response.UserResponse;
+
+import java.util.Map;
+import java.util.logging.Logger;
+
+@APICommand(name = GetUserKeysCmd.APINAME,
+ description = "This command allows the user to query the seceret and API keys for the account",
+ responseObject = RegisterResponse.class,
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = true,
+ authorized = {RoleType.User, RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin},
+ since = "4.10.0")
+
+public class GetUserKeysCmd extends BaseCmd{
+
+ @Parameter(name= ApiConstants.ID, type = CommandType.UUID, entityType = UserResponse.class, required = true, description = "ID of the user whose keys are required")
+ private Long id;
+
+ public static final Logger s_logger = Logger.getLogger(RegisterCmd.class.getName());
+ public static final String APINAME = "getUserKeys";
+
+ public Long getID(){
+ return id;
+ }
+
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ public long getEntityOwnerId(){
+ User user = _entityMgr.findById(User.class, getID());
+ if(user != null){
+ return user.getAccountId();
+ }
+ else return Account.ACCOUNT_ID_SYSTEM;
+ }
+ public void execute(){
+ Map keys = _accountService.getKeys(this);
+ RegisterResponse response = new RegisterResponse();
+ if(keys != null){
+ response.setApiKey(keys.get("apikey"));
+ response.setSecretKey(keys.get("secretkey"));
+ }
+
+ response.setObjectName("userkeys");
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/MoveUserCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/MoveUserCmd.java
new file mode 100644
index 000000000000..b32aa2f13268
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/user/MoveUserCmd.java
@@ -0,0 +1,126 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.user;
+
+import com.cloud.user.Account;
+import com.cloud.user.User;
+import com.google.common.base.Preconditions;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.AccountResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.api.response.UserResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.region.RegionService;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+
+@APICommand(name = "moveUser",
+ description = "Moves a user to another account",
+ responseObject = SuccessResponse.class,
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false,
+ since = "4.11",
+ authorized = {RoleType.Admin})
+public class MoveUserCmd extends BaseCmd {
+ public static final Logger s_logger = Logger.getLogger(UpdateUserCmd.class.getName());
+
+ public static final String APINAME = "moveUser";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+ @Parameter(name = ApiConstants.ID,
+ type = CommandType.UUID,
+ entityType = UserResponse.class,
+ required = true,
+ description = "id of the user to be deleted")
+ private Long id;
+
+ @Parameter(name = ApiConstants.ACCOUNT,
+ type = CommandType.STRING,
+ description = "Creates the user under the specified account. If no account is specified, the username will be used as the account name.")
+ private String accountName;
+
+ @Parameter(name = ApiConstants.ACCOUNT_ID,
+ type = CommandType.UUID,
+ entityType = AccountResponse.class,
+ description = "Creates the user under the specified domain. Has to be accompanied with the account parameter")
+ private Long accountId;
+
+ @Inject
+ RegionService _regionService;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public Long getAccountId() {
+ return accountId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ User user = _entityMgr.findById(User.class, getId());
+ if (user != null) {
+ return user.getAccountId();
+ }
+
+ return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
+ }
+
+ @Override
+ public void execute() {
+ Preconditions.checkNotNull(getId(),"I have to have an user to move!");
+ Preconditions.checkState(ObjectUtils.anyNotNull(getAccountId(),getAccountName()),"provide either an account name or an account id!");
+
+ CallContext.current().setEventDetails("UserId: " + getId());
+ boolean result =
+ _regionService.moveUser(this);
+ if (result) {
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ this.setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to move the user to a new account");
+ }
+ }
+
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java
index a2da7dbc8da5..fa66fdde1a72 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java
@@ -112,6 +112,9 @@ public class CreateVlanIpRangeCmd extends BaseCmd {
@Parameter(name = ApiConstants.IP6_CIDR, type = CommandType.STRING, description = "the CIDR of IPv6 network, must be at least /64")
private String ip6Cidr;
+ @Parameter(name = ApiConstants.FOR_SYSTEM_VMS, type = CommandType.BOOLEAN, description = "true if IP range is set to system vms, false if not")
+ private Boolean forSystemVms;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -136,6 +139,10 @@ public String getGateway() {
return gateway;
}
+ public Boolean isForSystemVms() {
+ return forSystemVms == null ? Boolean.FALSE : forSystemVms;
+ }
+
public String getNetmask() {
return netmask;
}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/vm/AssignVMCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vm/AssignVMCmd.java
index 435b7f184840..da5f68860bc6 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/vm/AssignVMCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/vm/AssignVMCmd.java
@@ -29,9 +29,11 @@
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.NetworkResponse;
+import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
+import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.uservm.UserVm;
import com.cloud.vm.VirtualMachine;
@@ -58,12 +60,15 @@ public class AssignVMCmd extends BaseCmd {
description = "id of the VM to be moved")
private Long virtualMachineId;
- @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "account name of the new VM owner.")
+ @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "account name of the new VM owner.")
private String accountName;
- @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, required = true, description = "domain id of the new VM owner.")
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "domain id of the new VM owner.")
private Long domainId;
+ @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "an optional project for the new VM owner.")
+ private Long projectId;
+
//Network information
@Parameter(name = ApiConstants.NETWORK_IDS,
type = CommandType.LIST,
@@ -98,6 +103,10 @@ public Long getDomainId() {
return domainId;
}
+ public Long getProjectId() {
+ return projectId;
+ }
+
public List getNetworkIds() {
return networkIds;
}
@@ -125,6 +134,9 @@ public void execute() {
UserVmResponse response = _responseGenerator.createUserVmResponse(ResponseView.Full, "virtualmachine", userVm).get(0);
response.setResponseName(getCommandName());
setResponseObject(response);
+ } catch (InvalidParameterValueException e){
+ e.printStackTrace();
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
} catch (Exception e) {
e.printStackTrace();
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to move vm " + e.getMessage());
diff --git a/api/src/org/apache/cloudstack/api/command/admin/volume/ListVolumesCmdByAdmin.java b/api/src/org/apache/cloudstack/api/command/admin/volume/ListVolumesCmdByAdmin.java
index 5fe5bfea485c..add22713931c 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/volume/ListVolumesCmdByAdmin.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/volume/ListVolumesCmdByAdmin.java
@@ -16,50 +16,15 @@
// under the License.
package org.apache.cloudstack.api.command.admin.volume;
-import org.apache.log4j.Logger;
-
-import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject.ResponseView;
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
-import org.apache.cloudstack.api.response.PodResponse;
-import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import com.cloud.storage.Volume;
-
-@APICommand(name = "listVolumes", description = "Lists all volumes.", responseObject = VolumeResponse.class, responseView = ResponseView.Full, entityType = {Volume.class},
- requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+@APICommand(name = "listVolumes", description = "Lists all volumes.", responseObject = VolumeResponse.class, responseView = ResponseView.Full, entityType = {
+ Volume.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListVolumesCmdByAdmin extends ListVolumesCmd {
- public static final Logger s_logger = Logger.getLogger(ListVolumesCmdByAdmin.class.getName());
-
- @Parameter(name=ApiConstants.POD_ID, type=CommandType.UUID, entityType=PodResponse.class,
- description="the pod id the disk volume belongs to")
- private Long podId;
-
-
- @Parameter(name=ApiConstants.STORAGE_ID, type=CommandType.UUID, entityType=StoragePoolResponse.class,
- description="the ID of the storage pool, available to ROOT admin only", since="4.3", authorized = { RoleType.Admin })
- private Long storageId;
-
-
- /////////////////////////////////////////////////////
- /////////////////// Accessors ///////////////////////
- /////////////////////////////////////////////////////
-
-
- @Override
- public Long getPodId() {
- return podId;
- }
-
-
- @Override
- public Long getStorageId() {
- return storageId;
- }
}
diff --git a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java
index 75bd9d21d1bd..15072ca9a4fd 100644
--- a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java
@@ -57,7 +57,7 @@
import com.cloud.projects.Project;
import com.cloud.user.Account;
-@APICommand(name = "associateIpAddress", description = "Acquires and associates a public IP to an account.", responseObject = IPAddressResponse.class, responseView = ResponseView.Restricted,
+@APICommand(name = "associateIpAddress", description = "Acquires and associates a public IP to an account. Either of the parameters are required, i.e. either zoneId, or networkId, or vpcId ", responseObject = IPAddressResponse.class, responseView = ResponseView.Restricted,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class AssociateIPAddrCmd extends BaseAsyncCreateCmd {
public static final Logger s_logger = Logger.getLogger(AssociateIPAddrCmd.class.getName());
diff --git a/api/src/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java b/api/src/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java
index a4934fa1dd9b..b98c30897a05 100644
--- a/api/src/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java
@@ -65,6 +65,9 @@ public class ListEventsCmd extends BaseListProjectAndAccountResourcesCmd {
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "the event type (see event types)")
private String type;
+ @Parameter(name = ApiConstants.START_ID, type = CommandType.UUID, entityType = EventResponse.class, description = "the parent/start ID of the event, when provided this will list all the events with the start/parent ID including the parent event")
+ private Long startId;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -97,6 +100,10 @@ public String getType() {
return type;
}
+ public Long getStartId() {
+ return startId;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/command/user/firewall/CreateEgressFirewallRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/firewall/CreateEgressFirewallRuleCmd.java
index 0303445af77d..9299c3ddd2c8 100644
--- a/api/src/org/apache/cloudstack/api/command/user/firewall/CreateEgressFirewallRuleCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/firewall/CreateEgressFirewallRuleCmd.java
@@ -77,6 +77,9 @@ public class CreateEgressFirewallRuleCmd extends BaseAsyncCreateCmd implements F
@Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic from")
private List cidrlist;
+ @Parameter(name = ApiConstants.DEST_CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic to")
+ private List destCidrList;
+
@Parameter(name = ApiConstants.ICMP_TYPE, type = CommandType.INTEGER, description = "type of the icmp message being sent")
private Integer icmpType;
@@ -113,6 +116,11 @@ public List getSourceCidrList() {
}
}
+ @Override
+ public List getDestinationCidrList(){
+ return destCidrList;
+ }
+
public Long getVpcId() {
Network network = _networkService.getNetwork(getNetworkId());
if (network == null) {
@@ -136,6 +144,10 @@ public void setSourceCidrList(List cidrs) {
cidrlist = cidrs;
}
+ public void setDestCidrList(List cidrs){
+ destCidrList = cidrs;
+ }
+
@Override
public void execute() throws ResourceUnavailableException {
CallContext callerContext = CallContext.current();
@@ -234,10 +246,10 @@ public void create() {
String guestCidr = _networkService.getNetwork(getNetworkId()).getCidr();
for (String cidr : getSourceCidrList()) {
- if (!NetUtils.isValidCIDR(cidr)) {
+ if (!NetUtils.isValidIp4Cidr(cidr) && !NetUtils.isValidIp6Cidr(cidr)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Source cidrs formatting error " + cidr);
}
- if (cidr.equals(NetUtils.ALL_CIDRS)) {
+ if (cidr.equals(NetUtils.ALL_IP4_CIDRS)) {
continue;
}
if (!NetUtils.isNetworkAWithinNetworkB(cidr, guestCidr)) {
@@ -245,6 +257,16 @@ public void create() {
}
}
}
+
+ //Destination CIDR formatting check. Since it's optional param, no need to set a default as in the case of source.
+ if(destCidrList != null){
+ for(String cidr : destCidrList){
+ if(!NetUtils.isValidIp4Cidr(cidr) && !NetUtils.isValidIp6Cidr(cidr)) {
+ throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Destination cidrs formatting error" + cidr);
+ }
+ }
+ }
+
if (getProtocol().equalsIgnoreCase(NetUtils.ALL_PROTO)) {
if (getSourcePortStart() != null && getSourcePortEnd() != null) {
throw new InvalidParameterValueException("Do not pass ports to protocol ALL, protocol ALL do not require ports. Unable to create " +
diff --git a/api/src/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java
index ee62aa5ad4ad..fab7d9eef29a 100644
--- a/api/src/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java
@@ -108,7 +108,7 @@ public List getSourceCidrList() {
return cidrlist;
} else {
List oneCidrList = new ArrayList();
- oneCidrList.add(NetUtils.ALL_CIDRS);
+ oneCidrList.add(NetUtils.ALL_IP4_CIDRS);
return oneCidrList;
}
@@ -242,7 +242,7 @@ public long getDomainId() {
public void create() {
if (getSourceCidrList() != null) {
for (String cidr : getSourceCidrList()) {
- if (!NetUtils.isValidCIDR(cidr)) {
+ if (!NetUtils.isValidIp4Cidr(cidr) && !NetUtils.isValidIp6Cidr(cidr)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Source CIDRs formatting error " + cidr);
}
}
@@ -349,6 +349,11 @@ public boolean isDisplay() {
}
}
+ @Override
+ public List getDestinationCidrList(){
+ return null;
+ }
+
@Override
public Class> getEntityType() {
return FirewallRule.class;
diff --git a/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java
index 9a0dffe1fdc5..ea0cb00301a0 100644
--- a/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java
@@ -348,7 +348,7 @@ public void create() {
Ip privateIp = getVmSecondaryIp();
if (privateIp != null) {
- if (!NetUtils.isValidIp(privateIp.toString())) {
+ if (!NetUtils.isValidIp4(privateIp.toString())) {
throw new InvalidParameterValueException("Invalid vm ip address");
}
}
@@ -429,6 +429,11 @@ public TrafficType getTrafficType() {
return null;
}
+ @Override
+ public List getDestinationCidrList(){
+ return null;
+ }
+
@Override
public boolean isDisplay() {
if (display != null) {
diff --git a/api/src/org/apache/cloudstack/api/command/user/firewall/UpdatePortForwardingRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/firewall/UpdatePortForwardingRuleCmd.java
index 5f609b726f80..7de50761630b 100644
--- a/api/src/org/apache/cloudstack/api/command/user/firewall/UpdatePortForwardingRuleCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/firewall/UpdatePortForwardingRuleCmd.java
@@ -47,9 +47,13 @@ public class UpdatePortForwardingRuleCmd extends BaseAsyncCustomIdCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, required = true, description = "the ID of the port forwarding rule", since = "4.4")
private Long id;
- @Parameter(name=ApiConstants.PRIVATE_PORT, type=CommandType.INTEGER, description="the private port of the port forwarding rule")
+ @Parameter(name=ApiConstants.PRIVATE_START_PORT, type=CommandType.INTEGER, description="the private start port of the port forwarding rule")
private Integer privatePort;
+
+ @Parameter(name=ApiConstants.PRIVATE_END_PORT, type=CommandType.INTEGER, description="the private end port of the port forwarding rule")
+ private Integer privateEndPort;
+
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
@@ -74,6 +78,10 @@ public Integer getPrivatePort() {
return privatePort;
}
+ public Integer getPrivateEndPort() {
+ return privateEndPort;
+ }
+
public Long getVirtualMachineId() {
return virtualMachineId;
}
@@ -130,7 +138,7 @@ public void checkUuid() {
@Override
public void execute() {
- PortForwardingRule rule = _rulesService.updatePortForwardingRule(id, getPrivatePort(), getVirtualMachineId(), getVmGuestIp(), getCustomId(), getDisplay());
+ PortForwardingRule rule = _rulesService.updatePortForwardingRule(getId(), getPrivatePort(), getPrivateEndPort(), getVirtualMachineId(), getVmGuestIp(), getCustomId(), getDisplay());
FirewallRuleResponse fwResponse = new FirewallRuleResponse();
if (rule != null) {
fwResponse = _responseGenerator.createPortForwardingRuleResponse(rule);
diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
index 599aac1fd03c..745b87dd941a 100644
--- a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
@@ -94,7 +94,7 @@ public class RegisterIsoCmd extends BaseCmd {
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account name. Must be used with domainId.")
private String accountName;
- @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the MD5 checksum value of this ISO")
+ @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the checksum value of this ISO. " + ApiConstants.CHECKSUM_PARAMETER_PREFIX_DESCRIPTION)
private String checksum;
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Register ISO for the project")
@@ -108,6 +108,11 @@ public class RegisterIsoCmd extends BaseCmd {
description = "true if ISO contains XS/VMWare tools inorder to support dynamic scaling of VM CPU/memory")
protected Boolean isDynamicallyScalable;
+ @Parameter(name=ApiConstants.DIRECT_DOWNLOAD,
+ type = CommandType.BOOLEAN,
+ description = "true if ISO should bypass Secondary Storage and be downloaded to Primary Storage on deployment")
+ private Boolean directDownload;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -168,6 +173,10 @@ public Boolean isDynamicallyScalable() {
return isDynamicallyScalable == null ? Boolean.FALSE : isDynamicallyScalable;
}
+ public boolean isDirectDownload() {
+ return directDownload == null ? false : directDownload;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignToLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignToLoadBalancerRuleCmd.java
index fdc8a31c59a5..1e7303708014 100644
--- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignToLoadBalancerRuleCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignToLoadBalancerRuleCmd.java
@@ -140,7 +140,7 @@ public Map> getVmIdIpListMap() {
}
//check wether the given ip is valid ip or not
- if (vmIp == null || !NetUtils.isValidIp(vmIp)) {
+ if (vmIp == null || !NetUtils.isValidIp4(vmIp)) {
throw new InvalidParameterValueException("Invalid ip address "+ vmIp +" passed in vmidipmap for " +
"vmid " + vmId);
}
diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteSslCertCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteSslCertCmd.java
index 2efd036cc97f..656c14c10483 100644
--- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteSslCertCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteSslCertCmd.java
@@ -34,7 +34,7 @@
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.network.lb.CertService;
+import org.apache.cloudstack.network.tls.CertService;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = "deleteSslCert", description = "Delete a certificate to CloudStack", responseObject = SuccessResponse.class,
diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java
index d1dbdcb28236..cfa567548500 100644
--- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java
@@ -33,7 +33,7 @@
import org.apache.cloudstack.api.response.SslCertResponse;
import org.apache.cloudstack.context.CallContext;
-import com.cloud.network.lb.CertService;
+import org.apache.cloudstack.network.tls.CertService;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = "listSslCerts", description = "Lists SSL certificates", responseObject = SslCertResponse.class,
diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerRuleCmd.java
index 6b1e0fddd54a..6ee277a354c9 100644
--- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerRuleCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerRuleCmd.java
@@ -64,6 +64,9 @@ public class UpdateLoadBalancerRuleCmd extends BaseAsyncCustomIdCmd {
@Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the rule to the end user or not", since = "4.4", authorized = {RoleType.Admin})
private Boolean display;
+ @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, description = "The protocol for the LB")
+ private String lbProtocol;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -88,6 +91,10 @@ public Boolean getDisplay() {
return display;
}
+ public String getLbProtocol() {
+ return lbProtocol;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UploadSslCertCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UploadSslCertCmd.java
index 4bd2de9017f4..309e43fcbbe9 100644
--- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UploadSslCertCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UploadSslCertCmd.java
@@ -36,7 +36,7 @@
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.network.lb.CertService;
+import org.apache.cloudstack.network.tls.CertService;
@APICommand(name = "uploadSslCert", description = "Upload a certificate to CloudStack", responseObject = SslCertResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -73,6 +73,9 @@ public class UploadSslCertCmd extends BaseCmd {
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "domain ID of the account owning the SSL certificate")
private Long domainId;
+ @Parameter(name = ApiConstants.NAME , type = CommandType.STRING, required = true, description = "Name for the uploaded certificate")
+ private String name;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -105,10 +108,15 @@ public Long getProjectId() {
return projectId;
}
+ public String getName() {
+ return name;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
+
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException, NetworkRuleConflictException {
diff --git a/api/src/org/apache/cloudstack/api/command/user/nat/CreateIpForwardingRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/nat/CreateIpForwardingRuleCmd.java
index d85030e3cd96..1b367a9fa7b3 100644
--- a/api/src/org/apache/cloudstack/api/command/user/nat/CreateIpForwardingRuleCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/nat/CreateIpForwardingRuleCmd.java
@@ -323,6 +323,11 @@ public boolean isDisplay() {
return true;
}
+ @Override
+ public List getDestinationCidrList(){
+ return null;
+ }
+
@Override
public Class> getEntityType() {
return FirewallRule.class;
diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLCmd.java
index c8a8f8cae394..4b6a836f32a8 100644
--- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkACLCmd.java
@@ -134,7 +134,7 @@ public List getSourceCidrList() {
return cidrlist;
} else {
List oneCidrList = new ArrayList();
- oneCidrList.add(NetUtils.ALL_CIDRS);
+ oneCidrList.add(NetUtils.ALL_IP4_CIDRS);
return oneCidrList;
}
}
diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
index 173126148082..befef999bfd5 100644
--- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
@@ -16,7 +16,6 @@
// under the License.
package org.apache.cloudstack.api.command.user.network;
-import com.cloud.utils.net.NetUtils;
import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.RoleType;
@@ -44,6 +43,7 @@
import com.cloud.network.Network;
import com.cloud.network.Network.GuestType;
import com.cloud.offering.NetworkOffering;
+import com.cloud.utils.net.NetUtils;
@APICommand(name = "createNetwork", description = "Creates a network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class},
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -134,6 +134,9 @@ public class CreateNetworkCmd extends BaseCmd {
@Parameter(name = ApiConstants.IP6_CIDR, type = CommandType.STRING, description = "the CIDR of IPv6 network, must be at least /64")
private String ip6Cidr;
+ @Parameter(name = ApiConstants.EXTERNAL_ID, type = CommandType.STRING, description = "ID of the network in an external system.")
+ private String externalId;
+
@Parameter(name = ApiConstants.DISPLAY_NETWORK,
type = CommandType.BOOLEAN,
description = "an optional field, whether to the display the network to the end user or not.", authorized = {RoleType.Admin})
@@ -209,6 +212,10 @@ public Boolean getDisplayNetwork() {
return displayNetwork;
}
+ public String getExternalId() {
+ return externalId;
+ }
+
@Override
public boolean isDisplay() {
if(displayNetwork == null)
diff --git a/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java
index 62566653bca7..645ae5aff8e3 100644
--- a/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/network/RestartNetworkCmd.java
@@ -55,7 +55,10 @@ public class RestartNetworkCmd extends BaseAsyncCmd {
private Long id;
@Parameter(name = ApiConstants.CLEANUP, type = CommandType.BOOLEAN, required = false, description = "If cleanup old network elements")
- private Boolean cleanup;
+ private Boolean cleanup = false;
+
+ @Parameter(name = ApiConstants.MAKEREDUNDANT, type = CommandType.BOOLEAN, required = false, description = "Turn the network into a network with redundant routers.", since = "4.11.1")
+ private Boolean makeRedundant = false;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
@@ -71,10 +74,11 @@ public Long getNetworkId() {
}
public Boolean getCleanup() {
- if (cleanup != null) {
- return cleanup;
- }
- return true;
+ return cleanup;
+ }
+
+ public Boolean getMakeRedundant() {
+ return makeRedundant;
}
/////////////////////////////////////////////////////
@@ -92,7 +96,7 @@ public static String getResultObjectName() {
@Override
public void execute() throws ResourceUnavailableException, ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException {
- boolean result = _networkService.restartNetwork(this, getCleanup());
+ boolean result = _networkService.restartNetwork(this, getCleanup(), getMakeRedundant());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
diff --git a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
index 921e74b67b2c..c313f369b0e2 100644
--- a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
@@ -75,11 +75,17 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd {
@Parameter(name = ApiConstants.GUEST_VM_CIDR, type = CommandType.STRING, description = "CIDR for guest VMs, CloudStack allocates IPs to guest VMs only from this CIDR")
private String guestVmCidr;
+ @Parameter(name =ApiConstants.Update_IN_SEQUENCE, type=CommandType.BOOLEAN, description = "if true, we will update the routers one after the other. applicable only for redundant router based networks using virtual router as provider")
+ private Boolean updateInSequence;
+
@Parameter(name = ApiConstants.DISPLAY_NETWORK,
type = CommandType.BOOLEAN,
description = "an optional field, whether to the display the network to the end user or not.", authorized = {RoleType.Admin})
private Boolean displayNetwork;
+ @Parameter(name= ApiConstants.FORCED, type = CommandType.BOOLEAN, description = "Setting this to true will cause a forced network update,", authorized = {RoleType.Admin})
+ private Boolean forced;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -119,6 +125,19 @@ public Boolean getDisplayNetwork() {
return displayNetwork;
}
+ public Boolean getUpdateInSequence(){
+ if(updateInSequence ==null)
+ return false;
+ else
+ return updateInSequence;
+ }
+
+ public boolean getForced(){
+ if(forced==null){
+ return false;
+ }
+ return forced;
+ }
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@@ -149,7 +168,7 @@ public void execute() throws InsufficientCapacityException, ConcurrentOperationE
Network result =
_networkService.updateGuestNetwork(getId(), getNetworkName(), getDisplayText(), callerAccount, callerUser, getNetworkDomain(), getNetworkOfferingId(),
- getChangeCidr(), getGuestVmCidr(), getDisplayNetwork(), getCustomId());
+ getChangeCidr(), getGuestVmCidr(), getDisplayNetwork(), getCustomId(), getUpdateInSequence(), getForced());
if (result != null) {
NetworkResponse response = _responseGenerator.createNetworkResponse(ResponseView.Restricted, result);
diff --git a/api/src/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java b/api/src/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java
index 14d1d55ff8bb..68c09c27fb03 100644
--- a/api/src/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java
@@ -19,6 +19,8 @@
import java.util.ArrayList;
import java.util.List;
+import com.cloud.configuration.Resource;
+import com.cloud.exception.InvalidParameterValueException;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
@@ -58,6 +60,21 @@ public class ListResourceLimitsCmd extends BaseListProjectAndAccountResourcesCmd
+ "11 - SecondaryStorage. Total secondary storage space (in GiB) a user can use. ")
private Integer resourceType;
+ @Parameter(name = ApiConstants.RESOURCE_TYPE_NAME, type = CommandType.STRING, description = "Type of resource (wins over resourceType if both are provided). Values are: "
+ + "user_vm - Instance. Number of instances a user can create. "
+ + "public_ip - IP. Number of public IP addresses an account can own. "
+ + "volume - Volume. Number of disk volumes an account can own. "
+ + "snapshot - Snapshot. Number of snapshots an account can own. "
+ + "template - Template. Number of templates an account can register/create. "
+ + "project - Project. Number of projects an account can own. "
+ + "network - Network. Number of networks an account can own. "
+ + "vpc - VPC. Number of VPC an account can own. "
+ + "cpu - CPU. Number of CPU an account can allocate for his resources. "
+ + "memory - Memory. Amount of RAM an account can allocate for his resources. "
+ + "primary_storage - PrimaryStorage. Total primary storage space (in GiB) a user can use. "
+ + "secondary_storage - SecondaryStorage. Total secondary storage space (in GiB) a user can use. ")
+ private String resourceTypeName;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -70,6 +87,10 @@ public Integer getResourceType() {
return resourceType;
}
+ public String getResourceTypeName() {
+ return resourceTypeName;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@@ -83,7 +104,7 @@ public String getCommandName() {
public void execute() {
List extends ResourceLimit> result =
_resourceLimitService.searchForLimits(id, _accountService.finalyzeAccountId(this.getAccountName(), this.getDomainId(), this.getProjectId(), false), this.getDomainId(),
- resourceType, this.getStartIndex(), this.getPageSizeVal());
+ getResourceTypeEnum(), this.getStartIndex(), this.getPageSizeVal());
ListResponse