Merge branch '4.22'
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..2af9f54
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,22 @@
+# 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.
+
+/plugins/storage/volume/linstor @rp-
+/plugins/storage/volume/storpool @slavkap
+
+.pre-commit-config.yaml @jbampton
+/.github/linters/ @jbampton
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yml
similarity index 100%
rename from .github/ISSUE_TEMPLATE/feature_request.yaml
rename to .github/ISSUE_TEMPLATE/feature_request.yml
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..41b3078
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,30 @@
+# 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.
+
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "maven" # See documentation for possible values
+ directory: "/" # Location of package manifests
+ schedule:
+ interval: "daily"
+ cooldown:
+ default-days: 7
diff --git a/.github/linters/.yamllint.yml b/.github/linters/.yamllint.yml
index 8a72aee..97b6684 100644
--- a/.github/linters/.yamllint.yml
+++ b/.github/linters/.yamllint.yml
@@ -15,13 +15,14 @@
# specific language governing permissions and limitations
# under the License.
---
-extends: relaxed
+extends: default
rules:
line-length:
max: 400 # Very forgiving for GitHub Actions and infrastructure files
indentation: disable # Disable indentation checking for existing files
comments: disable # Disable comment formatting checks
+ braces: disable
brackets: disable # Disable bracket spacing checks
colons:
max-spaces-after: -1 # Allow any number of spaces after colon
diff --git a/.github/linters/codespell.txt b/.github/linters/codespell.txt
index 27761c7..67cbeaa 100644
--- a/.github/linters/codespell.txt
+++ b/.github/linters/codespell.txt
@@ -4,6 +4,7 @@
actuall
acuiring
acumulate
+addin
addreess
addtion
adminstrator
@@ -12,10 +13,8 @@
afterall
againt
ags
-aktive
algoritm
allo
-alloacate
allocted
alocation
alogrithm
@@ -65,6 +64,7 @@
boardcast
bootstraper
bu
+callin
cant
capabilites
capablity
@@ -73,6 +73,7 @@
cavaet
chaing
checkd
+checkin
childs
choosen
chould
@@ -93,7 +94,6 @@
configruation
configuable
conneciton
-connexion
constrait
constraits
containg
@@ -101,9 +101,7 @@
continuesly
contro
controler
-controles
controll
-convienient
convinience
coputer
correcponding
@@ -158,13 +156,13 @@
differnt
direcotry
directroy
-disale
disbale
discrepency
disover
dissapper
dissassociated
divice
+dockin
doesn'
doesnot
doesnt
@@ -175,7 +173,6 @@
earch
ect
elemnt
-eles
elments
emmited
enble
@@ -187,22 +184,19 @@
equivalant
erro
erronous
-everthing
everytime
excute
execept
execption
+exects
execut
executeable
exeeded
exisitng
exisits
-existin
existsing
-exitting
expcted
expection
-explaination
explicitely
faield
faild
@@ -215,7 +209,6 @@
findout
fisrt
fo
-folowing
fowarding
frist
fro
@@ -234,6 +227,7 @@
happend
hasing
hasnt
+havin
hda
hostanme
hould
@@ -253,20 +247,14 @@
implmentation
incase
includeing
-incosistency
indecates
-indien
infor
informations
informaton
-infrastrcuture
ingore
-inital
initalize
initator
-initilization
inspite
-instace
instal
instnace
intefaces
@@ -284,12 +272,8 @@
klunky
lable
leve
-lief
limite
-linke
listner
-lokal
-lokales
maintainence
maintenace
maintenence
@@ -298,7 +282,6 @@
manaully
manuel
maxium
-mehtod
mergable
mesage
messge
@@ -308,7 +291,6 @@
mis
modifers
mor
-mot
mulitply
multipl
multple
@@ -322,7 +304,7 @@
nodel
nome
noone
-nowe
+notin
numbe
numer
occured
@@ -390,12 +372,9 @@
remore
remvoing
renabling
-repeatly
reponse
reqest
reqiured
-requieres
-requried
reserv
reserverd
reseted
@@ -414,14 +393,13 @@
returing
rever
rocessor
+roperty
runing
runnign
sate
scalled
-scipt
scirpt
scrip
-seconadry
seconday
seesion
sepcified
@@ -434,12 +412,10 @@
sevices
shoul
shoule
-sie
signle
simplier
singature
skiping
-snaphsot
snpashot
specied
specifed
@@ -450,7 +426,6 @@
statics
stickyness
stil
-stip
storeage
strat
streched
@@ -459,7 +434,6 @@
successfull
suceessful
suces
-sucessfully
suiteable
suppots
suppport
@@ -492,7 +466,6 @@
uneccessarily
unexepected
unexpect
-unknow
unkonw
unkown
unneccessary
@@ -500,14 +473,12 @@
unrecoginized
unsupport
unxpected
-updat
uptodate
usera
usign
usin
utlization
vaidate
-valiate
valule
valus
varibles
@@ -516,8 +487,6 @@
verifing
virutal
visable
-wakup
wil
wit
-wll
wth
diff --git a/.github/workflows/main-sonar-check.yml b/.github/workflows/main-sonar-check.yml
index 70cc3fb..224ea2c 100644
--- a/.github/workflows/main-sonar-check.yml
+++ b/.github/workflows/main-sonar-check.yml
@@ -44,14 +44,14 @@
cache: 'maven'
- name: Cache SonarCloud packages
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache local Maven repository
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('pom.xml', '*/pom.xml', '*/*/pom.xml', '*/*/*/pom.xml') }}
diff --git a/.github/workflows/linter.yml b/.github/workflows/pre-commit.yml
similarity index 90%
rename from .github/workflows/linter.yml
rename to .github/workflows/pre-commit.yml
index 6ff9974..11fe5c0 100644
--- a/.github/workflows/linter.yml
+++ b/.github/workflows/pre-commit.yml
@@ -39,11 +39,11 @@
pip install pre-commit
- name: Set PY
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
- - uses: actions/cache@v4
+ - uses: actions/cache@v5
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
- name: Run pre-commit
- run: pre-commit run --all-files
+ run: pre-commit run --color=always --all-files
- name: Run manual pre-commit hooks
- run: pre-commit run --all-files --hook-stage manual
+ run: pre-commit run --color=always --all-files --hook-stage manual
diff --git a/.github/workflows/sonar-check.yml b/.github/workflows/sonar-check.yml
index 46bfdd7..31fb671 100644
--- a/.github/workflows/sonar-check.yml
+++ b/.github/workflows/sonar-check.yml
@@ -46,14 +46,14 @@
cache: 'maven'
- name: Cache SonarCloud packages
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache local Maven repository
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('pom.xml', '*/pom.xml', '*/*/pom.xml', '*/*/*/pom.xml') }}
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 0000000..842e449
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -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.
+
+name: 'Close stale issues and PRs'
+on:
+ schedule:
+ - cron: '30 1 * * *'
+
+jobs:
+ stale:
+ runs-on: ubuntu-latest
+ permissions:
+ actions: write
+ issues: write
+ pull-requests: write
+ steps:
+ - uses: actions/stale@v10
+ with:
+ stale-issue-message: 'This issue is stale because it has been open for 120 days with no activity. It may be removed by administrators of this project at any time. Remove the stale label or comment to request for removal of it to prevent this.'
+ stale-pr-message: 'This PR is stale because it has been open for 120 days with no activity. It may be removed by administrators of this project at any time. Remove the stale label or comment to request for removal of it to prevent this.'
+ close-issue-message: 'This issue was closed because it has been stale for 120 days with no activity.'
+ close-pr-message: 'This PR was closed because it has been stale for 240 days with no activity.'
+ stale-issue-label: 'no-issue-activity'
+ stale-pr-label: 'no-pr-activity'
+ days-before-stale: 120
+ days-before-close: -1
+ days-before-pr-close: 240
+ exempt-issue-labels: 'gsoc,good-first-issue,long-term-plan'
+ exempt-pr-labels: 'status:ready-for-merge,status:needs-testing,status:on-hold'
+ - uses: actions/stale@v10
+ with:
+ stale-issue-label: 'archive'
+ days-before-stale: 240
+ exempt-issue-labels: 'gsoc,good-first-issue,long-term-plan'
+ days-before-close: -1
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e1a7db7..49829ca 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,6 +25,12 @@
hooks:
- id: identity
- id: check-hooks-apply
+ - repo: https://github.com/thlorenz/doctoc.git
+ rev: v2.2.0
+ hooks:
+ - id: doctoc
+ name: Add TOC for Markdown files
+ files: ^CONTRIBUTING\.md$|^INSTALL\.md$|^README\.md$
- repo: https://github.com/oxipng/oxipng
rev: v9.1.5
hooks:
@@ -41,6 +47,21 @@
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
hooks:
+ - id: chmod
+ name: set file permissions
+ args: ['644']
+ files: \.md$
+ stages: [manual]
+ - id: insert-license
+ name: add license for all cfg files
+ description: automatically adds a licence header to all cfg files that don't have a license header
+ files: \.cfg$
+ args:
+ - --comment-style
+ - '|#|'
+ - --license-filepath
+ - .github/workflows/license-templates/LICENSE.txt
+ - --fuzzy-match-generates-todo
- id: insert-license
name: add license for all Markdown files
files: \.md$
@@ -51,6 +72,54 @@
- .github/workflows/license-templates/LICENSE.txt
- --fuzzy-match-generates-todo
exclude: ^(CHANGES|ISSUE_TEMPLATE|PULL_REQUEST_TEMPLATE)\.md$|^ui/docs/(full|smoke)-test-plan\.template\.md$
+ - id: insert-license
+ name: add license for all properties files
+ description: automatically adds a licence header to all properties files that don't have a license header
+ files: \.properties$
+ args:
+ - --comment-style
+ - '|#|'
+ - --license-filepath
+ - .github/workflows/license-templates/LICENSE.txt
+ - --fuzzy-match-generates-todo
+ - id: insert-license
+ name: add license for all Shell files
+ description: automatically adds a licence header to all Shell files that don't have a license header
+ files: \.sh$
+ args:
+ - --comment-style
+ - '|#|'
+ - --license-filepath
+ - .github/workflows/license-templates/LICENSE.txt
+ - --fuzzy-match-generates-todo
+ - id: insert-license
+ name: add license for all SQL files
+ files: \.sql$
+ args:
+ - --comment-style
+ - '|--|'
+ - --license-filepath
+ - .github/workflows/license-templates/LICENSE.txt
+ - --fuzzy-match-generates-todo
+ - id: insert-license
+ name: add license for all Vue files
+ files: \.vue$
+ args:
+ - --comment-style
+ - '|//|'
+ - --license-filepath
+ - .github/workflows/license-templates/LICENSE.txt
+ - --fuzzy-match-generates-todo
+ - id: insert-license
+ name: add license for all YAML files
+ description: automatically adds a licence header to all YAML files that don't have a license header
+ files: \.ya?ml$
+ args:
+ - --comment-style
+ - '|#|'
+ - --license-filepath
+ - .github/workflows/license-templates/LICENSE.txt
+ - --fuzzy-match-generates-todo
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
@@ -84,7 +153,7 @@
^systemvm/agent/certs/realhostip\.key$|
^test/integration/smoke/test_ssl_offloading\.py$
- id: end-of-file-fixer
- exclude: \.vhd$
+ exclude: \.vhd$|\.svg$
- id: file-contents-sorter
args: [--unique]
files: ^\.github/linters/codespell\.txt$
@@ -92,11 +161,11 @@
- id: forbid-submodules
- id: mixed-line-ending
- id: trailing-whitespace
- files: \.(bat|cfg|cs|css|gitignore|header|in|install|java|md|properties|py|rb|rc|sh|sql|te|template|txt|ucls|vue|xml|xsl|yaml|yml)$|^cloud-cli/bindir/cloud-tool$|^debian/changelog$
+ files: ^(LICENSE|NOTICE)$|\.(bat|cfg|cs|css|gitignore|header|in|install|java|md|properties|py|rb|rc|sh|sql|te|template|txt|ucls|vue|xml|xsl|yaml|yml)$|^cloud-cli/bindir/cloud-tool$|^debian/changelog$
args: [--markdown-linebreak-ext=md]
exclude: ^services/console-proxy/rdpconsole/src/test/doc/freerdp-debug-log\.txt$
- repo: https://github.com/codespell-project/codespell
- rev: v2.2.6
+ rev: v2.4.1
hooks:
- id: codespell
name: run codespell
@@ -117,14 +186,6 @@
args: [--config=.github/linters/.markdown-lint.yml]
types: [markdown]
files: \.(md|mdown|markdown)$
- - repo: https://github.com/Lucas-C/pre-commit-hooks
- rev: v1.5.5
- hooks:
- - id: chmod
- name: set file permissions
- args: ['644']
- files: \.md$
- stages: [manual]
- repo: https://github.com/adrienverge/yamllint
rev: v1.37.1
hooks:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 57b7a71..f0678ed 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -21,6 +21,24 @@
## Summary
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+
+- [Summary](#summary)
+- [Bug fixes](#bug-fixes)
+- [Developing new features](#developing-new-features)
+- [PendingReleaseNotes file](#pendingreleasenotes-file)
+- [Fork the code](#fork-the-code)
+- [Making changes](#making-changes)
+- [Rebase `feature_x` to include updates from `upstream/main`](#rebase-feature_x-to-include-updates-from-upstreammain)
+- [Make a GitHub Pull Request to contribute your changes](#make-a-github-pull-request-to-contribute-your-changes)
+- [Cleaning up after a successful pull request](#cleaning-up-after-a-successful-pull-request)
+- [Release Principles](#release-principles)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
+## Summary
+
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.
diff --git a/INSTALL.md b/INSTALL.md
index 0619b97..52f109b 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -26,9 +26,21 @@
Apache CloudStack developers use various platforms for development, this guide
was tested against a CentOS 7 x86_64 setup.
-* [Setting up development environment](https://cwiki.apache.org/confluence/display/CLOUDSTACK/Setting+up+CloudStack+Development+Environment) for Apache CloudStack.
-* [Building](https://cwiki.apache.org/confluence/display/CLOUDSTACK/How+to+build+CloudStack) Apache CloudStack.
-* [Appliance based development](https://github.com/rhtyd/monkeybox)
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+
+- [Setting up Development Environment](#setting-up-development-environment)
+ - [Using jenv and/or pyenv for Version Management](#using-jenv-andor-pyenv-for-version-management)
+- [Getting the Source Code](#getting-the-source-code)
+- [Building](#building)
+- [To bring up CloudStack UI](#to-bring-up-cloudstack-ui)
+- [Building with non-redistributable plugins](#building-with-non-redistributable-plugins)
+- [Packaging and Installation](#packaging-and-installation)
+ - [Debian/Ubuntu](#debianubuntu)
+ - [RHEL/CentOS](#rhelcentos)
+- [Notes](#notes)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Setting up Development Environment
diff --git a/LICENSE b/LICENSE
index 8be7d80..e61c431 100644
--- a/LICENSE
+++ b/LICENSE
@@ -177,14 +177,14 @@
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
-
+
This distribution contains third party resources.
Within the console-proxy/js directory
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
- Copyright (c) 2009, John Resig
-
+ Copyright (c) 2009, John Resig
+
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
@@ -192,10 +192,10 @@
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
@@ -203,43 +203,43 @@
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 John Resig
- jquery.js
+
+ from John Resig
+ jquery.js
Within the systemvm/debian/etc directory
placed in the public domain
- by Adiscon GmbH http://www.adiscon.com/
- rsyslog.conf
- by Simon Kelley
- dnsmasq.conf
- vpcdnsmasq.conf
+ by Adiscon GmbH http://www.adiscon.com/
+ rsyslog.conf
+ by Simon Kelley
+ dnsmasq.conf
+ vpcdnsmasq.conf
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
+ from The Apache Software Foundation http://www.apache.org/
+ httpd.conf
vhost.template
Within the systemvm/debian/etc/ssh/ directory
licensed under the BSD (2-clause) http://www.opensource.org/licenses/BSD-2-Clause (as follows)
-
-
+
+
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the
distribution.
-
+
Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -250,55 +250,55 @@
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- from OpenSSH Project http://www.openssh.org/
- sshd_config
+
+ from OpenSSH Project http://www.openssh.org/
+ sshd_config
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
+ by The netfilter.org project http://www.netfilter.org/
+ conntrackd.conf.templ
Within the scripts/storage/secondary directory
licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above)
Copyright (c) 2010-2011 OpenStack, LLC.
- from OpenStack, LLC http://www.openstack.org
- swift
+ from OpenStack, LLC http://www.openstack.org
+ swift
Within the scripts/vm/hypervisor/xenserver directory
licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above)
Copyright (c) 2010-2011 OpenStack, LLC.
- from OpenStack, LLC http://www.openstack.org
- swift
+ from OpenStack, LLC http://www.openstack.org
+ swift
Within the ui/lib directory
placed in the public domain
- by Eric Meyer http://meyerweb.com/eric/
+ by Eric Meyer http://meyerweb.com/eric/
reset.css from http://meyerweb.com/eric/tools/css/reset/
licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above)
Copyright (c) 2006 Google Inc.
- from Google Inc. http://google.com
+ from Google Inc. http://google.com
excanvas.js from http://code.google.com/p/explorercanvas/
licensed under the BSD (2-clause) http://www.opensource.org/licenses/BSD-2-Clause (as follows)
Copyright (c) 2008 George McGinley Smith
- All rights reserved.
-
+ All rights reserved.
+
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the
distribution.
-
+
Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -309,13 +309,13 @@
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- from George McGinley Smith
- jquery.easing.js
+
+ from George McGinley Smith
+ jquery.easing.js
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
-
-
+
+
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
@@ -323,10 +323,10 @@
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
@@ -334,14 +334,14 @@
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 The Dojo Foundation http://dojofoundation.org/
+
+ from The Dojo Foundation http://dojofoundation.org/
require.js from http://github.com/jrburke/requirejs
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
- Copyright (c) 2011, John Resig
-
+ Copyright (c) 2011, John Resig
+
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
@@ -349,10 +349,10 @@
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
@@ -360,14 +360,14 @@
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 John Resig
- jquery.js
+
+ from John Resig
+ jquery.js
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
Copyright (c) 2014 Jörn Zaefferer
-
+
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
@@ -375,10 +375,10 @@
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
@@ -386,9 +386,9 @@
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 Jorn Zaefferer
- jquery.validate.js
+
+ from Jorn Zaefferer
+ jquery.validate.js
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
@@ -418,8 +418,8 @@
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
- Copyright (c) 2010, Sebastian Tschan
-
+ Copyright (c) 2010, Sebastian Tschan
+
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
@@ -427,10 +427,10 @@
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
@@ -438,14 +438,14 @@
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 Sebastian Tschan https://blueimp.net
- jquery.md5.js
+
+ from Sebastian Tschan https://blueimp.net
+ jquery.md5.js
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
- Copyright (c) 2006 Klaus Hartl (stilbuero.de)
-
+ Copyright (c) 2006 Klaus Hartl (stilbuero.de)
+
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
@@ -453,10 +453,10 @@
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
@@ -464,15 +464,15 @@
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 Klaus Hartl http://stilbuero.de
- jquery.cookies.js
+
+ from Klaus Hartl http://stilbuero.de
+ jquery.cookies.js
Within the ui/lib/flot directory
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
- Released under the MIT license by IOLA, December 2007.
-
+ Released under the MIT license by IOLA, December 2007.
+
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
@@ -480,10 +480,10 @@
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
@@ -491,24 +491,24 @@
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 IOLA http://www.iola.dk/
- jquery.flot.crosshair.js
- jquery.flot.fillbetween.js
- jquery.flot.image.js
- jquery.flot.js
- jquery.flot.navigate.js
- jquery.flot.resize.js
- jquery.flot.selection.js
- jquery.flot.stack.js
- jquery.flot.symbol.js
- jquery.flot.threshold.js
+
+ from IOLA http://www.iola.dk/
+ jquery.flot.crosshair.js
+ jquery.flot.fillbetween.js
+ jquery.flot.image.js
+ jquery.flot.js
+ jquery.flot.navigate.js
+ jquery.flot.resize.js
+ jquery.flot.selection.js
+ jquery.flot.stack.js
+ jquery.flot.symbol.js
+ jquery.flot.threshold.js
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
Created by Brian Medendorp, June 2009
- Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
-
+ Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
+
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
@@ -516,10 +516,10 @@
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
@@ -527,13 +527,13 @@
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 Brian Medendorp
- jquery.pie.js
+
+ from Brian Medendorp
+ jquery.pie.js
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
-
-
+
+
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
@@ -541,10 +541,10 @@
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
@@ -552,14 +552,14 @@
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 Ole Laursen
- jquery.colorhelpers.js
+
+ from Ole Laursen
+ jquery.colorhelpers.js
Within the ui/lib/jquery-ui directory
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
-
-
+
+
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
@@ -567,10 +567,10 @@
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
@@ -578,17 +578,17 @@
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 jQuery UI Developers http://jqueryui.com/about
- css/jquery-ui.css
- index.html
- js/jquery-ui.js
+
+ from jQuery UI Developers http://jqueryui.com/about
+ css/jquery-ui.css
+ index.html
+ js/jquery-ui.js
Within the ui/lib/qunit directory
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
- Copyright (c) 2012 John Resig, Jörn Zaefferer
-
+ Copyright (c) 2012 John Resig, Jörn Zaefferer
+
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
@@ -596,10 +596,10 @@
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
@@ -607,20 +607,20 @@
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 Jorn Zaefferer
+
+ from Jorn Zaefferer
qunit.css from http://docs.jquery.com/QUnit
qunit.js from http://docs.jquery.com/QUnit
Within the utils/src/main/java/com/cloud/utils/db directory
licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above)
Copyright (c) 2004 Clinton Begin
- from Clinton Begin http://code.google.com/p/mybatis/
+ from Clinton Begin http://code.google.com/p/mybatis/
ScriptRunner.java from http://code.google.com/p/mybatis/
Within the utils/src/main/java/org/apache/commons/httpclient/contrib/ssl directory
licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above)
Copyright (c) 2007 The Apache Software Foundation
- from The Apache Software Foundation http://www.apache.org/
- EasySSLProtocolSocketFactory.java
- EasyX509TrustManager.java
+ from The Apache Software Foundation http://www.apache.org/
+ EasySSLProtocolSocketFactory.java
+ EasyX509TrustManager.java
diff --git a/NOTICE b/NOTICE
index b19e4a4..8666be2 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,62 +1,62 @@
Apache CloudStack
Copyright 2014 The Apache Software Foundation
-
+
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
-
-
+
+
This distribution contains third party resources requiring the following notices:
-
- For
+
+ For
jquery.js
-
+
jQuery JavaScript Library v1.3.2
http://jquery.com/
-
+
Copyright (c) 2009 John Resig
Dual licensed under the MIT and GPL licenses.
http://docs.jquery.com/License
-
+
Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
Revision: 6246
-
- For
+
+ For
jquery.js
-
+
jQuery JavaScript Library v1.6.4
http://jquery.com/
-
+
Copyright 2011, John Resig
Dual licensed under the MIT or GPL Version 2 licenses.
http://jquery.org/license
-
+
Includes Sizzle.js
http://sizzlejs.com/
Copyright 2011, The Dojo Foundation
Released under the MIT, BSD, and GPL Licenses.
-
+
Date: Mon Sep 12 18:54:48 2011 -0400
-
- For
+
+ For
jquery.md5.js
-
+
jQuery MD5 Plugin 1.2.1
https://github.com/blueimp/jQuery-MD5
-
+
Copyright 2010, Sebastian Tschan
https://blueimp.net
-
+
Licensed under the MIT license:
http://creativecommons.org/licenses/MIT/
-
+
Based on
A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
Digest Algorithm, as defined in RFC 1321.
@@ -65,15 +65,15 @@
Distributed under the BSD License
See http://pajhome.org.uk/crypt/md5 for more info.
-
- For
+
+ For
jquery.colorhelpers.js
-
+
Plugin for jQuery for working with colors.
-
+
Version 1.1.
-
+
Inspiration from jQuery color animation plugin by John Resig.
-
+
Released under the MIT license by Ole Laursen, October 2009.
diff --git a/PRE-COMMIT.md b/PRE_COMMIT.md
similarity index 97%
rename from PRE-COMMIT.md
rename to PRE_COMMIT.md
index 9b76929..62dc296 100644
--- a/PRE-COMMIT.md
+++ b/PRE_COMMIT.md
@@ -20,7 +20,7 @@
# pre-commit
We run [pre-commit](https://pre-commit.com/) with
-[GitHub Actions](https://github.com/apache/cloudstack/blob/main/.github/workflows/linter.yml) so installation on your
+[GitHub Actions](https://github.com/apache/cloudstack/blob/main/.github/workflows/pre-commit.yml) so installation on your
local machine is currently optional.
The `pre-commit` [configuration file](https://github.com/apache/cloudstack/blob/main/.pre-commit-config.yaml)
diff --git a/README.md b/README.md
index a241319..a5aacb4 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,24 @@
[](https://cloudstack.apache.org/)
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+
+- [Who Uses CloudStack?](#who-uses-cloudstack)
+- [Demo](#demo)
+- [Getting Started](#getting-started)
+- [Getting Source Repository](#getting-source-repository)
+- [Documentation](#documentation)
+- [News and Events](#news-and-events)
+- [Getting Involved and Contributing](#getting-involved-and-contributing)
+- [Reporting Security Vulnerabilities](#reporting-security-vulnerabilities)
+- [License](#license)
+- [Notice of Cryptographic Software](#notice-of-cryptographic-software)
+- [Star History](#star-history)
+- [Contributors](#contributors)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
Apache CloudStack is open source software designed to deploy and manage large
networks of virtual machines, as a highly available, highly scalable
Infrastructure as a Service (IaaS) cloud computing platform. CloudStack is used
diff --git a/agent/pom.xml b/agent/pom.xml
index 4fa30e4..5ab6cfe 100644
--- a/agent/pom.xml
+++ b/agent/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/agent/src/main/java/com/cloud/agent/Agent.java b/agent/src/main/java/com/cloud/agent/Agent.java
index 52b1fe3..275fd41 100644
--- a/agent/src/main/java/com/cloud/agent/Agent.java
+++ b/agent/src/main/java/com/cloud/agent/Agent.java
@@ -1322,7 +1322,6 @@
processResponse((Response)request, task.getLink());
} else {
//put the requests from mgt server into another thread pool, as the request may take a longer time to finish. Don't block the NIO main thread pool
- //processRequest(request, task.getLink());
requestHandler.submit(new AgentRequestHandler(getType(), getLink(), request));
}
} catch (final ClassNotFoundException e) {
diff --git a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java
index 1561f0d..3364f97 100644
--- a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java
+++ b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java
@@ -117,7 +117,7 @@
/**
* Local storage path.<br>
- * This property allows multiple values to be entered in a single String. The differente values must be separated by commas.<br>
+ * This property allows multiple values to be entered in a single String. The different values must be separated by commas.<br>
* Data type: String.<br>
* Default value: <code>/var/lib/libvirt/images/</code>
*/
@@ -134,7 +134,7 @@
/**
* MANDATORY: The UUID for the local storage pool.<br>
- * This property allows multiple values to be entered in a single String. The differente values must be separated by commas.<br>
+ * This property allows multiple values to be entered in a single String. The different values must be separated by commas.<br>
* Data type: String.<br>
* Default value: <code>null</code>
*/
diff --git a/api/pom.xml b/api/pom.xml
index 4053654..c80c355 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/api/src/main/java/com/cloud/agent/api/storage/OVFHelper.java b/api/src/main/java/com/cloud/agent/api/storage/OVFHelper.java
index ccb5362..23167c5 100644
--- a/api/src/main/java/com/cloud/agent/api/storage/OVFHelper.java
+++ b/api/src/main/java/com/cloud/agent/api/storage/OVFHelper.java
@@ -119,8 +119,7 @@
boolean password = StringUtils.isNotBlank(passStr) && passStr.equalsIgnoreCase("true");
String label = ovfParser.getChildNodeValue(node, "Label");
String description = ovfParser.getChildNodeValue(node, "Description");
- logger.debug("Creating OVF property index " + index + (category == null ? "" : " for category " + category)
- + " with key = " + key);
+ logger.debug("Creating OVF property index {} {} with key = {}", index, (category == null ? "" : " for category " + category), key);
return new OVFPropertyTO(key, type, value, qualifiers, userConfigurable,
label, description, password, index, category);
}
@@ -152,7 +151,7 @@
if (child.getNodeName().equalsIgnoreCase("Category") ||
child.getNodeName().endsWith(":Category")) {
lastCategoryFound = child.getTextContent();
- logger.info("Category found " + lastCategoryFound);
+ logger.info("Category found {}", lastCategoryFound);
} else if (child.getNodeName().equalsIgnoreCase("Property") ||
child.getNodeName().endsWith(":Property")) {
OVFPropertyTO prop = createOVFPropertyFromNode(child, propertyIndex, lastCategoryFound);
@@ -250,13 +249,13 @@
int diskNumber = 0;
for (OVFVirtualHardwareItemTO diskItem : diskHardwareItems) {
if (StringUtils.isBlank(diskItem.getHostResource())) {
- logger.error("Missing disk information for hardware item " + diskItem.getElementName() + " " + diskItem.getInstanceId());
+ logger.error("Missing disk information for hardware item {} {}", diskItem.getElementName(), diskItem.getInstanceId());
continue;
}
String diskId = extractDiskIdFromDiskHostResource(diskItem.getHostResource());
OVFDisk diskDefinition = getDiskDefinitionFromDiskId(diskId, disks);
if (diskDefinition == null) {
- logger.error("Missing disk definition for disk ID " + diskId);
+ logger.error("Missing disk definition for disk ID {}", diskId);
}
OVFFile fileDefinition = getFileDefinitionFromDiskDefinition(diskDefinition._fileRef, files);
DatadiskTO datadiskTO = generateDiskTO(fileDefinition, diskDefinition, ovfParentPath, diskNumber, diskItem);
@@ -278,8 +277,8 @@
if (StringUtils.isNotBlank(path)) {
File f = new File(path);
if (!f.exists() || f.isDirectory()) {
- logger.error("One of the attached disk or ISO does not exists " + path);
- throw new InternalErrorException("One of the attached disk or ISO as stated on OVF does not exists " + path);
+ logger.error("One of the attached disk or ISOs does not exists {}", path);
+ throw new InternalErrorException("One of the attached disk or ISOs as stated on OVF does not exists " + path);
}
}
Long capacity = disk != null ? disk._capacity : file._size;
@@ -334,9 +333,7 @@
od._controller = getControllerType(items, od._diskId);
vd.add(od);
}
- if (logger.isTraceEnabled()) {
- logger.trace(String.format("Found %d disk definitions", vd.size()));
- }
+ logger.trace("Found {} disk definitions", vd.size());
return vd;
}
@@ -366,9 +363,7 @@
vf.add(of);
}
}
- if (logger.isTraceEnabled()) {
- logger.trace(String.format("Found %d file definitions in %s", vf.size(), ovfFile.getPath()));
- }
+ logger.trace("Found {} file definitions in {}", vf.size(), ovfFile.getPath());
return vf;
}
@@ -506,7 +501,7 @@
outfile.write(writer.toString());
outfile.close();
} catch (IOException | TransformerException e) {
- logger.info("Unexpected exception caught while rewriting OVF:" + e.getMessage(), e);
+ logger.info("Unexpected exception caught while rewriting OVF: {}", e.getMessage(), e);
throw new CloudRuntimeException(e);
}
}
@@ -522,9 +517,7 @@
public List<OVFNetworkTO> getNetPrerequisitesFromDocument(Document doc) throws InternalErrorException {
if (doc == null) {
- if (logger.isTraceEnabled()) {
- logger.trace("No document to parse; returning no prerequisite Networks");
- }
+ logger.trace("No document to parse; returning no prerequisite networks");
return Collections.emptyList();
}
@@ -540,9 +533,7 @@
private void matchNicsToNets(Map<String, OVFNetworkTO> nets, Node systemElement) {
final DocumentTraversal traversal = (DocumentTraversal) systemElement;
final NodeIterator iterator = traversal.createNodeIterator(systemElement, NodeFilter.SHOW_ELEMENT, null, true);
- if (logger.isTraceEnabled()) {
- logger.trace(String.format("Starting out with %d network-prerequisites, parsing hardware",nets.size()));
- }
+ logger.trace("Starting out with {} network-prerequisites, parsing hardware", nets.size());
int nicCount = 0;
for (Node n = iterator.nextNode(); n != null; n = iterator.nextNode()) {
final Element e = (Element) n;
@@ -550,9 +541,7 @@
nicCount++;
String name = e.getTextContent(); // should be in our nets
if(nets.get(name) == null) {
- if(logger.isInfoEnabled()) {
- logger.info(String.format("Found a NIC definition without a Network definition by name %s, adding it to the list.", name));
- }
+ logger.info("Found a NIC definition without a Network definition by name {}, adding it to the list.", name);
nets.put(name, new OVFNetworkTO());
}
OVFNetworkTO thisNet = nets.get(name);
@@ -561,9 +550,7 @@
}
}
}
- if (logger.isTraceEnabled()) {
- logger.trace(String.format("Ending up with %d network-prerequisites, parsed %d NICs", nets.size(), nicCount));
- }
+ logger.trace("Ending up with {} network-prerequisites, parsed {} nics", nets.size(), nicCount);
}
/**
@@ -585,7 +572,7 @@
int addressOnParent = Integer.parseInt(addressOnParentStr);
nic.setAddressOnParent(addressOnParent);
} catch (NumberFormatException e) {
- logger.warn("Encountered element of type \"AddressOnParent\", that could not be parse to an integer number: " + addressOnParentStr);
+ logger.warn("Encountered element of type \"AddressOnParent\", that could not be parse to an integer number: {}", addressOnParentStr);
}
boolean automaticAllocation = StringUtils.isNotBlank(automaticAllocationStr) && Boolean.parseBoolean(automaticAllocationStr);
@@ -597,7 +584,7 @@
int instanceId = Integer.parseInt(instanceIdStr);
nic.setInstanceID(instanceId);
} catch (NumberFormatException e) {
- logger.warn("Encountered element of type \"InstanceID\", that could not be parse to an integer number: " + instanceIdStr);
+ logger.warn("Encountered element of type \"InstanceID\", that could not be parse to an integer number: {}", instanceIdStr);
}
nic.setResourceSubType(resourceSubType);
@@ -630,9 +617,7 @@
nets.put(networkName,network);
}
- if (logger.isTraceEnabled()) {
- logger.trace(String.format("Found %d Networks in Template", nets.size()));
- }
+ logger.trace("Found {} Networks in Template", nets.size());
return nets;
}
@@ -771,7 +756,7 @@
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
- logger.debug("Could not parse the value: " + value + ", ignoring it");
+ logger.debug("Could not parse the value: {}, ignoring it", value);
}
}
return null;
@@ -782,7 +767,7 @@
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
- logger.debug("Could not parse the value: " + value + ", ignoring it");
+ logger.debug("Could not parse the value: {}, ignoring it", value);
}
}
return null;
@@ -820,7 +805,7 @@
try {
compressedLicense = compressOVFEula(eulaLicense);
} catch (IOException e) {
- logger.error("Could not compress the license for info " + eulaInfo);
+ logger.error("Could not compress the license for info {}", eulaInfo);
continue;
}
OVFEulaSectionTO eula = new OVFEulaSectionTO(eulaInfo, compressedLicense, eulaIndex);
diff --git a/api/src/main/java/com/cloud/agent/api/storage/OVFParser.java b/api/src/main/java/com/cloud/agent/api/storage/OVFParser.java
index 38f478d..316ab4e 100644
--- a/api/src/main/java/com/cloud/agent/api/storage/OVFParser.java
+++ b/api/src/main/java/com/cloud/agent/api/storage/OVFParser.java
@@ -54,7 +54,7 @@
documentBuilderFactory.setNamespaceAware(true);
documentBuilder = documentBuilderFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
- logger.error("Cannot start the OVF parser: " + e.getMessage(), e);
+ logger.error("Cannot start the OVF parser: {}", e.getMessage(), e);
}
}
@@ -70,7 +70,7 @@
try {
return documentBuilder.parse(new File(ovfFilePath));
} catch (SAXException | IOException e) {
- logger.error("Error parsing " + ovfFilePath + " " + e.getMessage(), e);
+ logger.error("Error parsing {} {}", ovfFilePath, e.getMessage(), e);
return null;
}
}
diff --git a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineMetadataTO.java b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineMetadataTO.java
new file mode 100644
index 0000000..5b22afd
--- /dev/null
+++ b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineMetadataTO.java
@@ -0,0 +1,182 @@
+// 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;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class VirtualMachineMetadataTO {
+ // VM details
+ private final String name;
+ private final String internalName;
+ private final String displayName;
+ private final String instanceUuid;
+ private final Integer cpuCores;
+ private final Integer memory;
+ private final Long created;
+ private final Long started;
+
+ // Owner details
+ private final String ownerDomainUuid;
+ private final String ownerDomainName;
+ private final String ownerAccountUuid;
+ private final String ownerAccountName;
+ private final String ownerProjectUuid;
+ private final String ownerProjectName;
+
+ // Host and service offering
+ private final String serviceOfferingName;
+ private final List<String> serviceOfferingHostTags;
+
+ // zone, pod, and cluster details
+ private final String zoneName;
+ private final String zoneUuid;
+ private final String podName;
+ private final String podUuid;
+ private final String clusterName;
+ private final String clusterUuid;
+
+ // resource tags
+ private final Map<String, String> resourceTags;
+
+ public VirtualMachineMetadataTO(
+ String name, String internalName, String displayName, String instanceUuid, Integer cpuCores, Integer memory, Long created, Long started,
+ String ownerDomainUuid, String ownerDomainName, String ownerAccountUuid, String ownerAccountName, String ownerProjectUuid, String ownerProjectName,
+ String serviceOfferingName, List<String> serviceOfferingHostTags,
+ String zoneName, String zoneUuid, String podName, String podUuid, String clusterName, String clusterUuid, Map<String, String> resourceTags) {
+ /*
+ * Something failed in the metadata shall not be a fatal error, the VM can still be started
+ * Thus, the unknown fields just get an explicit "unknown" value so it can be fixed in case
+ * there are bugs on some execution paths.
+ * */
+
+ this.name = (name != null) ? name : "unknown";
+ this.internalName = (internalName != null) ? internalName : "unknown";
+ this.displayName = (displayName != null) ? displayName : "unknown";
+ this.instanceUuid = (instanceUuid != null) ? instanceUuid : "unknown";
+ this.cpuCores = (cpuCores != null) ? cpuCores : -1;
+ this.memory = (memory != null) ? memory : -1;
+ this.created = (created != null) ? created : 0;
+ this.started = (started != null) ? started : 0;
+ this.ownerDomainUuid = (ownerDomainUuid != null) ? ownerDomainUuid : "unknown";
+ this.ownerDomainName = (ownerDomainName != null) ? ownerDomainName : "unknown";
+ this.ownerAccountUuid = (ownerAccountUuid != null) ? ownerAccountUuid : "unknown";
+ this.ownerAccountName = (ownerAccountName != null) ? ownerAccountName : "unknown";
+ this.ownerProjectUuid = (ownerProjectUuid != null) ? ownerProjectUuid : "unknown";
+ this.ownerProjectName = (ownerProjectName != null) ? ownerProjectName : "unknown";
+ this.serviceOfferingName = (serviceOfferingName != null) ? serviceOfferingName : "unknown";
+ this.serviceOfferingHostTags = (serviceOfferingHostTags != null) ? serviceOfferingHostTags : new ArrayList<>();
+ this.zoneName = (zoneName != null) ? zoneName : "unknown";
+ this.zoneUuid = (zoneUuid != null) ? zoneUuid : "unknown";
+ this.podName = (podName != null) ? podName : "unknown";
+ this.podUuid = (podUuid != null) ? podUuid : "unknown";
+ this.clusterName = (clusterName != null) ? clusterName : "unknown";
+ this.clusterUuid = (clusterUuid != null) ? clusterUuid : "unknown";
+
+ this.resourceTags = (resourceTags != null) ? resourceTags : new HashMap<>();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getInternalName() {
+ return internalName;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public String getInstanceUuid() {
+ return instanceUuid;
+ }
+
+ public Integer getCpuCores() {
+ return cpuCores;
+ }
+
+ public Integer getMemory() {
+ return memory;
+ }
+
+ public Long getCreated() { return created; }
+
+ public Long getStarted() {
+ return started;
+ }
+
+ public String getOwnerDomainUuid() {
+ return ownerDomainUuid;
+ }
+
+ public String getOwnerDomainName() {
+ return ownerDomainName;
+ }
+
+ public String getOwnerAccountUuid() {
+ return ownerAccountUuid;
+ }
+
+ public String getOwnerAccountName() {
+ return ownerAccountName;
+ }
+
+ public String getOwnerProjectUuid() {
+ return ownerProjectUuid;
+ }
+
+ public String getOwnerProjectName() {
+ return ownerProjectName;
+ }
+
+ public String getserviceOfferingName() {
+ return serviceOfferingName;
+ }
+
+ public List<String> getserviceOfferingHostTags() {
+ return serviceOfferingHostTags;
+ }
+
+ public String getZoneName() {
+ return zoneName;
+ }
+
+ public String getZoneUuid() {
+ return zoneUuid;
+ }
+
+ public String getPodName() {
+ return podName;
+ }
+
+ public String getPodUuid() {
+ return podUuid;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public String getClusterUuid() {
+ return clusterUuid;
+ }
+
+ public Map<String, String> getResourceTags() { return resourceTags; }
+}
diff --git a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
index cffb987..e26cc1e 100644
--- a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
+++ b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
@@ -89,6 +89,7 @@
private DeployAsIsInfoTO deployAsIsInfo;
private String metadataManufacturer;
private String metadataProductName;
+ private VirtualMachineMetadataTO metadata;
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) {
@@ -494,6 +495,14 @@
this.metadataProductName = metadataProductName;
}
+ public VirtualMachineMetadataTO getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(VirtualMachineMetadataTO metadata) {
+ this.metadata = metadata;
+ }
+
@Override
public String toString() {
return String.format("VM {id: \"%s\", name: \"%s\", uuid: \"%s\", type: \"%s\"}", id, name, uuid, type);
diff --git a/api/src/main/java/com/cloud/cpu/CPU.java b/api/src/main/java/com/cloud/cpu/CPU.java
index 3016e54..11b38b7 100644
--- a/api/src/main/java/com/cloud/cpu/CPU.java
+++ b/api/src/main/java/com/cloud/cpu/CPU.java
@@ -22,7 +22,8 @@
public enum CPUArch {
x86("i686", 32),
amd64("x86_64", 64),
- arm64("aarch64", 64);
+ arm64("aarch64", 64),
+ s390x("s390x", 64);
private final String type;
private final int bits;
diff --git a/api/src/main/java/com/cloud/deploy/DeploymentClusterPlanner.java b/api/src/main/java/com/cloud/deploy/DeploymentClusterPlanner.java
index d127e4b..9471c3d 100644
--- a/api/src/main/java/com/cloud/deploy/DeploymentClusterPlanner.java
+++ b/api/src/main/java/com/cloud/deploy/DeploymentClusterPlanner.java
@@ -62,11 +62,11 @@
"vm.allocation.algorithm",
"Advanced",
"random",
- "Order in which hosts within a cluster will be considered for VM allocation. The value can be 'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit', or 'firstfitleastconsumed'.",
+ "Order in which hosts within a cluster will be considered for VM allocation. The value can be 'random', 'firstfit', 'userdispersing', or 'firstfitleastconsumed'.",
true,
ConfigKey.Scope.Global, null, null, null, null, null,
ConfigKey.Kind.Select,
- "random,firstfit,userdispersing,userconcentratedpod_random,userconcentratedpod_firstfit,firstfitleastconsumed");
+ "random,firstfit,userdispersing,firstfitleastconsumed");
/**
* This is called to determine list of possible clusters where a virtual
diff --git a/api/src/main/java/com/cloud/deploy/DeploymentPlanner.java b/api/src/main/java/com/cloud/deploy/DeploymentPlanner.java
index 354f9cf..8f7e773 100644
--- a/api/src/main/java/com/cloud/deploy/DeploymentPlanner.java
+++ b/api/src/main/java/com/cloud/deploy/DeploymentPlanner.java
@@ -70,7 +70,7 @@
boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid);
public enum AllocationAlgorithm {
- random, firstfit, userdispersing, userconcentratedpod_random, userconcentratedpod_firstfit;
+ random, firstfit, userdispersing;
}
public enum PlannerResourceUsage {
diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java
index 6fa6a06..889e821 100644
--- a/api/src/main/java/com/cloud/event/EventTypes.java
+++ b/api/src/main/java/com/cloud/event/EventTypes.java
@@ -503,6 +503,7 @@
public static final String EVENT_S2S_VPN_CUSTOMER_GATEWAY_CREATE = "VPN.S2S.CUSTOMER.GATEWAY.CREATE";
public static final String EVENT_S2S_VPN_CUSTOMER_GATEWAY_DELETE = "VPN.S2S.CUSTOMER.GATEWAY.DELETE";
public static final String EVENT_S2S_VPN_CUSTOMER_GATEWAY_UPDATE = "VPN.S2S.CUSTOMER.GATEWAY.UPDATE";
+ public static final String EVENT_S2S_VPN_GATEWAY_OBSOLETE_PARAMS = "VPN.S2S.GATEWAY.OBSOLETE.PARAMS";
public static final String EVENT_S2S_VPN_CONNECTION_CREATE = "VPN.S2S.CONNECTION.CREATE";
public static final String EVENT_S2S_VPN_CONNECTION_DELETE = "VPN.S2S.CONNECTION.DELETE";
public static final String EVENT_S2S_VPN_CONNECTION_RESET = "VPN.S2S.CONNECTION.RESET";
@@ -1152,6 +1153,7 @@
entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_CREATE, Site2SiteCustomerGateway.class);
entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_DELETE, Site2SiteCustomerGateway.class);
entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_UPDATE, Site2SiteCustomerGateway.class);
+ entityEventDetails.put(EVENT_S2S_VPN_GATEWAY_OBSOLETE_PARAMS, Site2SiteCustomerGateway.class);
entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_CREATE, Site2SiteVpnConnection.class);
entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_DELETE, Site2SiteVpnConnection.class);
entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_RESET, Site2SiteVpnConnection.class);
diff --git a/api/src/main/java/com/cloud/host/HostStats.java b/api/src/main/java/com/cloud/host/HostStats.java
index d147944..0e72b5f 100644
--- a/api/src/main/java/com/cloud/host/HostStats.java
+++ b/api/src/main/java/com/cloud/host/HostStats.java
@@ -36,5 +36,4 @@
public HostStats getHostStats();
public double getLoadAverage();
- // public double getXapiMemoryUsageKBs();
}
diff --git a/api/src/main/java/com/cloud/network/PhysicalNetworkTrafficType.java b/api/src/main/java/com/cloud/network/PhysicalNetworkTrafficType.java
index 9676bad..d3804cd 100644
--- a/api/src/main/java/com/cloud/network/PhysicalNetworkTrafficType.java
+++ b/api/src/main/java/com/cloud/network/PhysicalNetworkTrafficType.java
@@ -41,4 +41,6 @@
String getHypervNetworkLabel();
String getOvm3NetworkLabel();
+
+ String getVlan();
}
diff --git a/api/src/main/java/com/cloud/network/rules/LbStickinessMethod.java b/api/src/main/java/com/cloud/network/rules/LbStickinessMethod.java
index 56a0622..5143611 100644
--- a/api/src/main/java/com/cloud/network/rules/LbStickinessMethod.java
+++ b/api/src/main/java/com/cloud/network/rules/LbStickinessMethod.java
@@ -108,8 +108,7 @@
}
public void addParam(String name, Boolean required, String description, Boolean isFlag) {
- /* FIXME : UI is breaking if the capability string length is larger , temporarily description is commented out */
- // LbStickinessMethodParam param = new LbStickinessMethodParam(name, required, description);
+ /* is this still a valid comment: FIXME : UI is breaking if the capability string length is larger , temporarily description is commented out */
LbStickinessMethodParam param = new LbStickinessMethodParam(name, required, " ", isFlag);
_paramList.add(param);
return;
@@ -133,7 +132,6 @@
public void setDescription(String description) {
/* FIXME : UI is breaking if the capability string length is larger , temporarily description is commented out */
- //this.description = description;
this._description = " ";
}
}
diff --git a/api/src/main/java/com/cloud/server/ResourceTag.java b/api/src/main/java/com/cloud/server/ResourceTag.java
index b3026de..3230575 100644
--- a/api/src/main/java/com/cloud/server/ResourceTag.java
+++ b/api/src/main/java/com/cloud/server/ResourceTag.java
@@ -16,14 +16,14 @@
// under the License.
package com.cloud.server;
-import org.apache.cloudstack.acl.ControlledEntity;
-import org.apache.cloudstack.api.Identity;
-import org.apache.cloudstack.api.InternalIdentity;
-
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
public interface ResourceTag extends ControlledEntity, Identity, InternalIdentity {
// FIXME - extract enum to another interface as its used both by resourceTags and resourceMetaData code
@@ -70,7 +70,7 @@
GuestOs(false, true),
NetworkOffering(false, true),
VpcOffering(true, false),
- Domain(false, false, true),
+ Domain(true, false, true),
ObjectStore(false, false, true);
diff --git a/api/src/main/java/com/cloud/storage/Storage.java b/api/src/main/java/com/cloud/storage/Storage.java
index 1ad3731..5b3e976 100644
--- a/api/src/main/java/com/cloud/storage/Storage.java
+++ b/api/src/main/java/com/cloud/storage/Storage.java
@@ -128,7 +128,7 @@
public static enum TemplateType {
ROUTING, // Router template
SYSTEM, /* routing, system vm template */
- BUILTIN, /* buildin template */
+ BUILTIN, /* builtin template */
PERHOST, /* every host has this template, don't need to install it in secondary storage */
USER, /* User supplied template/iso */
VNF, /* VNFs (virtual network functions) template */
diff --git a/api/src/main/java/com/cloud/storage/VolumeApiService.java b/api/src/main/java/com/cloud/storage/VolumeApiService.java
index 19c2ebe..1a9bcc6 100644
--- a/api/src/main/java/com/cloud/storage/VolumeApiService.java
+++ b/api/src/main/java/com/cloud/storage/VolumeApiService.java
@@ -56,9 +56,9 @@
Boolean.class,
"use.https.to.upload",
"true",
- "Determines the protocol (HTTPS or HTTP) ACS will use to generate links to upload ISOs, volumes, and templates. When set as 'true', ACS will use protocol HTTPS, otherwise, it will use protocol HTTP. Default value is 'true'.",
+ "Controls whether upload links for ISOs, volumes, and templates use HTTPS (true, default) or HTTP (false). After changing this setting, the Secondary Storage VM (SSVM) must be recreated",
true,
- ConfigKey.Scope.StoragePool);
+ ConfigKey.Scope.Zone);
/**
* Creates the database object for a volume based on the given criteria
diff --git a/api/src/main/java/com/cloud/user/AccountService.java b/api/src/main/java/com/cloud/user/AccountService.java
index 09fe5ff..b92654b 100644
--- a/api/src/main/java/com/cloud/user/AccountService.java
+++ b/api/src/main/java/com/cloud/user/AccountService.java
@@ -36,6 +36,7 @@
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import org.apache.cloudstack.auth.UserTwoFactorAuthenticator;
+import org.apache.cloudstack.backup.BackupOffering;
public interface AccountService {
@@ -115,13 +116,15 @@
void checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException;
+ void checkAccess(Account account, BackupOffering bof) throws PermissionDeniedException;
+
void checkAccess(User user, ControlledEntity entity);
void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName, ControlledEntity... entities) throws PermissionDeniedException;
void validateAccountHasAccessToResource(Account account, AccessType accessType, Object resource);
- Long finalyzeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly);
+ Long finalizeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly);
/**
* returns the user account object for a given user id
diff --git a/api/src/main/java/org/apache/cloudstack/acl/RoleType.java b/api/src/main/java/org/apache/cloudstack/acl/RoleType.java
index c721d52..c33488c 100644
--- a/api/src/main/java/org/apache/cloudstack/acl/RoleType.java
+++ b/api/src/main/java/org/apache/cloudstack/acl/RoleType.java
@@ -132,10 +132,10 @@
* */
public static Account.Type getAccountTypeByRole(final Role role, final Account.Type defautAccountType) {
if (role != null) {
- LOGGER.debug(String.format("Role [%s] is not null; therefore, we use its Account type [%s].", role, defautAccountType));
+ LOGGER.debug("Role [{}] is not null; therefore, we use its Account type [{}].", role, defautAccountType);
return role.getRoleType().getAccountType();
}
- LOGGER.debug(String.format("Role is null; therefore, we use the default Account type [%s] value.", defautAccountType));
+ LOGGER.debug("Role is null; therefore, we use the default Account type [{}] value.", defautAccountType);
return defautAccountType;
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/acl/SecurityChecker.java b/api/src/main/java/org/apache/cloudstack/acl/SecurityChecker.java
index 82a8ec5..fa17df7 100644
--- a/api/src/main/java/org/apache/cloudstack/acl/SecurityChecker.java
+++ b/api/src/main/java/org/apache/cloudstack/acl/SecurityChecker.java
@@ -27,6 +27,8 @@
import com.cloud.user.User;
import com.cloud.utils.component.Adapter;
+import org.apache.cloudstack.backup.BackupOffering;
+
/**
* SecurityChecker checks the ownership and access control to objects within
*/
@@ -145,4 +147,6 @@
boolean checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException;
boolean checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException;
+
+ boolean checkAccess(Account account, BackupOffering bof) throws PermissionDeniedException;
}
diff --git a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java
index 1422322..fcc8790 100644
--- a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java
+++ b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java
@@ -24,18 +24,24 @@
public interface AlertService {
public static class AlertType {
- private static Set<AlertType> defaultAlertTypes = new HashSet<AlertType>();
+ private static final Set<AlertType> defaultAlertTypes = new HashSet<>();
private final String name;
private final short type;
+ private final boolean repetitionAllowed;
- private AlertType(short type, String name, boolean isDefault) {
+ private AlertType(short type, String name, boolean isDefault, boolean repetitionAllowed) {
this.name = name;
this.type = type;
+ this.repetitionAllowed = repetitionAllowed;
if (isDefault) {
defaultAlertTypes.add(this);
}
}
+ private AlertType(short type, String name, boolean isDefault) {
+ this(type, name, isDefault, false);
+ }
+
public static final AlertType ALERT_TYPE_MEMORY = new AlertType(Capacity.CAPACITY_TYPE_MEMORY, "ALERT.MEMORY", true);
public static final AlertType ALERT_TYPE_CPU = new AlertType(Capacity.CAPACITY_TYPE_CPU, "ALERT.CPU", true);
public static final AlertType ALERT_TYPE_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_STORAGE, "ALERT.STORAGE", true);
@@ -45,35 +51,36 @@
public static final AlertType ALERT_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET = new AlertType(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, "ALERT.NETWORK.IPV6SUBNET", true);
public static final AlertType ALERT_TYPE_PRIVATE_IP = new AlertType(Capacity.CAPACITY_TYPE_PRIVATE_IP, "ALERT.NETWORK.PRIVATEIP", true);
public static final AlertType ALERT_TYPE_SECONDARY_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE, "ALERT.STORAGE.SECONDARY", true);
- public static final AlertType ALERT_TYPE_HOST = new AlertType((short)7, "ALERT.COMPUTE.HOST", true);
- public static final AlertType ALERT_TYPE_USERVM = new AlertType((short)8, "ALERT.USERVM", true);
- public static final AlertType ALERT_TYPE_DOMAIN_ROUTER = new AlertType((short)9, "ALERT.SERVICE.DOMAINROUTER", true);
- public static final AlertType ALERT_TYPE_CONSOLE_PROXY = new AlertType((short)10, "ALERT.SERVICE.CONSOLEPROXY", true);
+ public static final AlertType ALERT_TYPE_HOST = new AlertType((short)7, "ALERT.COMPUTE.HOST", true, true);
+ public static final AlertType ALERT_TYPE_USERVM = new AlertType((short)8, "ALERT.USERVM", true, true);
+ public static final AlertType ALERT_TYPE_DOMAIN_ROUTER = new AlertType((short)9, "ALERT.SERVICE.DOMAINROUTER", true, true);
+ public static final AlertType ALERT_TYPE_CONSOLE_PROXY = new AlertType((short)10, "ALERT.SERVICE.CONSOLEPROXY", true, true);
public static final AlertType ALERT_TYPE_ROUTING = new AlertType((short)11, "ALERT.NETWORK.ROUTING", true);
- public static final AlertType ALERT_TYPE_STORAGE_MISC = new AlertType((short)12, "ALERT.STORAGE.MISC", true);
+ public static final AlertType ALERT_TYPE_STORAGE_MISC = new AlertType((short)12, "ALERT.STORAGE.MISC", true, true);
public static final AlertType ALERT_TYPE_USAGE_SERVER = new AlertType((short)13, "ALERT.USAGE", true);
- public static final AlertType ALERT_TYPE_MANAGEMENT_NODE = new AlertType((short)14, "ALERT.MANAGEMENT", true);
+ public static final AlertType ALERT_TYPE_MANAGEMENT_NODE = new AlertType((short)14, "ALERT.MANAGEMENT", true, true);
public static final AlertType ALERT_TYPE_DOMAIN_ROUTER_MIGRATE = new AlertType((short)15, "ALERT.NETWORK.DOMAINROUTERMIGRATE", true);
public static final AlertType ALERT_TYPE_CONSOLE_PROXY_MIGRATE = new AlertType((short)16, "ALERT.SERVICE.CONSOLEPROXYMIGRATE", true);
public static final AlertType ALERT_TYPE_USERVM_MIGRATE = new AlertType((short)17, "ALERT.USERVM.MIGRATE", true);
public static final AlertType ALERT_TYPE_VLAN = new AlertType((short)18, "ALERT.NETWORK.VLAN", true);
- public static final AlertType ALERT_TYPE_SSVM = new AlertType((short)19, "ALERT.SERVICE.SSVM", true);
+ public static final AlertType ALERT_TYPE_SSVM = new AlertType((short)19, "ALERT.SERVICE.SSVM", true, true);
public static final AlertType ALERT_TYPE_USAGE_SERVER_RESULT = new AlertType((short)20, "ALERT.USAGE.RESULT", true);
public static final AlertType ALERT_TYPE_STORAGE_DELETE = new AlertType((short)21, "ALERT.STORAGE.DELETE", true);
public static final AlertType ALERT_TYPE_UPDATE_RESOURCE_COUNT = new AlertType((short)22, "ALERT.RESOURCE.COUNT", true);
public static final AlertType ALERT_TYPE_USAGE_SANITY_RESULT = new AlertType((short)23, "ALERT.USAGE.SANITY", true);
public static final AlertType ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP = new AlertType((short)24, "ALERT.NETWORK.DIRECTPUBLICIP", true);
public static final AlertType ALERT_TYPE_LOCAL_STORAGE = new AlertType((short)25, "ALERT.STORAGE.LOCAL", true);
- public static final AlertType ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = new AlertType((short)26, "ALERT.RESOURCE.EXCEED", true);
+ public static final AlertType ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = new AlertType((short)26, "ALERT.RESOURCE.EXCEED", true, true);
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 static final AlertType ALERT_TYPE_UPLOAD_FAILED = new AlertType((short)28, "ALERT.UPLOAD.FAILED", true, true);
+ public static final AlertType ALERT_TYPE_OOBM_AUTH_ERROR = new AlertType((short)29, "ALERT.OOBM.AUTHERROR", true, true);
+ public static final AlertType ALERT_TYPE_HA_ACTION = new AlertType((short)30, "ALERT.HA.ACTION", true, true);
+ public static final AlertType ALERT_TYPE_CA_CERT = new AlertType((short)31, "ALERT.CA.CERT", true, true);
public static final AlertType ALERT_TYPE_VM_SNAPSHOT = new AlertType((short)32, "ALERT.VM.SNAPSHOT", true);
public static final AlertType ALERT_TYPE_VR_PUBLIC_IFACE_MTU = new AlertType((short)33, "ALERT.VR.PUBLIC.IFACE.MTU", true);
public static final AlertType ALERT_TYPE_VR_PRIVATE_IFACE_MTU = new AlertType((short)34, "ALERT.VR.PRIVATE.IFACE.MTU", true);
- public static final AlertType ALERT_TYPE_EXTENSION_PATH_NOT_READY = new AlertType((short)33, "ALERT.TYPE.EXTENSION.PATH.NOT.READY", true);
+ public static final AlertType ALERT_TYPE_EXTENSION_PATH_NOT_READY = new AlertType((short)33, "ALERT.TYPE.EXTENSION.PATH.NOT.READY", true, true);
+ public static final AlertType ALERT_TYPE_VPN_GATEWAY_OBSOLETE_PARAMETERS = new AlertType((short)34, "ALERT.S2S.VPN.GATEWAY.OBSOLETE.PARAMETERS", true, true);
public static final AlertType ALERT_TYPE_BACKUP_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_BACKUP_STORAGE, "ALERT.STORAGE.BACKUP", true);
public static final AlertType ALERT_TYPE_OBJECT_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_OBJECT_STORAGE, "ALERT.STORAGE.OBJECT", true);
@@ -85,6 +92,10 @@
return name;
}
+ public boolean isRepetitionAllowed() {
+ return repetitionAllowed;
+ }
+
private static AlertType getAlertType(short type) {
for (AlertType alertType : defaultAlertTypes) {
if (alertType.getType() == type) {
@@ -108,7 +119,7 @@
if (defaultAlert != null && !defaultAlert.getName().equalsIgnoreCase(name)) {
throw new InvalidParameterValueException("There is a default alert having type " + type + " and name " + defaultAlert.getName());
} else {
- return new AlertType(type, name, false);
+ return new AlertType(type, name, false, false);
}
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/APICommand.java b/api/src/main/java/org/apache/cloudstack/api/APICommand.java
index c559be0..b776490 100644
--- a/api/src/main/java/org/apache/cloudstack/api/APICommand.java
+++ b/api/src/main/java/org/apache/cloudstack/api/APICommand.java
@@ -50,4 +50,6 @@
RoleType[] authorized() default {};
Class<?>[] entityType() default {};
+
+ String httpMethod() default "";
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index 944b111..1ab6fba 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -282,6 +282,7 @@
public static final String HOST = "host";
public static final String HOST_CONTROL_STATE = "hostcontrolstate";
public static final String HOSTS_MAP = "hostsmap";
+ public static final String HTTP_REQUEST_TYPE = "httprequesttype";
public static final String HYPERVISOR = "hypervisor";
public static final String INLINE = "inline";
public static final String INSTANCE = "instance";
@@ -375,6 +376,7 @@
public static final String MAC_ADDRESS = "macaddress";
public static final String MAC_ADDRESSES = "macaddresses";
public static final String MANUAL_UPGRADE = "manualupgrade";
+ public static final String MATCH_TYPE = "matchtype";
public static final String MAX = "max";
public static final String MAX_SNAPS = "maxsnaps";
public static final String MAX_BACKUPS = "maxbackups";
@@ -501,6 +503,7 @@
public static final String RECONNECT = "reconnect";
public static final String RECOVER = "recover";
public static final String REPAIR = "repair";
+ public static final String REPETITION_ALLOWED = "repetitionallowed";
public static final String REQUIRES_HVM = "requireshvm";
public static final String RESOURCES = "resources";
public static final String RESOURCE_COUNT = "resourcecount";
@@ -1165,6 +1168,7 @@
public static final String OVM3_VIP = "ovm3vip";
public static final String CLEAN_UP_DETAILS = "cleanupdetails";
public static final String CLEAN_UP_EXTERNAL_DETAILS = "cleanupexternaldetails";
+ public static final String CLEAN_UP_EXTRA_CONFIG = "cleanupextraconfig";
public static final String CLEAN_UP_PARAMETERS = "cleanupparameters";
public static final String VIRTUAL_SIZE = "virtualsize";
public static final String NETSCALER_CONTROLCENTER_ID = "netscalercontrolcenterid";
@@ -1364,6 +1368,10 @@
public static final String RECURSIVE_DOMAINS = "recursivedomains";
+ public static final String VPN_CUSTOMER_GATEWAY_PARAMETERS = "vpncustomergatewayparameters";
+ public static final String OBSOLETE_PARAMETERS = "obsoleteparameters";
+ public static final String EXCLUDED_PARAMETERS = "excludedparameters";
+
/**
* This enum specifies IO Drivers, each option controls specific policies on I/O.
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseBackupListCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseBackupListCmd.java
index 0aa8366..2a64a1f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/BaseBackupListCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/BaseBackupListCmd.java
@@ -25,7 +25,7 @@
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.context.CallContext;
-public abstract class BaseBackupListCmd extends BaseListCmd {
+public abstract class BaseBackupListCmd extends BaseListAccountResourcesCmd {
protected void setupResponseBackupOfferingsList(final List<BackupOffering> offerings, final Integer count) {
final ListResponse<BackupOfferingResponse> response = new ListResponse<>();
diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java
index 8f47d51..a4de301 100644
--- a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java
@@ -382,7 +382,7 @@
if (roleIsAllowed) {
validFields.add(field);
} else {
- logger.debug("Ignoring parameter " + parameterAnnotation.name() + " as the caller is not authorized to pass it in");
+ logger.debug("Ignoring parameter {} as the caller is not authorized to pass it in", parameterAnnotation.name());
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
index f0a82cc..6da9db5 100644
--- a/api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
@@ -84,7 +84,7 @@
private Boolean cleanupDetails;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the template/ISO. Valid options are: x86_64, aarch64",
+ description = "the CPU arch of the template/ISO. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/autoscale/DeleteCounterCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/autoscale/DeleteCounterCmd.java
index fb0c960..769f6fd 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/autoscale/DeleteCounterCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/autoscale/DeleteCounterCmd.java
@@ -61,7 +61,7 @@
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
- logger.warn("Failed to delete counter with Id: " + getId());
+ logger.warn("Failed to delete counter with Id: {}", getId());
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete counter.");
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ImportBackupOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ImportBackupOfferingCmd.java
index 2e73698..5e70258 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ImportBackupOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ImportBackupOfferingCmd.java
@@ -27,6 +27,7 @@
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
+import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupOffering;
@@ -40,6 +41,11 @@
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
@APICommand(name = "importBackupOffering",
description = "Imports a backup offering using a backup provider",
@@ -76,6 +82,13 @@
description = "Whether users are allowed to create adhoc backups and backup schedules", required = true)
private Boolean userDrivenBackups;
+ @Parameter(name = ApiConstants.DOMAIN_ID,
+ type = CommandType.LIST,
+ collectionType = CommandType.UUID,
+ entityType = DomainResponse.class,
+ description = "the ID of the containing domain(s), null for public offerings")
+ private List<Long> domainIds;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -100,6 +113,15 @@
return userDrivenBackups == null ? false : userDrivenBackups;
}
+ public List<Long> getDomainIds() {
+ if (CollectionUtils.isNotEmpty(domainIds)) {
+ Set<Long> set = new LinkedHashSet<>(domainIds);
+ domainIds.clear();
+ domainIds.addAll(set);
+ }
+ return domainIds;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/UpdateBackupOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/UpdateBackupOfferingCmd.java
index 9de0671..2f0dd6a 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/UpdateBackupOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/UpdateBackupOfferingCmd.java
@@ -25,19 +25,24 @@
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.utils.exception.CloudRuntimeException;
+import java.util.List;
+import java.util.function.LongFunction;
+
@APICommand(name = "updateBackupOffering", description = "Updates a backup offering.", responseObject = BackupOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.16.0")
-public class UpdateBackupOfferingCmd extends BaseCmd {
+public class UpdateBackupOfferingCmd extends BaseCmd implements DomainAndZoneIdResolver {
@Inject
private BackupManager backupManager;
@@ -57,6 +62,13 @@
@Parameter(name = ApiConstants.ALLOW_USER_DRIVEN_BACKUPS, type = CommandType.BOOLEAN, description = "Whether to allow user driven backups or not")
private Boolean allowUserDrivenBackups;
+ @Parameter(name = ApiConstants.DOMAIN_ID,
+ type = CommandType.STRING,
+ description = "the ID of the containing domain(s) as comma separated string, public for public offerings",
+ since = "4.23.0",
+ length = 4096)
+ private String domainIds;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -82,7 +94,7 @@
@Override
public void execute() {
try {
- if (StringUtils.isAllEmpty(getName(), getDescription()) && getAllowUserDrivenBackups() == null) {
+ if (StringUtils.isAllEmpty(getName(), getDescription()) && getAllowUserDrivenBackups() == null && CollectionUtils.isEmpty(getDomainIds())) {
throw new InvalidParameterValueException(String.format("Can't update Backup Offering [id: %s] because there are no parameters to be updated, at least one of the",
"following should be informed: name, description or allowUserDrivenBackups.", id));
}
@@ -98,11 +110,23 @@
this.setResponseObject(response);
} catch (CloudRuntimeException e) {
ApiErrorCode paramError = e instanceof InvalidParameterValueException ? ApiErrorCode.PARAM_ERROR : ApiErrorCode.INTERNAL_ERROR;
- logger.error(String.format("Failed to update Backup Offering [id: %s] due to: [%s].", id, e.getMessage()), e);
+ logger.error("Failed to update Backup Offering [id: {}] due to: [{}].", id, e.getMessage(), e);
throw new ServerApiException(paramError, e.getMessage());
}
}
+ public List<Long> getDomainIds() {
+ // backupManager may be null in unit tests where the command is spied without injection.
+ // Avoid creating a method reference to a null receiver which causes NPE. When backupManager
+ // is null, pass null as the defaultDomainsProvider so resolveDomainIds will simply return
+ // an empty list or parse the explicit domainIds string.
+ LongFunction<List<Long>> defaultDomainsProvider = null;
+ if (backupManager != null) {
+ defaultDomainsProvider = backupManager::getBackupOfferingDomains;
+ }
+ return resolveDomainIds(domainIds, id, defaultDomainsProvider, "backup offering");
+ }
+
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java
index 5d1c1f8..d8fa212 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java
@@ -69,7 +69,7 @@
private String hypervisor;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "The CPU arch of the cluster. Valid options are: x86_64, aarch64",
+ description = "The CPU arch of the cluster. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java
index 2e7cb21..77d0557 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java
@@ -58,7 +58,7 @@
private String managedState;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the cluster. Valid options are: x86_64, aarch64",
+ description = "the CPU arch of the cluster. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
index 2fad8d7..97dee8f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
@@ -150,7 +150,7 @@
ConfigurationResponse response = _responseGenerator.createConfigurationResponse(cfg);
response.setResponseName(getCommandName());
response = setResponseScopes(response);
- response = setResponseValue(response, cfg);
+ setResponseValue(response, cfg);
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update config");
@@ -161,15 +161,13 @@
* Sets the configuration value in the response. If the configuration is in the `Hidden` or `Secure` categories, the value is encrypted before being set in the response.
* @param response to be set with the configuration `cfg` value
* @param cfg to be used in setting the response value
- * @return the response with the configuration's value
*/
- public ConfigurationResponse setResponseValue(ConfigurationResponse response, Configuration cfg) {
+ public void setResponseValue(ConfigurationResponse response, Configuration cfg) {
+ String value = cfg.getValue();
if (cfg.isEncrypted()) {
- response.setValue(DBEncryptionUtil.encrypt(getValue()));
- } else {
- response.setValue(getValue());
+ value = DBEncryptionUtil.encrypt(value);
}
- return response;
+ response.setValue(value);
}
/**
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificateCmd.java
index 780198d..ad44037 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificateCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/direct/download/UploadTemplateDirectDownloadCertificateCmd.java
@@ -95,7 +95,7 @@
}
try {
- logger.debug("Uploading certificate " + name + " to agents for Direct Download");
+ logger.debug("Uploading certificate {} to agents for Direct Download", name);
Pair<DirectDownloadCertificate, List<HostCertificateStatus>> uploadStatus =
directDownloadManager.uploadCertificateToHosts(certificate, name, hypervisor, zoneId, hostId);
DirectDownloadCertificate certificate = uploadStatus.first();
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/domain/ListDomainsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/domain/ListDomainsCmd.java
index 5c5a92c..aa19780 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/domain/ListDomainsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/domain/ListDomainsCmd.java
@@ -23,7 +23,7 @@
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.BaseListTaggedResourcesCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject.ResponseView;
import org.apache.cloudstack.api.command.user.UserCmd;
@@ -39,7 +39,7 @@
@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)
-public class ListDomainsCmd extends BaseListCmd implements UserCmd {
+public class ListDomainsCmd extends BaseListTaggedResourcesCmd implements UserCmd {
private static final String s_name = "listdomainsresponse";
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
index 82699b4..c085abd 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
@@ -147,7 +147,7 @@
this.setResponseObject(hostResponse);
} catch (Exception e) {
Host host = _entityMgr.findById(Host.class, getId());
- logger.debug("Failed to update host: {} with id {}", host, getId(), e);
+ logger.error("Failed to update {}", host, e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to update host: %s with id %d, %s", host, getId(), e.getMessage()));
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/iso/ListIsoPermissionsCmdByAdmin.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/iso/ListIsoPermissionsCmdByAdmin.java
index c4b9db3..b831a99 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/iso/ListIsoPermissionsCmdByAdmin.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/iso/ListIsoPermissionsCmdByAdmin.java
@@ -1,4 +1,4 @@
-// Licensedname = "listIsoPermissions", to the Apache Software Foundation (ASF) under one
+// 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
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java
index 41cf5e5..5b50c90 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java
@@ -116,7 +116,7 @@
logger.warn("Exception: ", ex);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
} catch (Exception e) {
- logger.warn("Failed to delete management ip range from " + getStartIp() + " to " + getEndIp() + " of Pod: " + getPodId(), e);
+ logger.warn("Failed to delete management ip range from {} to {} of Pod: {}", getStartIp(), getEndIp(), getPodId(), e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteStorageNetworkIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteStorageNetworkIpRangeCmd.java
index d12135c..4ffe583 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteStorageNetworkIpRangeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteStorageNetworkIpRangeCmd.java
@@ -75,7 +75,7 @@
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} catch (Exception e) {
- logger.warn("Failed to delete storage network ip range " + getId(), e);
+ logger.warn("Failed to delete storage network ip range {}", getId(), e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/ListStorageNetworkIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/ListStorageNetworkIpRangeCmd.java
index c269be9..3e32bed 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/ListStorageNetworkIpRangeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/ListStorageNetworkIpRangeCmd.java
@@ -97,7 +97,7 @@
response.setResponseName(getCommandName());
this.setResponseObject(response);
} catch (Exception e) {
- logger.warn("Failed to list storage Network IP range for rangeId=" + getRangeId() + " podId=" + getPodId() + " zoneId=" + getZoneId());
+ logger.warn("Failed to list storage Network IP range for rangeId={} podId={} zoneId={}", getRangeId(), getPodId(), getZoneId());
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java
index 8910966..df9f6ad 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java
@@ -16,7 +16,6 @@
// under the License.
package org.apache.cloudstack.api.command.admin.network;
-import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.api.APICommand;
@@ -26,18 +25,16 @@
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
import org.apache.cloudstack.api.response.NetworkOfferingResponse;
-import org.apache.commons.lang3.StringUtils;
-import com.cloud.dc.DataCenter;
-import com.cloud.domain.Domain;
-import com.cloud.exception.InvalidParameterValueException;
+
import com.cloud.offering.NetworkOffering;
import com.cloud.user.Account;
@APICommand(name = "updateNetworkOffering", description = "Updates a network offering.", responseObject = NetworkOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
-public class UpdateNetworkOfferingCmd extends BaseCmd {
+public class UpdateNetworkOfferingCmd extends BaseCmd implements DomainAndZoneIdResolver {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
@@ -130,63 +127,11 @@
}
public List<Long> getDomainIds() {
- List<Long> validDomainIds = new ArrayList<>();
- if (StringUtils.isNotEmpty(domainIds)) {
- if (domainIds.contains(",")) {
- String[] domains = domainIds.split(",");
- for (String domain : domains) {
- Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim());
- if (validDomain != null) {
- validDomainIds.add(validDomain.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create network offering because invalid domain has been specified.");
- }
- }
- } else {
- domainIds = domainIds.trim();
- if (!domainIds.matches("public")) {
- Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim());
- if (validDomain != null) {
- validDomainIds.add(validDomain.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create network offering because invalid domain has been specified.");
- }
- }
- }
- } else {
- validDomainIds.addAll(_configService.getNetworkOfferingDomains(id));
- }
- return validDomainIds;
+ return resolveDomainIds(domainIds, id, _configService::getNetworkOfferingDomains, "network offering");
}
public List<Long> getZoneIds() {
- List<Long> validZoneIds = new ArrayList<>();
- if (StringUtils.isNotEmpty(zoneIds)) {
- if (zoneIds.contains(",")) {
- String[] zones = zoneIds.split(",");
- for (String zone : zones) {
- DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim());
- if (validZone != null) {
- validZoneIds.add(validZone.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create network offering because invalid zone has been specified.");
- }
- }
- } else {
- zoneIds = zoneIds.trim();
- if (!zoneIds.matches("all")) {
- DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim());
- if (validZone != null) {
- validZoneIds.add(validZone.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create network offering because invalid zone has been specified.");
- }
- }
- }
- } else {
- validZoneIds.addAll(_configService.getNetworkOfferingZones(id));
- }
- return validZoneIds;
+ return resolveZoneIds(zoneIds, id, _configService::getNetworkOfferingZones, "network offering");
}
/////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdatePodManagementNetworkIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdatePodManagementNetworkIpRangeCmd.java
index 6f90a07..394d42a 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdatePodManagementNetworkIpRangeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdatePodManagementNetworkIpRangeCmd.java
@@ -139,7 +139,7 @@
logger.warn("Exception: ", ex);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
} catch (Exception e) {
- logger.warn("Failed to update pod management IP range " + getNewStartIP() + "-" + getNewEndIP() + " of Pod: " + getPodId(), e);
+ logger.warn("Failed to update pod management IP range {}-{} of Pod: {}", getNewStartIP(), getNewEndIP(), getPodId(), e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/IsAccountAllowedToCreateOfferingsWithTagsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/IsAccountAllowedToCreateOfferingsWithTagsCmd.java
index fcd6b03d..4b1cd2f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/IsAccountAllowedToCreateOfferingsWithTagsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/IsAccountAllowedToCreateOfferingsWithTagsCmd.java
@@ -26,7 +26,8 @@
import org.apache.cloudstack.api.response.IsAccountAllowedToCreateOfferingsWithTagsResponse;
@APICommand(name = "isAccountAllowedToCreateOfferingsWithTags", description = "Return true if the specified account is allowed to create offerings with tags.",
- responseObject = IsAccountAllowedToCreateOfferingsWithTagsResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+ responseObject = IsAccountAllowedToCreateOfferingsWithTagsResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ httpMethod = "GET")
public class IsAccountAllowedToCreateOfferingsWithTagsCmd extends BaseCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "Account UUID", required = true)
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java
index c93b5d4..4d48327 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java
@@ -16,7 +16,6 @@
// under the License.
package org.apache.cloudstack.api.command.admin.offering;
-import java.util.ArrayList;
import java.util.List;
import com.cloud.offering.DiskOffering.State;
@@ -27,19 +26,18 @@
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
-import com.cloud.dc.DataCenter;
-import com.cloud.domain.Domain;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.offering.DiskOffering;
import com.cloud.user.Account;
@APICommand(name = "updateDiskOffering", description = "Updates a disk offering.", responseObject = DiskOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
-public class UpdateDiskOfferingCmd extends BaseCmd {
+public class UpdateDiskOfferingCmd extends BaseCmd implements DomainAndZoneIdResolver {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
@@ -152,63 +150,11 @@
}
public List<Long> getDomainIds() {
- List<Long> validDomainIds = new ArrayList<>();
- if (StringUtils.isNotEmpty(domainIds)) {
- if (domainIds.contains(",")) {
- String[] domains = domainIds.split(",");
- for (String domain : domains) {
- Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim());
- if (validDomain != null) {
- validDomainIds.add(validDomain.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create disk offering because invalid domain has been specified.");
- }
- }
- } else {
- domainIds = domainIds.trim();
- if (!domainIds.matches("public")) {
- Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim());
- if (validDomain != null) {
- validDomainIds.add(validDomain.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create disk offering because invalid domain has been specified.");
- }
- }
- }
- } else {
- validDomainIds.addAll(_configService.getDiskOfferingDomains(id));
- }
- return validDomainIds;
+ return resolveDomainIds(domainIds, id, _configService::getDiskOfferingDomains, "disk offering");
}
public List<Long> getZoneIds() {
- List<Long> validZoneIds = new ArrayList<>();
- if (StringUtils.isNotEmpty(zoneIds)) {
- if (zoneIds.contains(",")) {
- String[] zones = zoneIds.split(",");
- for (String zone : zones) {
- DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim());
- if (validZone != null) {
- validZoneIds.add(validZone.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create disk offering because invalid zone has been specified.");
- }
- }
- } else {
- zoneIds = zoneIds.trim();
- if (!zoneIds.matches("all")) {
- DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim());
- if (validZone != null) {
- validZoneIds.add(validZone.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create disk offering because invalid zone has been specified.");
- }
- }
- }
- } else {
- validZoneIds.addAll(_configService.getDiskOfferingZones(id));
- }
- return validZoneIds;
+ return resolveZoneIds(zoneIds, id, _configService::getDiskOfferingZones, "disk offering");
}
public String getTags() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java
index 8f10058..8e37499 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java
@@ -16,7 +16,6 @@
// under the License.
package org.apache.cloudstack.api.command.admin.offering;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -28,19 +27,18 @@
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
-import com.cloud.dc.DataCenter;
-import com.cloud.domain.Domain;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.offering.ServiceOffering;
import com.cloud.user.Account;
@APICommand(name = "updateServiceOffering", description = "Updates a service offering.", responseObject = ServiceOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
-public class UpdateServiceOfferingCmd extends BaseCmd {
+public class UpdateServiceOfferingCmd extends BaseCmd implements DomainAndZoneIdResolver {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
@@ -131,63 +129,11 @@
}
public List<Long> getDomainIds() {
- List<Long> validDomainIds = new ArrayList<>();
- if (StringUtils.isNotEmpty(domainIds)) {
- if (domainIds.contains(",")) {
- String[] domains = domainIds.split(",");
- for (String domain : domains) {
- Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim());
- if (validDomain != null) {
- validDomainIds.add(validDomain.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create service offering because invalid domain has been specified.");
- }
- }
- } else {
- domainIds = domainIds.trim();
- if (!domainIds.matches("public")) {
- Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim());
- if (validDomain != null) {
- validDomainIds.add(validDomain.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create service offering because invalid domain has been specified.");
- }
- }
- }
- } else {
- validDomainIds.addAll(_configService.getServiceOfferingDomains(id));
- }
- return validDomainIds;
+ return resolveDomainIds(domainIds, id, _configService::getServiceOfferingDomains, "service offering");
}
public List<Long> getZoneIds() {
- List<Long> validZoneIds = new ArrayList<>();
- if (StringUtils.isNotEmpty(zoneIds)) {
- if (zoneIds.contains(",")) {
- String[] zones = zoneIds.split(",");
- for (String zone : zones) {
- DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim());
- if (validZone != null) {
- validZoneIds.add(validZone.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create service offering because invalid zone has been specified.");
- }
- }
- } else {
- zoneIds = zoneIds.trim();
- if (!zoneIds.matches("all")) {
- DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim());
- if (validZone != null) {
- validZoneIds.add(validZone.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create service offering because invalid zone has been specified.");
- }
- }
- }
- } else {
- validZoneIds.addAll(_configService.getServiceOfferingZones(id));
- }
- return validZoneIds;
+ return resolveZoneIds(zoneIds, id, _configService::getServiceOfferingZones, "service offering");
}
public String getStorageTags() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java
index e7bfbdb..dcd4f2c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java
@@ -16,7 +16,10 @@
// under the License.
package org.apache.cloudstack.api.command.admin.resource;
-import com.cloud.user.Account;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
import org.apache.cloudstack.alert.AlertService;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseCmd;
@@ -24,9 +27,7 @@
import org.apache.cloudstack.api.response.AlertTypeResponse;
import org.apache.cloudstack.api.response.ListResponse;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
+import com.cloud.user.Account;
@APICommand(name = "listAlertTypes", description = "Lists all alerts types", responseObject = AlertResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -43,7 +44,8 @@
ListResponse<AlertTypeResponse> response = new ListResponse<>();
List<AlertTypeResponse> typeResponseList = new ArrayList<>();
for (AlertService.AlertType alertType : result) {
- AlertTypeResponse alertResponse = new AlertTypeResponse(alertType.getType(), alertType.getName());
+ AlertTypeResponse alertResponse = new AlertTypeResponse(alertType.getType(), alertType.getName(),
+ alertType.isRepetitionAllowed());
alertResponse.setObjectName("alerttype");
typeResponseList.add(alertResponse);
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/template/ListTemplatePermissionsCmdByAdmin.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/template/ListTemplatePermissionsCmdByAdmin.java
index a68958a..6115ff9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/template/ListTemplatePermissionsCmdByAdmin.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/template/ListTemplatePermissionsCmdByAdmin.java
@@ -1,4 +1,4 @@
-// Licensedname = "listTemplatePermissions", to the Apache Software Foundation (ASF) under one
+// 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
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListTrafficTypesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListTrafficTypesCmd.java
index 28e2eef..dc6e0f5 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListTrafficTypesCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListTrafficTypesCmd.java
@@ -26,14 +26,13 @@
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
-import org.apache.cloudstack.api.response.ProviderResponse;
import org.apache.cloudstack.api.response.TrafficTypeResponse;
import com.cloud.network.PhysicalNetworkTrafficType;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
-@APICommand(name = "listTrafficTypes", description = "Lists traffic types of a given physical network.", responseObject = ProviderResponse.class, since = "3.0.0",
+@APICommand(name = "listTrafficTypes", description = "Lists traffic types of a given physical network.", responseObject = TrafficTypeResponse.class, since = "3.0.0",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListTrafficTypesCmd extends BaseListCmd {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/user/DisableUserCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/user/DisableUserCmd.java
index 974c1c7..6ce669d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/user/DisableUserCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/user/DisableUserCmd.java
@@ -78,12 +78,12 @@
@Override
public String getEventDescription() {
- return "disabling user: " + getId();
+ return "disabling user: " + this._uuidMgr.getUuid(User.class, getId());
}
@Override
public void execute() {
- CallContext.current().setEventDetails("UserId: " + getId());
+ CallContext.current().setEventDetails("User ID: " + this._uuidMgr.getUuid(User.class, getId()));
UserAccount user = _regionService.disableUser(this);
if (user != null) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java
index 876474e..6727899 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java
@@ -238,7 +238,7 @@
logger.warn("Exception: ", ex);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
} catch (InsufficientCapacityException ex) {
- logger.info(ex);
+ logger.error(ex);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java
index d60c627..ad7e8a4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java
@@ -201,9 +201,7 @@
for (Map<String, String> entry : (Collection<Map<String, String>>)nicNetworkList.values()) {
String nic = entry.get(VmDetailConstants.NIC);
String networkUuid = entry.get(VmDetailConstants.NETWORK);
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("NIC, '%s', goes on net, '%s'", nic, networkUuid));
- }
+ logger.debug("Checking if NIC '{}' can be mapped on network '{}'", nic, networkUuid);
if (StringUtils.isAnyEmpty(nic, networkUuid) || _entityMgr.findByUuid(Network.class, networkUuid) == null) {
throw new InvalidParameterValueException(String.format("Network ID: %s for NIC ID: %s is invalid", networkUuid, nic));
}
@@ -219,9 +217,7 @@
for (Map<String, String> entry : (Collection<Map<String, String>>)nicIpAddressList.values()) {
String nic = entry.get(VmDetailConstants.NIC);
String ipAddress = StringUtils.defaultIfEmpty(entry.get(VmDetailConstants.IP4_ADDRESS), null);
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("NIC, '%s', gets IP, '%s'", nic, ipAddress));
- }
+ logger.debug("Checking if IP address '{}' can be mapped to NIC '{}'", ipAddress, nic);
if (StringUtils.isEmpty(nic)) {
throw new InvalidParameterValueException(String.format("NIC ID: '%s' is invalid for IP address mapping", nic));
}
@@ -244,9 +240,7 @@
for (Map<String, String> entry : (Collection<Map<String, String>>)dataDiskToDiskOfferingList.values()) {
String disk = entry.get(VmDetailConstants.DISK);
String offeringUuid = entry.get(VmDetailConstants.DISK_OFFERING);
- if (logger.isTraceEnabled()) {
- logger.trace(String.format("disk, '%s', gets offering, '%s'", disk, offeringUuid));
- }
+ logger.trace("Checking if offering '{}' can be used on disk '{}'", offeringUuid, disk);
if (StringUtils.isAnyEmpty(disk, offeringUuid) || _entityMgr.findByUuid(DiskOffering.class, offeringUuid) == null) {
throw new InvalidParameterValueException(String.format("Disk offering ID: %s for disk ID: %s is invalid", offeringUuid, disk));
}
@@ -298,7 +292,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
Account account = CallContext.current().getCallingAccount();
if (account != null) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java
index c92cda1..0142f6f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java
@@ -155,7 +155,7 @@
Host destinationHost = _resourceService.getHost(getHostId());
// OfflineVmwareMigration: destination host would have to not be a required parameter for stopped VMs
if (destinationHost == null) {
- logger.error(String.format("Unable to find the host with ID [%s].", getHostId()));
+ logger.error("Unable to find the host with ID [{}].", getHostId());
throw new InvalidParameterValueException("Unable to find the specified host to migrate the Instance.");
}
return destinationHost;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/volume/ImportVolumeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/volume/ImportVolumeCmd.java
index 57c3ee5..50f4b9c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/volume/ImportVolumeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/volume/ImportVolumeCmd.java
@@ -156,7 +156,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java
index 6087948..6b425bc 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java
@@ -224,10 +224,8 @@
Iterator<? extends Map<String, String>> iter = servicesCollection.iterator();
while (iter.hasNext()) {
Map<String, String> obj = iter.next();
- if (logger.isTraceEnabled()) {
- logger.trace("service provider entry specified: " + obj);
- }
- HashMap<String, String> services = (HashMap<String, String>) obj;
+ logger.trace("Service provider entry specified: {}", obj);
+ HashMap<String, String> services = (HashMap<String, String>)obj;
String service = services.get("service");
String provider = services.get("provider");
List<String> providerList = null;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java
index 44bc88c..d4565cb 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java
@@ -16,7 +16,6 @@
// under the License.
package org.apache.cloudstack.api.command.admin.vpc;
-import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.api.APICommand;
@@ -26,19 +25,16 @@
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
import org.apache.cloudstack.api.response.VpcOfferingResponse;
-import org.apache.commons.lang3.StringUtils;
-import com.cloud.dc.DataCenter;
-import com.cloud.domain.Domain;
import com.cloud.event.EventTypes;
-import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.vpc.VpcOffering;
import com.cloud.user.Account;
@APICommand(name = "updateVPCOffering", description = "Updates VPC offering", responseObject = VpcOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
-public class UpdateVPCOfferingCmd extends BaseAsyncCmd {
+public class UpdateVPCOfferingCmd extends BaseAsyncCmd implements DomainAndZoneIdResolver {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
@@ -93,63 +89,11 @@
}
public List<Long> getDomainIds() {
- List<Long> validDomainIds = new ArrayList<>();
- if (StringUtils.isNotEmpty(domainIds)) {
- if (domainIds.contains(",")) {
- String[] domains = domainIds.split(",");
- for (String domain : domains) {
- Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim());
- if (validDomain != null) {
- validDomainIds.add(validDomain.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create VPC offering because invalid domain has been specified.");
- }
- }
- } else {
- domainIds = domainIds.trim();
- if (!domainIds.matches("public")) {
- Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim());
- if (validDomain != null) {
- validDomainIds.add(validDomain.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create VPC offering because invalid domain has been specified.");
- }
- }
- }
- } else {
- validDomainIds.addAll(_vpcProvSvc.getVpcOfferingDomains(id));
- }
- return validDomainIds;
+ return resolveDomainIds(domainIds, id, _vpcProvSvc::getVpcOfferingDomains, "VPC offering");
}
public List<Long> getZoneIds() {
- List<Long> validZoneIds = new ArrayList<>();
- if (StringUtils.isNotEmpty(zoneIds)) {
- if (zoneIds.contains(",")) {
- String[] zones = zoneIds.split(",");
- for (String zone : zones) {
- DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim());
- if (validZone != null) {
- validZoneIds.add(validZone.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create VPC offering because invalid zone has been specified.");
- }
- }
- } else {
- zoneIds = zoneIds.trim();
- if (!zoneIds.matches("all")) {
- DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim());
- if (validZone != null) {
- validZoneIds.add(validZone.getId());
- } else {
- throw new InvalidParameterValueException("Failed to create VPC offering because invalid zone has been specified.");
- }
- }
- }
- } else {
- validZoneIds.addAll(_vpcProvSvc.getVpcOfferingZones(id));
- }
- return validZoneIds;
+ return resolveZoneIds(zoneIds, id, _vpcProvSvc::getVpcOfferingZones, "VPC offering");
}
public Integer getSortKey() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/offering/DomainAndZoneIdResolver.java b/api/src/main/java/org/apache/cloudstack/api/command/offering/DomainAndZoneIdResolver.java
new file mode 100644
index 0000000..b302c4a
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/offering/DomainAndZoneIdResolver.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.offering;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.LongFunction;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.domain.Domain;
+import com.cloud.exception.InvalidParameterValueException;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * Helper for commands that accept a domainIds or zoneIds string and need to
+ * resolve them to lists of IDs, falling back to an offering-specific
+ * default provider.
+ */
+public interface DomainAndZoneIdResolver {
+ /**
+ * Parse the provided domainIds string and return a list of domain IDs.
+ * If domainIds is empty, the defaultDomainsProvider will be invoked with the
+ * provided resource id to obtain the current domains.
+ */
+ default List<Long> resolveDomainIds(final String domainIds, final Long id, final LongFunction<List<Long>> defaultDomainsProvider, final String resourceTypeName) {
+ final List<Long> validDomainIds = new ArrayList<>();
+ final BaseCmd base = (BaseCmd) this;
+ final Logger logger = LogManager.getLogger(base.getClass());
+
+ if (StringUtils.isEmpty(domainIds)) {
+ if (defaultDomainsProvider != null) {
+ final List<Long> defaults = defaultDomainsProvider.apply(id);
+ if (defaults != null) {
+ validDomainIds.addAll(defaults);
+ }
+ }
+ return validDomainIds;
+ }
+
+ final String[] domains = domainIds.split(",");
+ final String type = (resourceTypeName == null || resourceTypeName.isEmpty()) ? "offering" : resourceTypeName;
+ for (String domain : domains) {
+ final String trimmed = domain == null ? "" : domain.trim();
+ if (trimmed.isEmpty() || "public".equalsIgnoreCase(trimmed)) {
+ continue;
+ }
+
+ final Domain validDomain = base._entityMgr.findByUuid(Domain.class, trimmed);
+ if (validDomain == null) {
+ logger.warn("Invalid domain specified for {}", type);
+ throw new InvalidParameterValueException("Failed to create " + type + " because invalid domain has been specified.");
+ }
+ validDomainIds.add(validDomain.getId());
+ }
+
+ return validDomainIds;
+ }
+
+ /**
+ * Parse the provided zoneIds string and return a list of zone IDs.
+ * If zoneIds is empty, the defaultZonesProvider will be invoked with the
+ * provided resource id to obtain the current zones.
+ */
+ default List<Long> resolveZoneIds(final String zoneIds, final Long id, final LongFunction<List<Long>> defaultZonesProvider, final String resourceTypeName) {
+ final List<Long> validZoneIds = new ArrayList<>();
+ final BaseCmd base = (BaseCmd) this;
+ final Logger logger = LogManager.getLogger(base.getClass());
+
+ if (StringUtils.isEmpty(zoneIds)) {
+ if (defaultZonesProvider != null) {
+ final List<Long> defaults = defaultZonesProvider.apply(id);
+ if (defaults != null) {
+ validZoneIds.addAll(defaults);
+ }
+ }
+ return validZoneIds;
+ }
+
+ final String[] zones = zoneIds.split(",");
+ final String type = (resourceTypeName == null || resourceTypeName.isEmpty()) ? "offering" : resourceTypeName;
+ for (String zone : zones) {
+ final String trimmed = zone == null ? "" : zone.trim();
+ if (trimmed.isEmpty() || "all".equalsIgnoreCase(trimmed)) {
+ continue;
+ }
+
+ final DataCenter validZone = base._entityMgr.findByUuid(DataCenter.class, trimmed);
+ if (validZone == null) {
+ logger.warn("Invalid zone specified for {}: {}", type, trimmed);
+ throw new InvalidParameterValueException("Failed to create " + type + " because invalid zone has been specified.");
+ }
+ validZoneIds.add(validZone.getId());
+ }
+
+ return validZoneIds;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java
index 4ecce59..db9688a 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java
@@ -232,7 +232,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateConditionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateConditionCmd.java
index 9d42706..2bb101d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateConditionCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateConditionCmd.java
@@ -137,7 +137,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScalePolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScalePolicyCmd.java
index 98e2e2a..fac7ffe 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScalePolicyCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScalePolicyCmd.java
@@ -91,7 +91,7 @@
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} else {
- logger.warn("Failed to delete autoscale policy " + getId());
+ logger.warn("Failed to delete autoscale policy {}", getId());
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete AutoScale Policy");
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScaleVmGroupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScaleVmGroupCmd.java
index 274aac9..c2dd6d5 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScaleVmGroupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScaleVmGroupCmd.java
@@ -101,7 +101,7 @@
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} else {
- logger.warn("Failed to delete autoscale Instance group " + getId());
+ logger.warn("Failed to delete autoscale Instance group {}", getId());
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete autoscale vm group");
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScaleVmProfileCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScaleVmProfileCmd.java
index a4fbd70..9e2f63d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScaleVmProfileCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteAutoScaleVmProfileCmd.java
@@ -90,7 +90,7 @@
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} else {
- logger.warn("Failed to delete autoscale Instance profile " + getId());
+ logger.warn("Failed to delete autoscale Instance profile {}", getId());
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete autoscale Instance profile");
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteConditionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteConditionCmd.java
index 7b73a76..2eeed8b 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteConditionCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/DeleteConditionCmd.java
@@ -64,7 +64,7 @@
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} else {
- logger.warn("Failed to delete condition " + getId());
+ logger.warn("Failed to delete condition {}", getId());
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete condition.");
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupCmd.java
index 2d0cde6..df417ef 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupCmd.java
@@ -19,6 +19,7 @@
import javax.inject.Inject;
+import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
@@ -138,7 +139,8 @@
@Override
public String getEventDescription() {
- return "Creating backup for Instance " + vmId;
+ String vmUuid = _uuidMgr.getUuid(VirtualMachine.class, getVmId());
+ return "Creating backup for Instance " + vmUuid;
}
@Override
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DeleteBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DeleteBackupCmd.java
index 369934a..8c32dac 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DeleteBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DeleteBackupCmd.java
@@ -28,6 +28,7 @@
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import org.apache.commons.lang3.BooleanUtils;
@@ -111,6 +112,7 @@
@Override
public String getEventDescription() {
- return "Deleting backup ID " + backupId;
+ String backupUuid = _uuidMgr.getUuid(Backup.class, getId());
+ return "Deleting backup ID " + backupUuid;
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupsCmd.java
index f1f6303..fb9c92f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupsCmd.java
@@ -148,7 +148,7 @@
Pair<List<Backup>, Integer> result = backupManager.listBackups(this);
setupResponseBackupList(result.first(), result.second());
} catch (Exception e) {
- logger.debug("Exception while listing backups", e);
+ logger.error("Exception while listing backups", e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupCmd.java
index 5385c0f..3d096c0 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupCmd.java
@@ -28,6 +28,7 @@
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.BackupResponse;
+import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
@@ -99,6 +100,7 @@
@Override
public String getEventDescription() {
- return "Restoring Instance from backup: " + backupId;
+ String backupUuid = _uuidMgr.getUuid(Backup.class, getBackupId());
+ return "Restoring Instance from backup: " + backupUuid;
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/CreateBucketCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/CreateBucketCmd.java
index 722556b..f1c1498 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/CreateBucketCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/CreateBucketCmd.java
@@ -150,7 +150,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
index 947467a..2cb6407 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
@@ -21,7 +21,9 @@
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.CapabilitiesResponse;
+import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.config.ApiServiceConfiguration;
import com.cloud.user.Account;
@@ -30,12 +32,22 @@
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListCapabilitiesCmd extends BaseCmd {
+ @Parameter(name = ApiConstants.DOMAIN_ID,
+ type = CommandType.UUID,
+ entityType = DomainResponse.class,
+ description = "the domain for listing capabilities.",
+ since = "4.23.0")
+ private Long domainId;
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
+ public Long getDomainId() {
+ return domainId;
+ }
+
@Override
public void execute() {
Map<String, Object> capabilities = _mgr.listCapabilities(this);
@@ -77,6 +89,10 @@
response.setExtensionsPath((String)capabilities.get(ApiConstants.EXTENSIONS_PATH));
response.setDynamicScalingEnabled((Boolean) capabilities.get(ApiConstants.DYNAMIC_SCALING_ENABLED));
response.setAdditionalConfigEnabled((Boolean) capabilities.get(ApiConstants.ADDITONAL_CONFIG_ENABLED));
+ if (capabilities.containsKey(ApiConstants.VPN_CUSTOMER_GATEWAY_PARAMETERS)) {
+ Map<String, Object> vpnCustomerGatewayParameters = (Map<String, Object>) capabilities.get(ApiConstants.VPN_CUSTOMER_GATEWAY_PARAMETERS);
+ response.setVpnCustomerGatewayParameters(vpnCustomerGatewayParameters);
+ }
response.setObjectName("capability");
response.setResponseName(getCommandName());
this.setResponseObject(response);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateEgressFirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateEgressFirewallRuleCmd.java
index 7a96421..f972cbd 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateEgressFirewallRuleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateEgressFirewallRuleCmd.java
@@ -255,11 +255,8 @@
}
} catch (NetworkRuleConflictException ex) {
String message = "Network rule conflict: ";
- if (!logger.isTraceEnabled()) {
- logger.info(message + ex.getMessage());
- } else {
- logger.trace(message, ex);
- }
+ logger.error("{}{}", message, ex.getMessage());
+ logger.trace(message, ex);
throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, ex.getMessage());
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java
index 569b5fc..92be579 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java
@@ -271,7 +271,7 @@
setEntityUuid(result.getUuid());
}
} catch (NetworkRuleConflictException ex) {
- logger.trace("Network Rule Conflict: ", ex);
+ logger.error("Network Rule Conflict: ", ex);
throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, ex.getMessage(), ex);
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java
index 564ebb2..43cdf09 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java
@@ -158,7 +158,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
+ Long accountId = _accountService.finalizeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsoPermissionsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsoPermissionsCmd.java
index 48e4b85..069f3e4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsoPermissionsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsoPermissionsCmd.java
@@ -1,4 +1,4 @@
-// Licensedname = "listIsoPermissions", to the Apache Software Foundation (ASF) under one
+// 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
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java
index 6820afb..562cbc2 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java
@@ -87,7 +87,7 @@
private Boolean showIcon;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the ISO. Valid options are: x86_64, aarch64",
+ description = "the CPU arch of the ISO. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
index 2de0f96..1c57e90 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
@@ -120,7 +120,7 @@
private Boolean passwordEnabled;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the ISO. Valid options are: x86_64, aarch64",
+ description = "the CPU arch of the ISO. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
@@ -254,7 +254,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerRuleInstancesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerRuleInstancesCmd.java
index 8079e28..bf46046 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerRuleInstancesCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerRuleInstancesCmd.java
@@ -95,10 +95,10 @@
public void execute() {
Pair<List<? extends UserVm>, List<String>> vmServiceMap = _lbService.listLoadBalancerInstances(this);
List<? extends UserVm> result = vmServiceMap.first();
- logger.debug(String.format("A total of [%s] user VMs were obtained when listing the load balancer instances: [%s].", result.size(), result));
+ logger.debug("A total of [{}] user VMs were obtained when listing the load balancer instances: [{}].", result.size(), result);
List<String> serviceStates = vmServiceMap.second();
- logger.debug(String.format("A total of [%s] service states were obtained when listing the load balancer instances: [%s].", serviceStates.size(), serviceStates));
+ logger.debug("A total of [{}] service states were obtained when listing the load balancer instances: [{}].", serviceStates.size(), serviceStates);
if (!isListLbVmip()) {
ListResponse<UserVmResponse> response = new ListResponse<>();
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLBHealthCheckPolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLBHealthCheckPolicyCmd.java
index 80e285a..17bd61c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLBHealthCheckPolicyCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLBHealthCheckPolicyCmd.java
@@ -63,7 +63,7 @@
@Override
public String getEventDescription() {
- return "Update load balancer health check policy ID= " + id;
+ return "Update load balancer health check policy ID = " + id;
}
@Override
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLBStickinessPolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLBStickinessPolicyCmd.java
index 0163bb8..e79c1c5 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLBStickinessPolicyCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLBStickinessPolicyCmd.java
@@ -62,7 +62,7 @@
@Override
public String getEventDescription() {
- return "Update load balancer stickiness policy ID= " + id;
+ return "Update load balancer stickiness policy ID = " + id;
}
@Override
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/nat/CreateIpForwardingRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/nat/CreateIpForwardingRuleCmd.java
index 1aaf557..596d595 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/nat/CreateIpForwardingRuleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/nat/CreateIpForwardingRuleCmd.java
@@ -148,7 +148,7 @@
setEntityId(rule.getId());
setEntityUuid(rule.getUuid());
} catch (NetworkRuleConflictException e) {
- logger.info("Unable to create static NAT rule due to ", e);
+ logger.error("Unable to create static NAT rule due to ", e);
throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, e.getMessage());
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
index 3170322..31d1b49 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
@@ -128,7 +128,7 @@
} else {
account = CallContext.current().getCallingAccount();
if (!Account.Type.ADMIN.equals(account.getType())) {
- logger.warn(String.format("Only Root Admin can create global ACLs. Account [%s] cannot create any global ACL.", account));
+ logger.error("Only Root Admin can create global ACLs. {} cannot create any global ACL.", account);
throw new PermissionDeniedException("Only Root Admin can create global ACLs.");
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
index 35fec1d..cbf6df0 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
@@ -417,7 +417,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/routing/CreateRoutingFirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/routing/CreateRoutingFirewallRuleCmd.java
index 7146d1a..ad52916 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/routing/CreateRoutingFirewallRuleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/routing/CreateRoutingFirewallRuleCmd.java
@@ -250,7 +250,7 @@
}
ruleResponse.setResponseName(getCommandName());
} catch (Exception ex) {
- logger.error("Got exception when create Routing firewall rules: " + ex);
+ logger.error("Got exception when create Routing firewall rules: ", ex);
} finally {
if (!success || rule == null) {
routedIpv4Manager.revokeRoutingFirewallRule(getEntityId());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java
index df9b6b3..20b227b 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java
@@ -180,7 +180,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, null, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, null, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java
index 7bae74c..4bda236 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java
@@ -103,7 +103,7 @@
@Override
public void execute() {
List<? extends ResourceLimit> result =
- _resourceLimitService.searchForLimits(id, _accountService.finalyzeAccountId(this.getAccountName(), this.getDomainId(), this.getProjectId(), false), this.getDomainId(),
+ _resourceLimitService.searchForLimits(id, _accountService.finalizeAccountId(this.getAccountName(), this.getDomainId(), this.getProjectId(), false), this.getDomainId(),
getResourceTypeEnum(), getTag(), this.getStartIndex(), this.getPageSizeVal());
ListResponse<ResourceLimitResponse> response = new ListResponse<ResourceLimitResponse>();
List<ResourceLimitResponse> limitResponses = new ArrayList<ResourceLimitResponse>();
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java
index 123b0e4..d43bb29 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java
@@ -127,7 +127,7 @@
@Override
public void execute() {
List<? extends ResourceCount> result =
- _resourceLimitService.recalculateResourceCount(_accountService.finalyzeAccountId(accountName, domainId, projectId, true), getDomainId(), getResourceType(), getTag());
+ _resourceLimitService.recalculateResourceCount(_accountService.finalizeAccountId(accountName, domainId, projectId, true), getDomainId(), getResourceType(), getTag());
if ((result != null) && (result.size() > 0)) {
ListResponse<ResourceCountResponse> response = new ListResponse<ResourceCountResponse>();
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java
index 3678e88..f88ef96 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java
@@ -100,7 +100,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
@@ -110,7 +110,7 @@
@Override
public void execute() {
- ResourceLimit result = _resourceLimitService.updateResourceLimit(_accountService.finalyzeAccountId(accountName, domainId, projectId, true), getDomainId(), resourceType, max, getTag());
+ ResourceLimit result = _resourceLimitService.updateResourceLimit(_accountService.finalizeAccountId(accountName, domainId, projectId, true), getDomainId(), resourceType, max, getTag());
if (result != null || (result == null && max != null && max.longValue() == -1L)) {
ResourceLimitResponse response = _responseGenerator.createResourceLimitResponse(result);
response.setResponseName(getCommandName());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupEgressCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupEgressCmd.java
index 13b09c7..7d0004c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupEgressCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupEgressCmd.java
@@ -166,7 +166,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupIngressCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupIngressCmd.java
index 07a4df9..d7a95d8 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupIngressCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupIngressCmd.java
@@ -166,7 +166,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/DeleteSecurityGroupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/DeleteSecurityGroupCmd.java
index 0636f03..1882d80 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/DeleteSecurityGroupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/DeleteSecurityGroupCmd.java
@@ -103,7 +103,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CopySnapshotCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CopySnapshotCmd.java
index ac54ebb..519f987 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CopySnapshotCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CopySnapshotCmd.java
@@ -97,7 +97,11 @@
"The snapshot will always be made available in the zone in which the volume is present. Currently supported for StorPool only")
protected List<Long> storagePoolIds;
- @Parameter (name = ApiConstants.USE_STORAGE_REPLICATION, type=CommandType.BOOLEAN, required = false, since = "4.21.0", description = "This parameter enables the option the snapshot to be copied to supported primary storage")
+ @Parameter (name = ApiConstants.USE_STORAGE_REPLICATION,
+ type=CommandType.BOOLEAN,
+ since = "4.21.0",
+ description = "Enables the snapshot to be copied to the supported primary storages when the config 'use.storage.replication' is set to true for the storage or globally. " +
+ "This is supported only for StorPool storage for now.")
protected Boolean useStorageReplication;
/////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
index 1b9d3c5..b2b1da9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
@@ -112,7 +112,10 @@
since = "4.21.0")
protected List<Long> storagePoolIds;
- @Parameter (name = ApiConstants.USE_STORAGE_REPLICATION, type=CommandType.BOOLEAN, required = false, description = "This parameter enables the option the snapshot to be copied to supported primary storage")
+ @Parameter (name = ApiConstants.USE_STORAGE_REPLICATION,
+ type=CommandType.BOOLEAN,
+ description = "Enables the snapshot to be copied to the supported primary storages when the config 'use.storage.replication' is set to true for the storage or globally. " +
+ "This is supported only for StorPool storage for now.")
protected Boolean useStorageReplication;
private String syncObjectType = BaseAsyncCmd.snapshotHostSyncObject;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotFromVMSnapshotCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotFromVMSnapshotCmd.java
index c7a592c..0dd275c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotFromVMSnapshotCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotFromVMSnapshotCmd.java
@@ -165,7 +165,7 @@
@Override
public void execute() {
VMSnapshot vmSnapshot = _vmSnapshotService.getVMSnapshotById(getVMSnapshotId());
- logger.info("CreateSnapshotFromVMSnapshotCmd with Instance Snapshot {} with ID: {} and Snapshot [ID: {}, UUID: {}]", vmSnapshot, getVMSnapshotId(), getEntityId(), getEntityUuid());
+ logger.info("CreateSnapshotFromVMSnapshotCmd with {} and Snapshot [ID: {}, UUID: {}]", vmSnapshot, getEntityId(), getEntityUuid());
CallContext.current().setEventDetails("Instance Snapshot Id: " + vmSnapshot.getUuid());
Snapshot snapshot = null;
try {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotPolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotPolicyCmd.java
index 24d756b..b1e7b2a 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotPolicyCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotPolicyCmd.java
@@ -94,7 +94,11 @@
since = "4.21.0")
protected List<Long> storagePoolIds;
- @Parameter (name = ApiConstants.USE_STORAGE_REPLICATION, type=CommandType.BOOLEAN, required = false, since = "4.21.0", description = "This parameter enables the option the snapshot to be copied to supported primary storage")
+ @Parameter (name = ApiConstants.USE_STORAGE_REPLICATION,
+ type=CommandType.BOOLEAN,
+ since = "4.21.0",
+ description = "Enables the snapshot to be copied to the supported primary storages when the config 'use.storage.replication' is set to true for the storage or globally. " +
+ "This is supported only for StorPool storage for now.")
protected Boolean useStorageReplication;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ssh/CreateSSHKeyPairCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ssh/CreateSSHKeyPairCmd.java
index a55b205..1b79c11 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/ssh/CreateSSHKeyPairCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ssh/CreateSSHKeyPairCmd.java
@@ -77,7 +77,7 @@
/////////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ssh/RegisterSSHKeyPairCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ssh/RegisterSSHKeyPairCmd.java
index 36c708e..f7af86d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/ssh/RegisterSSHKeyPairCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ssh/RegisterSSHKeyPairCmd.java
@@ -85,7 +85,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/storage/sharedfs/CreateSharedFSCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/storage/sharedfs/CreateSharedFSCmd.java
index ddaa316..595b611 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/storage/sharedfs/CreateSharedFSCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/storage/sharedfs/CreateSharedFSCmd.java
@@ -230,7 +230,7 @@
}
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java
index 6e6acf1..76fadb7 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java
@@ -150,7 +150,7 @@
private String accountName;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the template. Valid options are: x86_64, aarch64. Defaults to x86_64",
+ description = "the CPU arch of the template. Valid options are: x86_64, aarch64, s390x. Defaults to x86_64",
since = "4.20.2")
private String arch;
@@ -354,14 +354,12 @@
private Long findAccountIdToUse(Account callingAccount) {
Long accountIdToUse = null;
try {
- accountIdToUse = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ accountIdToUse = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
} catch (InvalidParameterValueException | PermissionDeniedException ex) {
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("An exception occurred while finalizing account id with accountName, domainId and projectId" +
- "using callingAccountId=%s", callingAccount.getUuid()), ex);
- }
- logger.warn("Unable to find accountId associated with accountName=" + accountName + " and domainId="
- + domainId + " or projectId=" + projectId + ", using callingAccountId=" + callingAccount.getUuid());
+ logger.error("Unable to find accountId associated with accountName={} and domainId={} or projectId={}" +
+ ", using callingAccountId={}", accountName, domainId, projectId, callingAccount.getUuid());
+ logger.debug("An exception occurred while finalizing account id with accountName, domainId and projectId" +
+ "using callingAccountId={}", callingAccount.getUuid(), ex);
}
return accountIdToUse != null ? accountIdToUse : callingAccount.getAccountId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java
index 12ef433..e6e178b 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java
@@ -57,7 +57,7 @@
private Long osTypeId;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the template. Valid options are: x86_64, aarch64",
+ description = "the CPU arch of the template. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
@@ -223,7 +223,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
+ Long accountId = _accountService.finalizeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatePermissionsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatePermissionsCmd.java
index 9dabbec..7e7efcf 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatePermissionsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatePermissionsCmd.java
@@ -1,4 +1,4 @@
-// Licensedname = "listTemplatePermissions", to the Apache Software Foundation (ASF) under one
+// 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
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java
index 0cf7256..0b52413 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java
@@ -112,7 +112,7 @@
private Boolean forCks;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the template. Valid options are: x86_64, aarch64",
+ description = "the CPU arch of the template. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java
index b501103..49992ac 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java
@@ -180,7 +180,7 @@
private String templateType;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the template. Valid options are: x86_64, aarch64",
+ description = "the CPU arch of the template. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
@@ -344,7 +344,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/userdata/RegisterCniConfigurationCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/userdata/RegisterCniConfigurationCmd.java
index eb80da3..3f1de41 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/userdata/RegisterCniConfigurationCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/userdata/RegisterCniConfigurationCmd.java
@@ -67,7 +67,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
+ Long accountId = _accountService.finalizeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/userdata/RegisterUserDataCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/userdata/RegisterUserDataCmd.java
index cbbe767..d99f2fd 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/userdata/RegisterUserDataCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/userdata/RegisterUserDataCmd.java
@@ -70,7 +70,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
+ Long accountId = _accountService.finalizeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/BaseDeployVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/BaseDeployVMCmd.java
index ecbde47..07c11b2 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/BaseDeployVMCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/BaseDeployVMCmd.java
@@ -416,9 +416,7 @@
nic = null;
}
String networkUuid = entry.get(VmDetailConstants.NETWORK);
- if (logger.isTraceEnabled()) {
- logger.trace(String.format("nic, '%s', goes on net, '%s'", nic, networkUuid));
- }
+ logger.trace("Checking if NIC '{}' can be mapped on network '{}'", nic, networkUuid);
if (nic == null || StringUtils.isEmpty(networkUuid) || _entityMgr.findByUuid(Network.class, networkUuid) == null) {
throw new InvalidParameterValueException(String.format("Network ID: %s for NIC ID: %s is invalid", networkUuid, nic));
}
@@ -810,7 +808,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMFromBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMFromBackupCmd.java
index 04e413e..e17ba9c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMFromBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMFromBackupCmd.java
@@ -137,7 +137,7 @@
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
}
}
- logger.info(String.format("%s: %s", message.toString(), ex.getLocalizedMessage()));
+ logger.info("{}: {}", message.toString(), ex.getLocalizedMessage());
logger.debug(message.toString(), ex);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
index 81ee00c..528a8b0 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
@@ -112,12 +112,12 @@
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
}
}
- logger.info(String.format("%s: %s", message, ex.getLocalizedMessage()));
+ logger.info("{}: {}", message.toString(), ex.getLocalizedMessage());
logger.debug(message.toString(), ex);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
}
} else {
- logger.info("Instance " + getEntityUuid() + " already created, load UserVm from DB");
+ logger.info("Instance {} already created, load UserVm from DB", getEntityUuid());
result = _userVmService.finalizeCreateVirtualMachine(getEntityId());
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ResetVMPasswordCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ResetVMPasswordCmd.java
index dbf11de..5302675 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ResetVMPasswordCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ResetVMPasswordCmd.java
@@ -120,9 +120,9 @@
UserVm vm = _responseGenerator.findUserVmById(getId());
if (StringUtils.isBlank(password)) {
password = _mgr.generateRandomPassword();
- logger.debug(String.format("Resetting VM [%s] password to a randomly generated password.", vm.getUuid()));
+ logger.debug("Resetting VM [{}] password to a randomly generated password.", vm.getUuid());
} else {
- logger.debug(String.format("Resetting VM [%s] password to password defined by user.", vm.getUuid()));
+ logger.debug("Resetting VM [{}] password to password defined by user.", vm.getUuid());
}
CallContext.current().setEventDetails("Vm Id: " + getId());
UserVm result = _userVmService.resetVMPassword(this, password);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java
index f870a9b..115b37d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java
@@ -163,6 +163,12 @@
description = "Lease expiry action, valid values are STOP and DESTROY")
private String leaseExpiryAction;
+ @Parameter(name = ApiConstants.CLEAN_UP_EXTRA_CONFIG, type = CommandType.BOOLEAN, since = "4.23.0",
+ description = "Optional boolean field, which indicates if extraconfig for the instance should be " +
+ "cleaned up or not (If set to true, extraconfig removed for this instance, extraconfig field " +
+ "ignored; if false or not set, no action)")
+ private Boolean cleanupExtraConfig;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -274,14 +280,18 @@
return extraConfig;
}
- /////////////////////////////////////////////////////
- /////////////// API Implementation///////////////////
- /////////////////////////////////////////////////////
-
public Long getOsTypeId() {
return osTypeId;
}
+ public boolean isCleanupExtraConfig() {
+ return Boolean.TRUE.equals(cleanupExtraConfig);
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
@Override
public String getCommandName() {
return s_name;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vmgroup/CreateVMGroupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vmgroup/CreateVMGroupCmd.java
index a142ffa..12f534e 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vmgroup/CreateVMGroupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vmgroup/CreateVMGroupCmd.java
@@ -82,7 +82,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
index 27b592a..5938bdb 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
@@ -188,7 +188,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/GetUploadParamsForVolumeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/GetUploadParamsForVolumeCmd.java
index 0020fe4..1e3b2e4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/GetUploadParamsForVolumeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/GetUploadParamsForVolumeCmd.java
@@ -72,7 +72,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
+ Long accountId = _accountService.finalizeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java
index 3d23a63..81077de 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java
@@ -159,7 +159,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateStaticRouteCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateStaticRouteCmd.java
index 15a31d4..1605e48 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateStaticRouteCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateStaticRouteCmd.java
@@ -95,7 +95,7 @@
setEntityId(result.getId());
setEntityUuid(result.getUuid());
} catch (NetworkRuleConflictException ex) {
- logger.info("Network rule conflict: " + ex.getMessage());
+ logger.info("Network rule conflict: {}", ex.getMessage());
logger.trace("Network rule conflict: ", ex);
throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, ex.getMessage());
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
index a91d3ba..2adbbd6 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
@@ -273,7 +273,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/AddVpnUserCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/AddVpnUserCmd.java
index b00b932..78cd9a3 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/AddVpnUserCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/AddVpnUserCmd.java
@@ -88,7 +88,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateRemoteAccessVpnCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateRemoteAccessVpnCmd.java
index e52e300..c730c2c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateRemoteAccessVpnCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateRemoteAccessVpnCmd.java
@@ -146,7 +146,7 @@
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create remote access VPN");
}
} catch (NetworkRuleConflictException e) {
- logger.info("Network rule conflict: " + e.getMessage());
+ logger.info("Network rule conflict: {}", e.getMessage());
logger.trace("Network Rule Conflict: ", e);
throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, e.getMessage());
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java
index e7b3863..3d6b791 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java
@@ -133,7 +133,7 @@
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create site to site VPN connection");
}
} catch (NetworkRuleConflictException e) {
- logger.info("Network rule conflict: " + e.getMessage());
+ logger.info("Network rule conflict: {}", e.getMessage());
logger.trace("Network Rule Conflict: ", e);
throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, e.getMessage());
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java
index ef0e235..0da813e 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java
@@ -167,7 +167,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
accountId = CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/RemoveVpnUserCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/RemoveVpnUserCmd.java
index aff8710..a18619c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/RemoveVpnUserCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/RemoveVpnUserCmd.java
@@ -82,7 +82,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/ResetVpnConnectionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/ResetVpnConnectionCmd.java
index b6e29e6..f681c8c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/ResetVpnConnectionCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/ResetVpnConnectionCmd.java
@@ -74,7 +74,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, null, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, null, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnConnectionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnConnectionCmd.java
index a4a0c92..92f6786 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnConnectionCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnConnectionCmd.java
@@ -66,7 +66,7 @@
@Override
public String getEventDescription() {
- return "Updating site-to-site VPN connection id= " + id;
+ return "Updating site-to-site VPN connection ID = " + id;
}
@Override
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java
index edd168f..56aa8b2 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java
@@ -161,7 +161,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, null, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, null, true);
if (accountId == null) {
accountId = CallContext.current().getCallingAccount().getId();
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnGatewayCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnGatewayCmd.java
index 29676bd..2507699 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnGatewayCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/UpdateVpnGatewayCmd.java
@@ -63,7 +63,7 @@
@Override
public String getEventDescription() {
- return "Update site-to-site VPN gateway id= " + id;
+ return "Update site-to-site VPN gateway ID = " + id;
}
@Override
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java
index 3f91cde..e8c3cf6 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java
@@ -16,11 +16,12 @@
// under the License.
package org.apache.cloudstack.api.response;
-import com.cloud.serializer.Param;
-import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
public class AlertTypeResponse extends BaseResponse {
@SerializedName("alerttypeid")
@@ -31,6 +32,10 @@
@Param(description = "description of alert type")
private String name;
+ @SerializedName(ApiConstants.REPETITION_ALLOWED)
+ @Param(description = "Whether repetitive alerts allowed for the alert type", since = "4.22.0")
+ private boolean repetitionAllowed = true;
+
public String getName() {
return name;
}
@@ -47,9 +52,10 @@
this.alertType = alertType;
}
- public AlertTypeResponse(short alertType, String name) {
+ public AlertTypeResponse(short alertType, String name, boolean repetitionAllowed) {
this.alertType = alertType;
this.name = name;
+ this.repetitionAllowed = repetitionAllowed;
setObjectName("alerttype");
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/BackupOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/BackupOfferingResponse.java
index b3a7d03..c4f3ee3 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/BackupOfferingResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/BackupOfferingResponse.java
@@ -61,6 +61,16 @@
@Param(description = "Zone name")
private String zoneName;
+ @SerializedName(ApiConstants.DOMAIN_ID)
+ @Param(description = "the domain ID(s) this backup offering belongs to.",
+ since = "4.23.0")
+ private String domainId;
+
+ @SerializedName(ApiConstants.DOMAIN)
+ @Param(description = "the domain name(s) this backup offering belongs to.",
+ since = "4.23.0")
+ private String domain;
+
@SerializedName(ApiConstants.CROSS_ZONE_INSTANCE_CREATION)
@Param(description = "the backups with this offering can be used to create Instances on all Zones", since = "4.22.0")
private Boolean crossZoneInstanceCreation;
@@ -108,4 +118,13 @@
public void setCreated(Date created) {
this.created = created;
}
+
+ public void setDomainId(String domainId) {
+ this.domainId = domainId;
+ }
+
+ public void setDomain(String domain) {
+ this.domain = domain;
+ }
+
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
index d8b6384..7ef627e 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
@@ -16,6 +16,8 @@
// under the License.
package org.apache.cloudstack.api.response;
+import java.util.Map;
+
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
@@ -157,6 +159,10 @@
@Param(description = "true if additional configurations or extraconfig can be passed to Instances", since = "4.20.2")
private Boolean additionalConfigEnabled;
+ @SerializedName(ApiConstants.VPN_CUSTOMER_GATEWAY_PARAMETERS)
+ @Param(description = "Excluded and obsolete VPN customer gateway cryptographic parameters")
+ private Map<String, Object> vpnCustomerGatewayParameters;
+
public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
this.securityGroupsEnabled = securityGroupsEnabled;
}
@@ -288,4 +294,8 @@
public void setAdditionalConfigEnabled(Boolean additionalConfigEnabled) {
this.additionalConfigEnabled = additionalConfigEnabled;
}
+
+ public void setVpnCustomerGatewayParameters(Map<String, Object> vpnCustomerGatewayParameters) {
+ this.vpnCustomerGatewayParameters = vpnCustomerGatewayParameters;
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DomainResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DomainResponse.java
index e018b1a..453c6b2 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/DomainResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/DomainResponse.java
@@ -16,21 +16,21 @@
// under the License.
package org.apache.cloudstack.api.response;
-import com.google.gson.annotations.SerializedName;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseResponseWithAnnotations;
+import org.apache.cloudstack.api.BaseResponseWithTagInformation;
import org.apache.cloudstack.api.EntityReference;
import com.cloud.domain.Domain;
import com.cloud.serializer.Param;
-
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import com.google.gson.annotations.SerializedName;
@EntityReference(value = Domain.class)
-public class DomainResponse extends BaseResponseWithAnnotations implements ResourceLimitAndCountResponse, SetResourceIconResponse {
+public class DomainResponse extends BaseResponseWithTagInformation implements ResourceLimitAndCountResponse, SetResourceIconResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "The ID of the domain")
private String id;
@@ -589,4 +589,8 @@
public void setTaggedResourceLimitsAndCounts(List<TaggedResourceLimitAndCountResponse> taggedResourceLimitsAndCounts) {
this.taggedResources = taggedResourceLimitsAndCounts;
}
+
+ public void setTags(Set<ResourceTagResponse> tags) {
+ this.tags = tags;
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/Site2SiteCustomerGatewayResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/Site2SiteCustomerGatewayResponse.java
index 4e58202..b121ef7 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/Site2SiteCustomerGatewayResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/Site2SiteCustomerGatewayResponse.java
@@ -114,6 +114,14 @@
@Param(description = "Which IKE Version to use, one of ike (autoselect), IKEv1, or IKEv2. Defaults to ike")
private String ikeVersion;
+ @SerializedName(ApiConstants.OBSOLETE_PARAMETERS)
+ @Param(description = "Contains the list of obsolete/insecure cryptographic parameters that the vpn customer gateway is using.", since = "4.23.0")
+ private String obsoleteParameters;
+
+ @SerializedName(ApiConstants.EXCLUDED_PARAMETERS)
+ @Param(description = "Contains the list of excluded/not allowed cryptographic parameters that the vpn customer gateway is using.", since = "4.23.0")
+ private String excludedParameters;
+
public void setId(String id) {
this.id = id;
}
@@ -202,4 +210,12 @@
this.domainPath = domainPath;
}
+ public void setContainsObsoleteParameters(String obsoleteParameters) {
+ this.obsoleteParameters = obsoleteParameters;
+ }
+
+ public void setContainsExcludedParameters(String excludedParameters) {
+ this.excludedParameters = excludedParameters;
+ }
+
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/SslCertResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/SslCertResponse.java
index ff2f956..d4add82 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/SslCertResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/SslCertResponse.java
@@ -27,8 +27,6 @@
import org.apache.cloudstack.network.tls.SslCert;
import com.cloud.serializer.Param;
-//import org.apache.cloudstack.api.EntityReference;
-
@EntityReference(value = SslCert.class)
public class SslCertResponse extends BaseResponse {
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java
index e69f636..a3ed88c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java
@@ -126,6 +126,10 @@
@Param(description = "The public netmask for the System VM")
private String publicNetmask;
+ @SerializedName("storageip")
+ @Param(description = "the ip address for the system VM on the storage network")
+ private String storageIp;
+
@SerializedName("templateid")
@Param(description = "The Template ID for the System VM")
private String templateId;
@@ -355,6 +359,14 @@
this.publicNetmask = publicNetmask;
}
+ public String getStorageIp() {
+ return storageIp;
+ }
+
+ public void setStorageIp(String storageIp) {
+ this.storageIp = storageIp;
+ }
+
public String getTemplateId() {
return templateId;
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/TrafficTypeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/TrafficTypeResponse.java
index bbf7159..2b8af97 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/TrafficTypeResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/TrafficTypeResponse.java
@@ -56,6 +56,14 @@
@Param(description = "The Network name label of the physical device dedicated to this traffic on a HyperV host")
private String hypervNetworkLabel;
+ @SerializedName(ApiConstants.VLAN)
+ @Param(description = "The VLAN id to be used for Management traffic by VMware host")
+ private String vlan;
+
+ @SerializedName(ApiConstants.ISOLATION_METHODS)
+ @Param(description = "isolation methods for the physical network traffic")
+ private String isolationMethods;
+
@SerializedName(ApiConstants.OVM3_NETWORK_LABEL)
@Param(description = "The Network name of the physical device dedicated to this traffic on an OVM3 host")
private String ovm3NetworkLabel;
@@ -128,4 +136,20 @@
public void setOvm3Label(String ovm3Label) {
this.ovm3NetworkLabel = ovm3Label;
}
+
+ public String getIsolationMethods() {
+ return isolationMethods;
+ }
+
+ public void setIsolationMethods(String isolationMethods) {
+ this.isolationMethods = isolationMethods;
+ }
+
+ public String getVlan() {
+ return vlan;
+ }
+
+ public void setVlan(String vlan) {
+ this.vlan = vlan;
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
index db05131..cbaf614 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
@@ -136,6 +136,8 @@
*/
BackupOffering importBackupOffering(final ImportBackupOfferingCmd cmd);
+ List<Long> getBackupOfferingDomains(final Long offeringId);
+
/**
* List backup offerings
* @param ListBackupOfferingsCmd API cmd
diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java b/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java
index 32a7143..23b8092 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java
@@ -124,6 +124,10 @@
*/
boolean supportsInstanceFromBackup();
+ default boolean supportsMemoryVmSnapshot() {
+ return true;
+ }
+
/**
* Returns the backup storage usage (Used, Total) for a backup provider
* @param zoneId the zone for which to return metrics
diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupService.java b/api/src/main/java/org/apache/cloudstack/backup/BackupService.java
index d4beb62..3ba2978 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/BackupService.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/BackupService.java
@@ -34,4 +34,11 @@
* @return backup provider
*/
BackupProvider getBackupProvider(final Long zoneId);
+
+ /**
+ * Find backup provider by name
+ * @param name backup provider name
+ * @return backup provider
+ */
+ BackupProvider getBackupProvider(final String name);
}
diff --git a/api/src/main/java/org/apache/cloudstack/context/CallContext.java b/api/src/main/java/org/apache/cloudstack/context/CallContext.java
index 69376e4..4cefd78 100644
--- a/api/src/main/java/org/apache/cloudstack/context/CallContext.java
+++ b/api/src/main/java/org/apache/cloudstack/context/CallContext.java
@@ -180,9 +180,7 @@
}
s_currentContext.set(callingContext);
ThreadContext.push("ctx-" + UuidUtils.first(contextId));
- if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Registered: " + callingContext);
- }
+ LOGGER.trace("Registered: {}", callingContext);
s_currentContextStack.get().push(callingContext);
@@ -279,9 +277,7 @@
return null;
}
s_currentContext.remove();
- if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Unregistered: " + context);
- }
+ LOGGER.trace("Unregistered: {}", context);
String contextId = context.getContextId();
String sessionIdOnStack = null;
String sessionIdPushedToNDC = "ctx-" + UuidUtils.first(contextId);
@@ -289,9 +285,7 @@
if (sessionIdOnStack.isEmpty() || sessionIdPushedToNDC.equals(sessionIdOnStack)) {
break;
}
- if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Popping from NDC: " + contextId);
- }
+ LOGGER.trace("Popping from NDC: {}", contextId);
}
Stack<CallContext> stack = s_currentContextStack.get();
diff --git a/api/src/main/java/org/apache/cloudstack/context/LogContext.java b/api/src/main/java/org/apache/cloudstack/context/LogContext.java
index c367975..24b9209 100644
--- a/api/src/main/java/org/apache/cloudstack/context/LogContext.java
+++ b/api/src/main/java/org/apache/cloudstack/context/LogContext.java
@@ -136,9 +136,7 @@
}
s_currentContext.set(callingContext);
ThreadContext.put("logcontextid", UuidUtils.first(contextId));
- if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Registered for log: " + callingContext);
- }
+ LOGGER.trace("Registered for log: {}", callingContext);
return callingContext;
}
@@ -207,9 +205,7 @@
LogContext context = s_currentContext.get();
if (context != null) {
s_currentContext.remove();
- if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Unregistered: " + context);
- }
+ LOGGER.trace("Unregistered: {}", context);
}
ThreadContext.clearMap();
}
diff --git a/api/src/test/java/com/cloud/cpu/CPUTest.java b/api/src/test/java/com/cloud/cpu/CPUTest.java
index dfedf21..0a059cf 100644
--- a/api/src/test/java/com/cloud/cpu/CPUTest.java
+++ b/api/src/test/java/com/cloud/cpu/CPUTest.java
@@ -28,6 +28,7 @@
assertEquals("i686", CPU.CPUArch.x86.getType());
assertEquals("x86_64", CPU.CPUArch.amd64.getType());
assertEquals("aarch64", CPU.CPUArch.arm64.getType());
+ assertEquals("s390x", CPU.CPUArch.s390x.getType());
}
@Test
@@ -35,6 +36,7 @@
assertEquals(32, CPU.CPUArch.x86.getBits());
assertEquals(64, CPU.CPUArch.amd64.getBits());
assertEquals(64, CPU.CPUArch.arm64.getBits());
+ assertEquals(64, CPU.CPUArch.s390x.getBits());
}
@Test
@@ -42,6 +44,7 @@
assertEquals(CPU.CPUArch.x86, CPU.CPUArch.fromType("i686"));
assertEquals(CPU.CPUArch.amd64, CPU.CPUArch.fromType("x86_64"));
assertEquals(CPU.CPUArch.arm64, CPU.CPUArch.fromType("aarch64"));
+ assertEquals(CPU.CPUArch.s390x, CPU.CPUArch.fromType("s390x"));
}
@Test
@@ -61,7 +64,7 @@
@Test
public void testCPUArchGetTypesAsCSV() {
- String expectedCSV = "i686,x86_64,aarch64";
+ String expectedCSV = "i686,x86_64,aarch64,s390x";
assertEquals(expectedCSV, CPU.CPUArch.getTypesAsCSV());
}
}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmdTest.java
new file mode 100644
index 0000000..51b1cd9
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmdTest.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.config;
+
+import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.apache.cloudstack.config.Configuration;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.crypt.DBEncryptionUtil;
+
+@RunWith(MockitoJUnitRunner.class)
+public class UpdateCfgCmdTest {
+
+ private UpdateCfgCmd updateCfgCmd;
+
+ private MockedStatic<DBEncryptionUtil> mockedStatic;
+
+ @Before
+ public void setUp() {
+ updateCfgCmd = new UpdateCfgCmd();
+ mockedStatic = Mockito.mockStatic(DBEncryptionUtil.class);
+ }
+
+ @After
+ public void tearDown() {
+ mockedStatic.close();
+ }
+
+ @Test
+ public void setResponseValueSetsEncryptedValueWhenConfigurationIsEncrypted() {
+ ConfigurationResponse response = new ConfigurationResponse();
+ Configuration cfg = Mockito.mock(Configuration.class);
+ Mockito.when(cfg.isEncrypted()).thenReturn(true);
+ Mockito.when(cfg.getValue()).thenReturn("testValue");
+ Mockito.when(DBEncryptionUtil.encrypt("testValue")).thenReturn("encryptedValue");
+ updateCfgCmd.setResponseValue(response, cfg);
+ Assert.assertEquals("encryptedValue", response.getValue());
+ }
+
+ @Test
+ public void setResponseValueSetsPlainValueWhenConfigurationIsNotEncrypted() {
+ ConfigurationResponse response = new ConfigurationResponse();
+ Configuration cfg = Mockito.mock(Configuration.class);
+ Mockito.when(cfg.isEncrypted()).thenReturn(false);
+ Mockito.when(cfg.getValue()).thenReturn("testValue");
+ updateCfgCmd.setResponseValue(response, cfg);
+ Assert.assertEquals("testValue", response.getValue());
+ }
+
+ @Test
+ public void setResponseValueHandlesNullConfigurationValueGracefully() {
+ ConfigurationResponse response = new ConfigurationResponse();
+ Configuration cfg = Mockito.mock(Configuration.class);
+ Mockito.when(cfg.isEncrypted()).thenReturn(false);
+ Mockito.when(cfg.getValue()).thenReturn(null);
+ updateCfgCmd.setResponseValue(response, cfg);
+ Assert.assertNull(response.getValue());
+ }
+
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/volume/ImportVolumeCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/volume/ImportVolumeCmdTest.java
index a7c41b9..235acb1 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/admin/volume/ImportVolumeCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/volume/ImportVolumeCmdTest.java
@@ -46,7 +46,7 @@
Long projectId = 5L;
long accountId = 6L;
- Mockito.when(accountService.finalyzeAccountId(accountName, domainId, projectId, true)).thenReturn(accountId);
+ Mockito.when(accountService.finalizeAccountId(accountName, domainId, projectId, true)).thenReturn(accountId);
ImportVolumeCmd cmd = new ImportVolumeCmd();
ReflectionTestUtils.setField(cmd, "path", path);
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/offering/DomainAndZoneIdResolverTest.java b/api/src/test/java/org/apache/cloudstack/api/command/offering/DomainAndZoneIdResolverTest.java
new file mode 100644
index 0000000..e679bbf
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/offering/DomainAndZoneIdResolverTest.java
@@ -0,0 +1,149 @@
+// 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.offering;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.LongFunction;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.domain.Domain;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.utils.db.EntityManager;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.ServerApiException;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class DomainAndZoneIdResolverTest {
+ static class TestCmd extends BaseCmd implements DomainAndZoneIdResolver {
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ // No implementation needed for tests
+ }
+
+ @Override
+ public String getCommandName() {
+ return "test";
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return 1L;
+ }
+ }
+
+ private void setEntityMgr(final BaseCmd cmd, final EntityManager entityMgr) throws Exception {
+ Field f = BaseCmd.class.getDeclaredField("_entityMgr");
+ f.setAccessible(true);
+ f.set(cmd, entityMgr);
+ }
+
+ @Test
+ public void resolveDomainIds_usesDefaultProviderWhenEmpty() {
+ TestCmd cmd = new TestCmd();
+
+ final LongFunction<List<Long>> defaultsProvider = id -> Arrays.asList(100L, 200L);
+
+ List<Long> result = cmd.resolveDomainIds("", 42L, defaultsProvider, "offering");
+ Assert.assertEquals(Arrays.asList(100L, 200L), result);
+ }
+
+ @Test
+ public void resolveDomainIds_resolvesValidUuids() throws Exception {
+ TestCmd cmd = new TestCmd();
+
+ EntityManager em = mock(EntityManager.class);
+ setEntityMgr(cmd, em);
+
+ Domain d1 = mock(Domain.class);
+ when(d1.getId()).thenReturn(10L);
+ Domain d2 = mock(Domain.class);
+ when(d2.getId()).thenReturn(20L);
+
+ when(em.findByUuid(Domain.class, "uuid1")).thenReturn(d1);
+ when(em.findByUuid(Domain.class, "uuid2")).thenReturn(d2);
+
+ List<Long> ids = cmd.resolveDomainIds("uuid1, public, uuid2", null, null, "template");
+ Assert.assertEquals(Arrays.asList(10L, 20L), ids);
+ }
+
+ @Test
+ public void resolveDomainIds_invalidUuid_throws() throws Exception {
+ TestCmd cmd = new TestCmd();
+
+ EntityManager em = mock(EntityManager.class);
+ setEntityMgr(cmd, em);
+
+ when(em.findByUuid(Domain.class, "bad-uuid")).thenReturn(null);
+
+ Assert.assertThrows(InvalidParameterValueException.class,
+ () -> cmd.resolveDomainIds("bad-uuid", null, null, "offering"));
+ }
+
+ @Test
+ public void resolveZoneIds_usesDefaultProviderWhenEmpty() {
+ TestCmd cmd = new TestCmd();
+
+ final LongFunction<List<Long>> defaultsProvider = id -> Collections.singletonList(300L);
+
+ List<Long> result = cmd.resolveZoneIds("", 99L, defaultsProvider, "offering");
+ Assert.assertEquals(Collections.singletonList(300L), result);
+ }
+
+ @Test
+ public void resolveZoneIds_resolvesValidUuids() throws Exception {
+ TestCmd cmd = new TestCmd();
+
+ EntityManager em = mock(EntityManager.class);
+ setEntityMgr(cmd, em);
+
+ DataCenter z1 = mock(DataCenter.class);
+ when(z1.getId()).thenReturn(30L);
+ DataCenter z2 = mock(DataCenter.class);
+ when(z2.getId()).thenReturn(40L);
+
+ when(em.findByUuid(DataCenter.class, "zone-1")).thenReturn(z1);
+ when(em.findByUuid(DataCenter.class, "zone-2")).thenReturn(z2);
+
+ List<Long> ids = cmd.resolveZoneIds("zone-1, all, zone-2", null, null, "service");
+ Assert.assertEquals(Arrays.asList(30L, 40L), ids);
+ }
+
+ @Test
+ public void resolveZoneIds_invalidUuid_throws() throws Exception {
+ TestCmd cmd = new TestCmd();
+
+ EntityManager em = mock(EntityManager.class);
+ setEntityMgr(cmd, em);
+
+ when(em.findByUuid(DataCenter.class, "bad-zone")).thenReturn(null);
+
+ Assert.assertThrows(InvalidParameterValueException.class,
+ () -> cmd.resolveZoneIds("bad-zone", null, null, "offering"));
+ }
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/test/ScaleVMCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/test/ScaleVMCmdTest.java
index 46ff0e1..1150c40 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/test/ScaleVMCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/test/ScaleVMCmdTest.java
@@ -78,10 +78,6 @@
scaleVMCmd._responseGenerator = responseGenerator;
UserVmResponse userVmResponse = Mockito.mock(UserVmResponse.class);
- //List<UserVmResponse> list = Mockito.mock(UserVmResponse.class);
- //list.add(userVmResponse);
- //LinkedList<UserVmResponse> mockedList = Mockito.mock(LinkedList.class);
- //Mockito.when(mockedList.get(0)).thenReturn(userVmResponse);
List<UserVmResponse> list = new LinkedList<UserVmResponse>();
list.add(userVmResponse);
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/userdata/RegisterUserDataCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/userdata/RegisterUserDataCmdTest.java
index e960552..8fac32d 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/user/userdata/RegisterUserDataCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/userdata/RegisterUserDataCmdTest.java
@@ -97,7 +97,7 @@
ReflectionTestUtils.setField(cmd, "name", "testUserdataName");
ReflectionTestUtils.setField(cmd, "userData", "testUserdata");
- when(_accountService.finalyzeAccountId(ACCOUNT_NAME, DOMAIN_ID, PROJECT_ID, true)).thenReturn(200L);
+ when(_accountService.finalizeAccountId(ACCOUNT_NAME, DOMAIN_ID, PROJECT_ID, true)).thenReturn(200L);
Assert.assertEquals("testUserdataName", cmd.getName());
Assert.assertEquals("testUserdata", cmd.getUserData());
diff --git a/client/bindir/cloud-setup-management.in b/client/bindir/cloud-setup-management.in
index 84c87ae..b4fe76c 100755
--- a/client/bindir/cloud-setup-management.in
+++ b/client/bindir/cloud-setup-management.in
@@ -36,6 +36,106 @@
from cloudutils.globalEnv import globalEnv
from cloudutils.serviceConfigServer import cloudManagementConfig
from optparse import OptionParser
+import urllib.request
+import configparser
+import hashlib
+
+SYSTEMVM_TEMPLATES_PATH = "/usr/share/cloudstack-management/templates/systemvm"
+SYSTEMVM_TEMPLATES_METADATA_FILE = SYSTEMVM_TEMPLATES_PATH + "/metadata.ini"
+
+def verify_sha512_checksum(file_path, expected_checksum):
+ sha512 = hashlib.sha512()
+ try:
+ with open(file_path, "rb") as f:
+ for chunk in iter(lambda: f.read(8192), b""):
+ sha512.update(chunk)
+ return sha512.hexdigest().lower() == expected_checksum.lower()
+ except Exception as e:
+ print(f"Failed to verify checksum for {file_path}: {e}")
+ return False
+
+def download_file(url, dest_path, chunk_size=8 * 1024 * 1024):
+ """
+ Downloads a file from the given URL to the specified destination path in chunks.
+ """
+ try:
+ with urllib.request.urlopen(url) as response:
+ total_size = response.length if response.length else None
+ downloaded = 0
+ try:
+ with open(dest_path, 'wb') as out_file:
+ while True:
+ chunk = response.read(chunk_size)
+ if not chunk:
+ break
+ out_file.write(chunk)
+ downloaded += len(chunk)
+ if total_size:
+ print(f"Downloaded {downloaded / (1024 * 1024):.2f}MB of {total_size / (1024 * 1024):.2f}MB", end='\r')
+ except PermissionError as pe:
+ print(f"Permission denied: {dest_path}")
+ raise
+ print(f"\nDownloaded file from {url} to {dest_path}")
+ except Exception as e:
+ print(f"Failed to download file: {e}")
+ raise
+
+def download_template_if_needed(template, url, filename, checksum):
+ dest_path = os.path.join(SYSTEMVM_TEMPLATES_PATH, filename)
+ if os.path.exists(dest_path):
+ if checksum and verify_sha512_checksum(dest_path, checksum):
+ print(f"{template} System VM template already exists at {dest_path} with valid checksum, skipping download.")
+ return
+ else:
+ print(f"{template} System VM template at {dest_path} has invalid or missing checksum, re-downloading...")
+ else:
+ print(f"Downloading {template} System VM template from {url} to {dest_path}...")
+ try:
+ download_file(url, dest_path)
+ #After download, verify checksum if provided
+ if checksum:
+ if verify_sha512_checksum(dest_path, checksum):
+ print(f"{template} System VM template downloaded and verified successfully.")
+ else:
+ print(f"ERROR: Checksum verification failed for {template} System VM template after download.")
+ except Exception as e:
+ print(f"ERROR: Failed to download {template} System VM template: {e}")
+
+def collect_template_metadata(selected_templates, options):
+ template_metadata_list = []
+ if not os.path.exists(SYSTEMVM_TEMPLATES_METADATA_FILE):
+ print(f"ERROR: System VM templates metadata file not found at {SYSTEMVM_TEMPLATES_METADATA_FILE}, cannot download templates.")
+ sys.exit(1)
+ config = configparser.ConfigParser()
+ config.read(SYSTEMVM_TEMPLATES_METADATA_FILE)
+ template_repo_url = None
+ if options.systemvm_templates_repository:
+ if "default" in config and "downloadrepository" in config["default"]:
+ template_repo_url = config["default"]["downloadrepository"].strip()
+ if not template_repo_url:
+ print("ERROR: downloadrepository value is empty in metadata file, cannot use --systemvm-template-repository option.")
+ sys.exit(1)
+ for template in selected_templates:
+ if template in config:
+ url = config[template].get("downloadurl")
+ filename = config[template].get("filename")
+ checksum = config[template].get("checksum")
+ if url and filename:
+ if template_repo_url:
+ url = url.replace(template_repo_url, options.systemvm_templates_repository)
+ template_metadata_list.append({
+ "template": template,
+ "url": url,
+ "filename": filename,
+ "checksum": checksum
+ })
+ else:
+ print(f"ERROR: URL or filename not found for {template} System VM template in metadata.")
+ sys.exit(1)
+ else:
+ print(f"ERROR: No metadata found for {template} System VM template.")
+ sys.exit(1)
+ return template_metadata_list
if __name__ == '__main__':
initLoging("@MSLOGDIR@/setupManagement.log")
@@ -45,6 +145,16 @@
parser.add_option("--https", action="store_true", dest="https", help="Enable HTTPs connection of management server")
parser.add_option("--tomcat7", action="store_true", dest="tomcat7", help="Depreciated option, don't use it")
parser.add_option("--no-start", action="store_true", dest="nostart", help="Do not start management server after successful configuration")
+ parser.add_option(
+ "--systemvm-templates",
+ dest="systemvm_templates",
+ help="Specify System VM templates to download: all, kvm-aarch64, kvm-x86_64, xenserver, vmware or comma-separated list of hypervisor combinations (e.g., kvm-x86_64,xenserver). Default is kvm-x86_64.",
+ )
+ parser.add_option(
+ "--systemvm-templates-repository",
+ dest="systemvm_templates_repository",
+ help="Specify the URL to download System VM templates from."
+ )
(options, args) = parser.parse_args()
if options.https:
glbEnv.svrMode = "HttpsServer"
@@ -53,6 +163,34 @@
if options.nostart:
glbEnv.noStart = True
+ available_templates = ["kvm-aarch64", "kvm-x86_64", "xenserver", "vmware"]
+ templates_arg = options.systemvm_templates
+
+ selected_templates = ["kvm-x86_64"]
+ if templates_arg:
+ templates_list = [t.strip().lower() for t in templates_arg.split(",")]
+ if "all" in templates_list:
+ if len(templates_list) > 1:
+ print("WARNING: 'all' specified for System VM templates, ignoring other specified templates.")
+ selected_templates = available_templates
+ else:
+ invalid_templates = []
+ for t in templates_list:
+ if t in available_templates:
+ if t not in selected_templates:
+ selected_templates.append(t)
+ else:
+ if t not in invalid_templates:
+ invalid_templates.append(t)
+ if invalid_templates:
+ print(f"ERROR: Invalid System VM template names provided: {', '.join(invalid_templates)}")
+ sys.exit(1)
+ print(f"Selected systemvm templates to download: {', '.join(selected_templates) if selected_templates else 'None'}")
+
+ template_metadata_list = []
+ if selected_templates:
+ template_metadata_list = collect_template_metadata(selected_templates, options)
+
glbEnv.mode = "Server"
print("Starting to configure CloudStack Management Server:")
@@ -74,3 +212,6 @@
syscfg.restore()
except:
pass
+
+ for meta in template_metadata_list:
+ download_template_if_needed(meta["template"], meta["url"], meta["filename"], meta["checksum"])
diff --git a/client/conf/server.properties.in b/client/conf/server.properties.in
index 5958486..7c5e3f9 100644
--- a/client/conf/server.properties.in
+++ b/client/conf/server.properties.in
@@ -62,3 +62,8 @@
# Thread pool configuration
#threads.min=10
#threads.max=500
+
+# The URL prefix for the system VM templates repository. When downloading system VM templates, the server replaces the
+# `downloadrepository` key value from the metadata file in template URLs. If not specified, the original template URL
+# will be used for download.
+# system.vm.templates.download.repository=http://download.cloudstack.org/systemvm/
diff --git a/client/pom.xml b/client/pom.xml
index 94d844b..b8dffe6 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
@@ -666,16 +666,22 @@
<build>
<plugins>
<plugin>
- <groupId>ru.concerteza.buildnumber</groupId>
- <artifactId>maven-jgit-buildnumber-plugin</artifactId>
- <version>1.2.6</version>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>buildnumber-maven-plugin</artifactId>
+ <version>3.2.0</version>
<executions>
<execution>
<id>git-buildnumber</id>
<goals>
- <goal>extract-buildnumber</goal>
+ <goal>create</goal>
</goals>
<phase>prepare-package</phase>
+ <configuration>
+ <doCheck>false</doCheck>
+ <doUpdate>false</doUpdate>
+ <getRevisionOnlyOnce>true</getRevisionOnlyOnce>
+ <revisionOnScmFailure>unknown</revisionOnScmFailure>
+ </configuration>
</execution>
</executions>
</plugin>
@@ -688,11 +694,11 @@
<mainClass>org.apache.cloudstack.ServerDaemon</mainClass>
</manifest>
<manifestEntries>
- <X-Git-Branch>${git.branch}</X-Git-Branch>
- <X-Git-Tag>${git.tag}</X-Git-Tag>
- <X-Git-Revision>${git.revision}</X-Git-Revision>
- <Implementation-Revision>${git.revision}</Implementation-Revision>
- <Implementation-Branch>${git.branch}</Implementation-Branch>
+ <X-Git-Branch>${scmBranch}</X-Git-Branch>
+ <X-Git-Tag>${project.version}</X-Git-Tag>
+ <X-Git-Revision>${buildNumber}</X-Git-Revision>
+ <Implementation-Revision>${buildNumber}</Implementation-Revision>
+ <Implementation-Branch>${scmBranch}</Implementation-Branch>
</manifestEntries>
</archive>
</configuration>
diff --git a/core/pom.xml b/core/pom.xml
index 1bf7c28..f91a330 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java
index 7736bea..128652f 100644
--- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java
+++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java
@@ -629,9 +629,6 @@
}
}
result.addAll(gSection);
- // TODO decide under what circumstances these options are needed
- // result.add("\tnokqueue");
- // result.add("\tnopoll");
result.add(blankLine);
final List<String> dSection = Arrays.asList(defaultsSection);
diff --git a/core/src/main/java/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java b/core/src/main/java/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java
index 3ac8303..253a260 100644
--- a/core/src/main/java/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java
+++ b/core/src/main/java/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java
@@ -57,8 +57,10 @@
private String nfsVersion;
- public TemplateOrVolumePostUploadCommand(long entityId, String entityUUID, String absolutePath, String checksum, String type, String name, String imageFormat, String dataTo,
- String dataToRole) {
+ private long zoneId;
+
+ public TemplateOrVolumePostUploadCommand(long entityId, String entityUUID, String absolutePath, String checksum,
+ String type, String name, String imageFormat, String dataTo, String dataToRole, long zoneId) {
this.entityId = entityId;
this.entityUUID = entityUUID;
this.absolutePath = absolutePath;
@@ -68,9 +70,7 @@
this.imageFormat = imageFormat;
this.dataTo = dataTo;
this.dataToRole = dataToRole;
- }
-
- public TemplateOrVolumePostUploadCommand() {
+ this.zoneId = zoneId;
}
public String getRemoteEndPoint() {
@@ -216,4 +216,8 @@
public long getProcessTimeout() {
return processTimeout;
}
+
+ public long getZoneId() {
+ return zoneId;
+ }
}
diff --git a/core/src/test/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResourceTest.java b/core/src/test/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResourceTest.java
index 2012425..4196587 100644
--- a/core/src/test/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResourceTest.java
+++ b/core/src/test/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResourceTest.java
@@ -417,8 +417,6 @@
// FIXME Check the json content
assertEquals(VRScripts.UPDATE_CONFIG, script);
assertEquals(VRScripts.NETWORK_ACL_CONFIG, args);
- // assertEquals(args, " -d eth3 -M 01:23:45:67:89:AB -i 192.168.1.1 -m 24 -a Egress:ALL:0:0:192.168.0.1/24-192.168.0.2/24:ACCEPT:," +
- // "Ingress:ICMP:0:0:192.168.0.1/24-192.168.0.2/24:DROP:,Ingress:TCP:20:80:192.168.0.1/24-192.168.0.2/24:ACCEPT:,");
break;
case 2:
assertEquals(VRScripts.UPDATE_CONFIG, script);
@@ -464,8 +462,6 @@
private void verifyArgs(final SetupGuestNetworkCommand cmd, final String script, final String args) {
// TODO Check the contents of the json file
- //assertEquals(script, VRScripts.VPC_GUEST_NETWORK);
- //assertEquals(args, " -C -M 01:23:45:67:89:AB -d eth4 -i 10.1.1.2 -g 10.1.1.1 -m 24 -n 10.1.1.0 -s 8.8.8.8,8.8.4.4 -e cloud.test");
}
@Test
diff --git a/debian/changelog b/debian/changelog
index 6d288af..0225113 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,12 +1,12 @@
-cloudstack (4.22.1.0-SNAPSHOT) unstable; urgency=low
+cloudstack (4.23.0.0-SNAPSHOT) unstable; urgency=low
- * Update the version to 4.22.1.0-SNAPSHOT
+ * Update the version to 4.23.0.0-SNAPSHOT
-- the Apache CloudStack project <dev@cloudstack.apache.org> Thu, 30 Oct 2025 19:23:55 +0530
-cloudstack (4.22.1.0-SNAPSHOT-SNAPSHOT) unstable; urgency=low
+cloudstack (4.23.0.0-SNAPSHOT-SNAPSHOT) unstable; urgency=low
- * Update the version to 4.22.1.0-SNAPSHOT-SNAPSHOT
+ * Update the version to 4.23.0.0-SNAPSHOT-SNAPSHOT
-- the Apache CloudStack project <dev@cloudstack.apache.org> Thu, Aug 28 11:58:36 2025 +0530
diff --git a/developer/pom.xml b/developer/pom.xml
index de6a8ef..0a0979e 100644
--- a/developer/pom.xml
+++ b/developer/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
@@ -66,7 +66,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
- <version>1.0-alpha-2</version>
+ <version>1.2.1</version>
<executions>
<execution>
<phase>initialize</phase>
diff --git a/engine/api/pom.xml b/engine/api/pom.xml
index 2f7e15a..cb50ef0 100644
--- a/engine/api/pom.xml
+++ b/engine/api/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
index 168822c..6f8c463 100644
--- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
@@ -90,11 +90,11 @@
"volume.allocation.algorithm",
"Advanced",
"random",
- "Order in which storage pool within a cluster will be considered for volume allocation. The value can be 'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit', or 'firstfitleastconsumed'.",
+ "Order in which storage pool within a cluster will be considered for volume allocation. The value can be 'random', 'firstfit', 'userdispersing', or 'firstfitleastconsumed'.",
true,
ConfigKey.Scope.Global, null, null, null, null, null,
ConfigKey.Kind.Select,
- "random,firstfit,userdispersing,userconcentratedpod_random,userconcentratedpod_firstfit,firstfitleastconsumed");
+ "random,firstfit,userdispersing,firstfitleastconsumed");
VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType)
throws ConcurrentOperationException, StorageUnavailableException;
diff --git a/engine/components-api/pom.xml b/engine/components-api/pom.xml
index 8caf8cc..49d41d3 100644
--- a/engine/components-api/pom.xml
+++ b/engine/components-api/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java b/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java
index 7fe19c3..46993b0 100644
--- a/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java
+++ b/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java
@@ -49,6 +49,10 @@
"Percentage (as a value between 0 and 1) of guest network IPv6 subnet utilization above which alerts will be sent.",
true);
+ ConfigKey<String> AllowedRepetitiveAlertTypes = new ConfigKey<>(ConfigKey.CATEGORY_ALERT, String.class,
+ "alert.allowed.repetitive.types", "",
+ "Comma-separated list of alert types (by name) that can be sent multiple times", true);
+
void clearAlert(AlertType alertType, long dataCenterId, long podId);
void recalculateCapacity();
diff --git a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
index 5c7348c..3c62738 100644
--- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
+++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
@@ -235,7 +235,7 @@
/**
* should we execute in sequence not involving any storages?
- * @return tru if commands should execute in sequence
+ * @return true if commands should execute in sequence
*/
static boolean shouldExecuteInSequenceOnVmware() {
return shouldExecuteInSequenceOnVmware(null, null);
diff --git a/engine/components-api/src/main/java/com/cloud/vm/VmWorkSerializer.java b/engine/components-api/src/main/java/com/cloud/vm/VmWorkSerializer.java
index bd6b52d..e4fdc0c 100644
--- a/engine/components-api/src/main/java/com/cloud/vm/VmWorkSerializer.java
+++ b/engine/components-api/src/main/java/com/cloud/vm/VmWorkSerializer.java
@@ -61,7 +61,6 @@
// use java binary serialization instead
//
return JobSerializerHelper.toObjectSerializedString(work);
- // return s_gson.toJson(work);
}
public static <T extends VmWork> T deserialize(Class<?> clazz, String workInJsonText) {
@@ -69,6 +68,5 @@
// use java binary serialization instead
//
return (T)JobSerializerHelper.fromObjectSerializedString(workInJsonText);
- // return (T)s_gson.fromJson(workInJsonText, clazz);
}
}
diff --git a/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java b/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java
index 997b413..6831552 100644
--- a/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java
+++ b/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java
@@ -31,7 +31,7 @@
static final ConfigKey<Integer> VMSnapshotExpireInterval = new ConfigKey<Integer>("Advanced", Integer.class, "vmsnapshot.expire.interval", "-1",
"VM Snapshot expire interval in hours", true, ConfigKey.Scope.Account);
- ConfigKey<Integer> VMSnapshotMax = new ConfigKey<Integer>("Advanced", Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a single vm", true, ConfigKey.Scope.Global);
+ ConfigKey<Integer> VMSnapshotMax = new ConfigKey<Integer>("Advanced", Integer.class, "vmsnapshot.max", "10", "Maximum VM snapshots for a single VM", true, ConfigKey.Scope.Account);
/**
* Delete all VM snapshots belonging to one VM
@@ -42,7 +42,7 @@
boolean deleteAllVMSnapshots(long id, VMSnapshot.Type type);
/**
- * Sync VM snapshot state when VM snapshot in reverting or snapshoting or expunging state
+ * Sync VM snapshot state when VM snapshot in reverting or snapshotting or expunging state
* Used for fullsync after agent connects
*
* @param vm, the VM in question
diff --git a/engine/orchestration/pom.xml b/engine/orchestration/pom.xml
index cd5578d..fda63d2 100755
--- a/engine/orchestration/pom.xml
+++ b/engine/orchestration/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java
index 3d398ca..439bdf9 100644
--- a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java
+++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java
@@ -1652,7 +1652,6 @@
final String reason = shutdown.getReason();
logger.info("Host {} has informed us that it is shutting down with reason {} and detail {}", attache, reason, shutdown.getDetail());
if (reason.equals(ShutdownCommand.Update)) {
- // disconnectWithoutInvestigation(attache, Event.UpdateNeeded);
throw new CloudRuntimeException("Agent update not implemented");
} else if (reason.equals(ShutdownCommand.Requested)) {
disconnectWithoutInvestigation(attache, Event.ShutdownRequested);
@@ -1753,7 +1752,6 @@
}
} catch (final UnsupportedVersionException e) {
logger.warn(e.getMessage());
- // upgradeAgent(task.getLink(), data, e.getReason());
} catch (final ClassNotFoundException e) {
final String message = String.format("Exception occurred when executing tasks! Error '%s'", e.getMessage());
logger.error(message);
diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java
index ffc9936..cfa0949 100644
--- a/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java
+++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java
@@ -965,7 +965,6 @@
synchronized (_agentToTransferIds) {
if (!_agentToTransferIds.isEmpty()) {
logger.debug("Found {} agents to transfer", _agentToTransferIds.size());
- // for (Long hostId : _agentToTransferIds) {
for (final Iterator<Long> iterator = _agentToTransferIds.iterator(); iterator.hasNext(); ) {
final Long hostId = iterator.next();
final AgentAttache attache = findAttache(hostId);
diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
index 86f4563..e8796fb 100755
--- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -935,7 +935,11 @@
throw new CloudRuntimeException(String.format("Unable to start a VM [%s] due to [%s].", vmUuid, e.getMessage()), e).add(VirtualMachine.class, vmUuid);
} catch (final ResourceUnavailableException e) {
if (e.getScope() != null && e.getScope().equals(VirtualRouter.class)){
- throw new CloudRuntimeException("Network is unavailable. Please contact administrator", e).add(VirtualMachine.class, vmUuid);
+ Account callingAccount = CallContext.current().getCallingAccount();
+ String errorSuffix = (callingAccount != null && callingAccount.getType() == Account.Type.ADMIN) ?
+ String.format("Failure: %s", e.getMessage()) :
+ "Please contact administrator.";
+ throw new CloudRuntimeException(String.format("The Network for VM %s is unavailable. %s", vmUuid, errorSuffix), e).add(VirtualMachine.class, vmUuid);
}
throw new CloudRuntimeException(String.format("Unable to start a VM [%s] due to [%s].", vmUuid, e.getMessage()), e).add(VirtualMachine.class, vmUuid);
}
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/dao/EngineHostDaoImpl.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/dao/EngineHostDaoImpl.java
index 2ad8d15..7f6571b 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/dao/EngineHostDaoImpl.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/dao/EngineHostDaoImpl.java
@@ -213,7 +213,6 @@
SequenceSearch = createSearchBuilder();
SequenceSearch.and("id", SequenceSearch.entity().getId(), SearchCriteria.Op.EQ);
- // SequenceSearch.addRetrieve("sequence", SequenceSearch.entity().getSequence());
SequenceSearch.done();
DirectlyConnectedSearch = createSearchBuilder();
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index af8ff83..a07fd13 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -1583,12 +1583,8 @@
vm.addDisk(disk);
}
- //if (vm.getType() == VirtualMachine.Type.User && vm.getTemplate().getFormat() == ImageFormat.ISO) {
if (vm.getType() == VirtualMachine.Type.User) {
_tmpltMgr.prepareIsoForVmProfile(vm, dest);
- //DataTO dataTO = tmplFactory.getTemplate(vm.getTemplate().getId(), DataStoreRole.Image, vm.getVirtualMachine().getDataCenterId()).getTO();
- //DiskTO iso = new DiskTO(dataTO, 3L, null, Volume.Type.ISO);
- //vm.addDisk(iso);
}
}
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/service/api/ProvisioningServiceImpl.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/service/api/ProvisioningServiceImpl.java
index 51e8766..ff75aa0 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/service/api/ProvisioningServiceImpl.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/service/api/ProvisioningServiceImpl.java
@@ -140,20 +140,12 @@
@Override
public List<PodEntity> listPods() {
- /*
- * Not in use now, just commented out.
- */
- //List<PodEntity> pods = new ArrayList<PodEntity>();
- //pods.add(new PodEntityImpl("pod-uuid-1", "pod1"));
- //pods.add(new PodEntityImpl("pod-uuid-2", "pod2"));
return null;
}
@Override
public List<ZoneEntity> listZones() {
List<ZoneEntity> zones = new ArrayList<ZoneEntity>();
- //zones.add(new ZoneEntityImpl("zone-uuid-1"));
- //zones.add(new ZoneEntityImpl("zone-uuid-2"));
return zones;
}
diff --git a/engine/pom.xml b/engine/pom.xml
index 821a4f8..2de84ea 100644
--- a/engine/pom.xml
+++ b/engine/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml
index 7d88f64..654cd14 100644
--- a/engine/schema/pom.xml
+++ b/engine/schema/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/ClusterVSMMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/ClusterVSMMapDaoImpl.java
index 02a7ac6..76058d2 100644
--- a/engine/schema/src/main/java/com/cloud/dc/dao/ClusterVSMMapDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/dc/dao/ClusterVSMMapDaoImpl.java
@@ -36,7 +36,6 @@
final SearchBuilder<ClusterVSMMapVO> VsmSearch;
public ClusterVSMMapDaoImpl() {
- //super();
ClusterSearch = createSearchBuilder();
ClusterSearch.and("clusterId", ClusterSearch.entity().getClusterId(), SearchCriteria.Op.EQ);
@@ -82,8 +81,6 @@
TransactionLegacy txn = TransactionLegacy.currentTxn();
txn.start();
ClusterVSMMapVO cluster = createForUpdate();
- //cluster.setClusterId(null);
- //cluster.setVsmId(null);
update(id, cluster);
diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java
index bb03a96..aec54e2 100644
--- a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java
@@ -31,7 +31,8 @@
private final SearchBuilder<DataCenterDetailVO> DetailSearch;
- DataCenterDetailsDaoImpl() {
+ public DataCenterDetailsDaoImpl() {
+ super();
DetailSearch = createSearchBuilder();
DetailSearch.and("zoneId", DetailSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ);
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java
index 8066b89..4e8b620 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java
@@ -598,7 +598,7 @@
public List<NetworkVO> listByPhysicalNetworkTrafficType(final long physicalNetworkId, final TrafficType trafficType) {
final SearchCriteria<NetworkVO> sc = AllFieldsSearch.create();
sc.setParameters("trafficType", trafficType);
- sc.setParameters("physicalNetwork", physicalNetworkId);
+ sc.setParameters("physicalNetworkId", physicalNetworkId);
return listBy(sc);
}
diff --git a/engine/schema/src/main/java/com/cloud/network/security/dao/VmRulesetLogDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/security/dao/VmRulesetLogDaoImpl.java
index 9a9ca80..7ed0ad0 100644
--- a/engine/schema/src/main/java/com/cloud/network/security/dao/VmRulesetLogDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/network/security/dao/VmRulesetLogDaoImpl.java
@@ -76,7 +76,6 @@
@Override
public int createOrUpdate(Set<Long> workItems) {
- //return createOrUpdateUsingBatch(workItems);
return createOrUpdateUsingMultiInsert(workItems);
}
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDao.java
index 6785c36..4c9f906 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDao.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDao.java
@@ -94,7 +94,7 @@
List<VMTemplateVO> listByParentTemplatetId(long parentTemplatetId);
- VMTemplateVO findLatestTemplateByName(String name, CPU.CPUArch arch);
+ VMTemplateVO findLatestTemplateByName(String name, HypervisorType hypervisorType, CPU.CPUArch arch);
List<VMTemplateVO> findTemplatesLinkedToUserdata(long userdataId);
@@ -103,4 +103,7 @@
List<Long> listIdsByTemplateTag(String tag);
List<Long> listIdsByExtensionId(long extensionId);
+
+ VMTemplateVO findActiveSystemTemplateByHypervisorArchAndUrlPath(HypervisorType hypervisorType,
+ CPU.CPUArch arch, String urlPathSuffix);
}
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java
index 7d46aa9..bcf8b39 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java
@@ -100,7 +100,6 @@
private SearchBuilder<VMTemplateVO> PublicIsoSearch;
private SearchBuilder<VMTemplateVO> UserIsoSearch;
private GenericSearchBuilder<VMTemplateVO, Long> CountTemplatesByAccount;
- // private SearchBuilder<VMTemplateVO> updateStateSearch;
private SearchBuilder<VMTemplateVO> AllFieldsSearch;
protected SearchBuilder<VMTemplateVO> ParentTemplateIdSearch;
private SearchBuilder<VMTemplateVO> InactiveUnremovedTmpltSearch;
@@ -246,13 +245,17 @@
@Override
- public VMTemplateVO findLatestTemplateByName(String name, CPU.CPUArch arch) {
+ public VMTemplateVO findLatestTemplateByName(String name, HypervisorType hypervisorType, CPU.CPUArch arch) {
SearchBuilder<VMTemplateVO> sb = createSearchBuilder();
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
+ sb.and("hypervisorType", sb.entity().getHypervisorType(), SearchCriteria.Op.EQ);
sb.and("arch", sb.entity().getArch(), SearchCriteria.Op.EQ);
sb.done();
SearchCriteria<VMTemplateVO> sc = sb.create();
sc.setParameters("name", name);
+ if (hypervisorType != null) {
+ sc.setParameters("hypervisorType", hypervisorType);
+ }
if (arch != null) {
sc.setParameters("arch", arch);
}
@@ -404,12 +407,6 @@
CountTemplatesByAccount.and("state", CountTemplatesByAccount.entity().getState(), SearchCriteria.Op.EQ);
CountTemplatesByAccount.done();
- // updateStateSearch = this.createSearchBuilder();
- // updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ);
- // updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ);
- // updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ);
- // updateStateSearch.done();
-
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
@@ -858,6 +855,37 @@
}
@Override
+ public VMTemplateVO findActiveSystemTemplateByHypervisorArchAndUrlPath(HypervisorType hypervisorType,
+ CPU.CPUArch arch, String urlPathSuffix) {
+ if (StringUtils.isBlank(urlPathSuffix)) {
+ return null;
+ }
+ SearchBuilder<VMTemplateVO> sb = createSearchBuilder();
+ sb.and("templateType", sb.entity().getTemplateType(), SearchCriteria.Op.EQ);
+ sb.and("hypervisorType", sb.entity().getHypervisorType(), SearchCriteria.Op.EQ);
+ sb.and("arch", sb.entity().getArch(), SearchCriteria.Op.EQ);
+ sb.and("urlPathSuffix", sb.entity().getUrl(), SearchCriteria.Op.LIKE);
+ sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
+ sb.done();
+ SearchCriteria<VMTemplateVO> sc = sb.create();
+ sc.setParameters("templateType", TemplateType.SYSTEM);
+ if (hypervisorType != null) {
+ sc.setParameters("hypervisorType", hypervisorType);
+ }
+ if (arch != null) {
+ sc.setParameters("arch", arch);
+ }
+ sc.setParameters("urlPathSuffix", "%" + urlPathSuffix);
+ sc.setParameters("state", VirtualMachineTemplate.State.Active);
+ Filter filter = new Filter(VMTemplateVO.class, "id", false, null, 1L);
+ List<VMTemplateVO> templates = listBy(sc, filter);
+ if (CollectionUtils.isNotEmpty(templates)) {
+ return templates.get(0);
+ }
+ return null;
+ }
+
+ @Override
public boolean updateState(
com.cloud.template.VirtualMachineTemplate.State currentState,
com.cloud.template.VirtualMachineTemplate.Event event,
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java
index 296f80f..0e784d9 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java
@@ -33,11 +33,10 @@
import javax.inject.Inject;
-import com.cloud.utils.FileUtil;
import org.apache.cloudstack.utils.CloudStackVersion;
import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import com.cloud.upgrade.dao.DbUpgrade;
import com.cloud.upgrade.dao.DbUpgradeSystemVmTemplate;
@@ -94,6 +93,7 @@
import com.cloud.upgrade.dao.Upgrade42200to42210;
import com.cloud.upgrade.dao.Upgrade420to421;
import com.cloud.upgrade.dao.Upgrade421to430;
+import com.cloud.upgrade.dao.Upgrade42210to42300;
import com.cloud.upgrade.dao.Upgrade430to440;
import com.cloud.upgrade.dao.Upgrade431to440;
import com.cloud.upgrade.dao.Upgrade432to440;
@@ -122,6 +122,7 @@
import com.cloud.upgrade.dao.VersionDaoImpl;
import com.cloud.upgrade.dao.VersionVO;
import com.cloud.upgrade.dao.VersionVO.Step;
+import com.cloud.utils.FileUtil;
import com.cloud.utils.component.SystemIntegrityChecker;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.GlobalLock;
@@ -242,6 +243,7 @@
.next("4.20.1.0", new Upgrade42010to42100())
.next("4.21.0.0", new Upgrade42100to42200())
.next("4.22.0.0", new Upgrade42200to42210())
+ .next("4.22.1.0", new Upgrade42210to42300())
.build();
}
@@ -318,20 +320,20 @@
}
protected void executeProcedureScripts() {
- LOGGER.info(String.format("Executing Stored Procedure scripts that are under resource directory [%s].", PROCEDURES_DIRECTORY));
+ LOGGER.info("Executing Stored Procedure scripts that are under resource directory [{}].", PROCEDURES_DIRECTORY);
List<String> filesPathUnderViewsDirectory = FileUtil.getFilesPathsUnderResourceDirectory(PROCEDURES_DIRECTORY);
try (TransactionLegacy txn = TransactionLegacy.open("execute-procedure-scripts")) {
Connection conn = txn.getConnection();
for (String filePath : filesPathUnderViewsDirectory) {
- LOGGER.debug(String.format("Executing PROCEDURE script [%s].", filePath));
+ LOGGER.debug("Executing PROCEDURE script [{}].", filePath);
InputStream viewScript = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
runScript(conn, viewScript);
}
- LOGGER.info(String.format("Finished execution of PROCEDURE scripts that are under resource directory [%s].", PROCEDURES_DIRECTORY));
+ LOGGER.info("Finished execution of PROCEDURE scripts that are under resource directory [{}].", PROCEDURES_DIRECTORY);
} catch (SQLException e) {
String message = String.format("Unable to execute PROCEDURE scripts due to [%s].", e.getMessage());
LOGGER.error(message, e);
@@ -340,7 +342,7 @@
}
private DbUpgrade[] executeUpgrades(CloudStackVersion dbVersion, CloudStackVersion currentVersion) {
- LOGGER.info("Database upgrade must be performed from " + dbVersion + " to " + currentVersion);
+ LOGGER.info("Database upgrade must be performed from {} to {}", dbVersion, currentVersion);
final DbUpgrade[] upgrades = calculateUpgradePath(dbVersion, currentVersion);
@@ -353,8 +355,8 @@
private VersionVO executeUpgrade(DbUpgrade upgrade) {
VersionVO version;
- LOGGER.debug("Running upgrade " + upgrade.getClass().getSimpleName() + " to upgrade from " + upgrade.getUpgradableVersionRange()[0] + "-" + upgrade
- .getUpgradableVersionRange()[1] + " to " + upgrade.getUpgradedVersion());
+ LOGGER.debug("Running upgrade {} to upgrade from {}-{} to {}", upgrade.getClass().getSimpleName(), upgrade.getUpgradableVersionRange()[0], upgrade
+ .getUpgradableVersionRange()[1], upgrade.getUpgradedVersion());
TransactionLegacy txn = TransactionLegacy.open("Upgrade");
txn.start();
try {
@@ -397,8 +399,8 @@
// Run the corresponding '-cleanup.sql' script
txn = TransactionLegacy.open("Cleanup");
try {
- LOGGER.info("Cleanup upgrade " + upgrade.getClass().getSimpleName() + " to upgrade from " + upgrade.getUpgradableVersionRange()[0] + "-" + upgrade
- .getUpgradableVersionRange()[1] + " to " + upgrade.getUpgradedVersion());
+ LOGGER.info("Cleanup upgrade {} to upgrade from {}-{} to {}", upgrade.getClass().getSimpleName(), upgrade.getUpgradableVersionRange()[0], upgrade
+ .getUpgradableVersionRange()[1], upgrade.getUpgradedVersion());
txn.start();
Connection conn;
@@ -413,7 +415,7 @@
if (scripts != null) {
for (InputStream script : scripts) {
runScript(conn, script);
- LOGGER.debug("Cleanup script " + upgrade.getClass().getSimpleName() + " is executed successfully");
+ LOGGER.debug("Cleanup script {} is executed successfully", upgrade.getClass().getSimpleName());
}
}
txn.commit();
@@ -423,27 +425,27 @@
version.setUpdated(new Date());
_dao.update(version.getId(), version);
txn.commit();
- LOGGER.debug("Upgrade completed for version " + version.getVersion());
+ LOGGER.debug("Upgrade completed for version {}", version.getVersion());
} finally {
txn.close();
}
}
protected void executeViewScripts() {
- LOGGER.info(String.format("Executing VIEW scripts that are under resource directory [%s].", VIEWS_DIRECTORY));
+ LOGGER.info("Executing VIEW scripts that are under resource directory [{}].", VIEWS_DIRECTORY);
List<String> filesPathUnderViewsDirectory = FileUtil.getFilesPathsUnderResourceDirectory(VIEWS_DIRECTORY);
try (TransactionLegacy txn = TransactionLegacy.open("execute-view-scripts")) {
Connection conn = txn.getConnection();
for (String filePath : filesPathUnderViewsDirectory) {
- LOGGER.debug(String.format("Executing VIEW script [%s].", filePath));
+ LOGGER.debug("Executing VIEW script [{}].", filePath);
InputStream viewScript = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
runScript(conn, viewScript);
}
- LOGGER.info(String.format("Finished execution of VIEW scripts that are under resource directory [%s].", VIEWS_DIRECTORY));
+ LOGGER.info("Finished execution of VIEW scripts that are under resource directory [{}].", VIEWS_DIRECTORY);
} catch (SQLException e) {
String message = String.format("Unable to execute VIEW scripts due to [%s].", e.getMessage());
LOGGER.error(message, e);
@@ -507,10 +509,10 @@
String csVersion = parseSystemVmMetadata();
final CloudStackVersion sysVmVersion = CloudStackVersion.parse(csVersion);
final CloudStackVersion currentVersion = CloudStackVersion.parse(currentVersionValue);
- SystemVmTemplateRegistration.CS_MAJOR_VERSION = String.valueOf(sysVmVersion.getMajorRelease()) + "." + String.valueOf(sysVmVersion.getMinorRelease());
+ SystemVmTemplateRegistration.CS_MAJOR_VERSION = sysVmVersion.getMajorRelease() + "." + sysVmVersion.getMinorRelease();
SystemVmTemplateRegistration.CS_TINY_VERSION = String.valueOf(sysVmVersion.getPatchRelease());
- LOGGER.info("DB version = " + dbVersion + " Code Version = " + currentVersion);
+ LOGGER.info("DB version = {} Code Version = {}", dbVersion, currentVersion);
if (dbVersion.compareTo(currentVersion) > 0) {
throw new CloudRuntimeException("Database version " + dbVersion + " is higher than management software version " + currentVersionValue);
@@ -583,7 +585,7 @@
ResultSet result = pstmt.executeQuery()) {
if (result.next()) {
String init = result.getString(1);
- LOGGER.info("init = " + DBEncryptionUtil.decrypt(init));
+ LOGGER.info("init = {}", DBEncryptionUtil.decrypt(init));
}
}
}
@@ -615,21 +617,11 @@
}
@Override
- public boolean supportsRollingUpgrade() {
- return false;
- }
-
- @Override
public InputStream[] getPrepareScripts() {
return new InputStream[0];
}
@Override
- public void performDataMigration(Connection conn) {
-
- }
-
- @Override
public InputStream[] getCleanupScripts() {
return new InputStream[0];
}
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/SystemVmTemplateRegistration.java b/engine/schema/src/main/java/com/cloud/upgrade/SystemVmTemplateRegistration.java
index d8cf070..292bafe 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/SystemVmTemplateRegistration.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/SystemVmTemplateRegistration.java
@@ -28,7 +28,6 @@
import java.sql.Date;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -51,6 +50,7 @@
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.utils.security.DigestHelper;
+import org.apache.cloudstack.utils.server.ServerPropertiesUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -62,6 +62,8 @@
import com.cloud.dc.dao.ClusterDaoImpl;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.DataCenterDaoImpl;
+import com.cloud.dc.dao.DataCenterDetailsDao;
+import com.cloud.dc.dao.DataCenterDetailsDaoImpl;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.GuestOSVO;
@@ -103,14 +105,20 @@
private static final String METADATA_FILE = TEMPLATES_PATH + METADATA_FILE_NAME;
public static final String TEMPORARY_SECONDARY_STORE = "tmp";
private static final String PARTIAL_TEMPLATE_FOLDER = String.format("/template/tmpl/%d/", Account.ACCOUNT_ID_SYSTEM);
- private static final String storageScriptsDir = "scripts/storage/secondary";
+ protected static final String STORAGE_SCRIPTS_DIR = "scripts/storage/secondary";
private static final Integer OTHER_LINUX_ID = 99;
- private static Integer LINUX_12_ID = 363;
+ protected static Integer LINUX_12_ID = 363;
private static final Integer SCRIPT_TIMEOUT = 1800000;
private static final Integer LOCK_WAIT_TIMEOUT = 1200;
+ protected static final String TEMPLATE_DOWNLOAD_URL_KEY = "downloadurl";
+ protected static final String TEMPLATES_DOWNLOAD_REPOSITORY_KEY = "downloadrepository";
+ protected static final String TEMPLATES_CUSTOM_DOWNLOAD_REPOSITORY_KEY = "system.vm.templates.download.repository";
protected static final List<CPU.CPUArch> DOWNLOADABLE_TEMPLATE_ARCH_TYPES = Arrays.asList(
+ CPU.CPUArch.amd64,
CPU.CPUArch.arm64
);
+ protected static final String MINIMUM_SYSTEM_VM_VERSION_KEY = "minreq.sysvmtemplate.version";
+ protected static final String DEFAULT_SYSTEM_VM_GUEST_OS_NAME = "Debian GNU/Linux 12 (64-bit)";
public static String CS_MAJOR_VERSION = null;
public static String CS_TINY_VERSION = null;
@@ -134,7 +142,9 @@
@Inject
ConfigurationDao configurationDao;
@Inject
- private GuestOSDao guestOSDao;
+ DataCenterDetailsDao dataCenterDetailsDao;
+ @Inject
+ GuestOSDao guestOSDao;
private String systemVmTemplateVersion;
@@ -142,6 +152,7 @@
public SystemVmTemplateRegistration() {
dataCenterDao = new DataCenterDaoImpl();
+ dataCenterDetailsDao = new DataCenterDetailsDaoImpl();
vmTemplateDao = new VMTemplateDaoImpl();
vmTemplateZoneDao = new VMTemplateZoneDaoImpl();
templateDataStoreDao = new BasicTemplateDataStoreDaoImpl();
@@ -155,33 +166,14 @@
}
/**
- * Convenience constructor method to use when there is no system VM template change for a new version.
+ * Convenience constructor method to use when there is no system VM Template change for a new version.
*/
public SystemVmTemplateRegistration(String systemVmTemplateVersion) {
this();
this.systemVmTemplateVersion = systemVmTemplateVersion;
}
- public static String getMountCommand(String nfsVersion, String device, String dir) {
- String cmd = MOUNT_COMMAND_BASE;
- if (StringUtils.isNotBlank(nfsVersion)) {
- cmd = String.format("%s -o vers=%s", cmd, nfsVersion);
- }
- return String.format("%s %s %s", cmd, device, dir);
- }
-
- public String getSystemVmTemplateVersion() {
- if (StringUtils.isEmpty(systemVmTemplateVersion)) {
- return String.format("%s.%s", CS_MAJOR_VERSION, CS_TINY_VERSION);
- }
- return systemVmTemplateVersion;
- }
-
- public File getTempDownloadDir() {
- return tempDownloadDir;
- }
-
- private static class SystemVMTemplateDetails {
+ protected static class SystemVMTemplateDetails {
Long id;
String uuid;
String name;
@@ -312,19 +304,19 @@
}
}
- public static final List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorList = Arrays.asList(
+ protected static final List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> AVAILABLE_SYSTEM_TEMPLATES_HYPERVISOR_ARCH_LIST = Arrays.asList(
new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64),
new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.arm64),
- new Pair<>(Hypervisor.HypervisorType.VMware, null),
- new Pair<>(Hypervisor.HypervisorType.XenServer, null),
- new Pair<>(Hypervisor.HypervisorType.Hyperv, null),
- new Pair<>(Hypervisor.HypervisorType.LXC, null),
- new Pair<>(Hypervisor.HypervisorType.Ovm3, null)
+ new Pair<>(Hypervisor.HypervisorType.VMware, CPU.CPUArch.amd64),
+ new Pair<>(Hypervisor.HypervisorType.XenServer, CPU.CPUArch.amd64),
+ new Pair<>(Hypervisor.HypervisorType.Hyperv, CPU.CPUArch.amd64),
+ new Pair<>(Hypervisor.HypervisorType.LXC, CPU.CPUArch.amd64),
+ new Pair<>(Hypervisor.HypervisorType.Ovm3, CPU.CPUArch.amd64)
);
- public static final Map<String, MetadataTemplateDetails> NewTemplateMap = new HashMap<>();
+ protected static final List<MetadataTemplateDetails> METADATA_TEMPLATE_LIST = new ArrayList<>();
- public static final Map<Hypervisor.HypervisorType, String> RouterTemplateConfigurationNames = new HashMap<>() {
+ protected static final Map<Hypervisor.HypervisorType, String> ROUTER_TEMPLATE_CONFIGURATION_NAMES = new HashMap<>() {
{
put(Hypervisor.HypervisorType.KVM, "router.template.kvm");
put(Hypervisor.HypervisorType.VMware, "router.template.vmware");
@@ -335,18 +327,7 @@
}
};
- public static Map<Hypervisor.HypervisorType, Integer> hypervisorGuestOsMap = new HashMap<>() {
- {
- put(Hypervisor.HypervisorType.KVM, LINUX_12_ID);
- put(Hypervisor.HypervisorType.XenServer, OTHER_LINUX_ID);
- put(Hypervisor.HypervisorType.VMware, OTHER_LINUX_ID);
- put(Hypervisor.HypervisorType.Hyperv, LINUX_12_ID);
- put(Hypervisor.HypervisorType.LXC, LINUX_12_ID);
- put(Hypervisor.HypervisorType.Ovm3, LINUX_12_ID);
- }
- };
-
- public static final Map<Hypervisor.HypervisorType, ImageFormat> hypervisorImageFormat = new HashMap<Hypervisor.HypervisorType, ImageFormat>() {
+ protected static final Map<Hypervisor.HypervisorType, ImageFormat> HYPERVISOR_IMAGE_FORMAT_MAP = new HashMap<>() {
{
put(Hypervisor.HypervisorType.KVM, ImageFormat.QCOW2);
put(Hypervisor.HypervisorType.XenServer, ImageFormat.VHD);
@@ -357,69 +338,27 @@
}
};
- public boolean validateIfSeeded(TemplateDataStoreVO templDataStoreVO, String url, String path, String nfsVersion) {
- String filePath = null;
- try {
- filePath = Files.createTempDirectory(TEMPORARY_SECONDARY_STORE).toString();
- if (filePath == null) {
- throw new CloudRuntimeException("Failed to create temporary directory to mount secondary store");
- }
- mountStore(url, filePath, nfsVersion);
- int lastIdx = path.lastIndexOf(File.separator);
- String partialDirPath = path.substring(0, lastIdx);
- String templatePath = filePath + File.separator + partialDirPath;
- File templateProps = new File(templatePath + "/template.properties");
- if (templateProps.exists()) {
- Pair<Long, Long> templateSizes = readTemplatePropertiesSizes(templatePath + "/template.properties");
- updateSeededTemplateDetails(templDataStoreVO.getTemplateId(), templDataStoreVO.getDataStoreId(),
- templateSizes.first(), templateSizes.second());
- LOGGER.info("SystemVM Template already seeded, skipping registration");
- return true;
- }
- LOGGER.info("SystemVM Template not seeded");
- return false;
- } catch (Exception e) {
- LOGGER.error("Failed to verify if the Template is seeded", e);
- throw new CloudRuntimeException("Failed to verify if the Template is seeded", e);
- } finally {
- unmountStore(filePath);
- try {
- Files.delete(Path.of(filePath));
- } catch (IOException e) {
- LOGGER.error(String.format("Failed to delete temporary directory: %s", filePath));
- }
+ protected static Map<Hypervisor.HypervisorType, Integer> hypervisorGuestOsMap = new HashMap<>() {
+ {
+ put(Hypervisor.HypervisorType.KVM, LINUX_12_ID);
+ put(Hypervisor.HypervisorType.XenServer, OTHER_LINUX_ID);
+ put(Hypervisor.HypervisorType.VMware, OTHER_LINUX_ID);
+ put(Hypervisor.HypervisorType.Hyperv, LINUX_12_ID);
+ put(Hypervisor.HypervisorType.LXC, LINUX_12_ID);
+ put(Hypervisor.HypervisorType.Ovm3, LINUX_12_ID);
}
+ };
+
+ private static boolean isRunningInTest() {
+ return "true".equalsIgnoreCase(System.getProperty("test.mode"));
}
private static String getHypervisorArchLog(Hypervisor.HypervisorType hypervisorType, CPU.CPUArch arch) {
StringBuilder sb = new StringBuilder("hypervisor: ").append(hypervisorType.name());
- if (Hypervisor.HypervisorType.KVM.equals(hypervisorType)) {
- sb.append(", arch: ").append(arch == null ? CPU.CPUArch.amd64.getType() : arch.getType());
- }
+ sb.append(", arch: ").append(arch == null ? CPU.CPUArch.amd64.getType() : arch.getType());
return sb.toString();
}
- protected static String getHypervisorArchKey(Hypervisor.HypervisorType hypervisorType, CPU.CPUArch arch) {
- if (Hypervisor.HypervisorType.KVM.equals(hypervisorType)) {
- return String.format("%s-%s", hypervisorType.name().toLowerCase(),
- arch == null ? CPU.CPUArch.amd64.getType() : arch.getType());
- }
- return hypervisorType.name().toLowerCase();
- }
-
- protected static MetadataTemplateDetails getMetadataTemplateDetails(Hypervisor.HypervisorType hypervisorType,
- CPU.CPUArch arch) {
- return NewTemplateMap.get(getHypervisorArchKey(hypervisorType, arch));
- }
-
- public VMTemplateVO getRegisteredTemplate(String templateName, CPU.CPUArch arch) {
- return vmTemplateDao.findLatestTemplateByName(templateName, arch);
- }
-
- private static boolean isRunningInTest() {
- return "true".equalsIgnoreCase(System.getProperty("test.mode"));
- }
-
/**
* Attempts to determine the templates directory path by locating the metadata file.
* <p>
@@ -460,7 +399,170 @@
throw new CloudRuntimeException(errMsg);
}
- private List<Long> getEligibleZoneIds() {
+ protected static void cleanupStore(Long templateId, String filePath) {
+ String destTempFolder = filePath + PARTIAL_TEMPLATE_FOLDER + String.valueOf(templateId);
+ try {
+ Files.deleteIfExists(Paths.get(destTempFolder));
+ } catch (IOException e) {
+ LOGGER.error("Failed to cleanup mounted store at: {}", filePath, e);
+ }
+ }
+
+ protected static Pair<Long, Long> readTemplatePropertiesSizes(String path) {
+ File tmpFile = new File(path);
+ Long size = null;
+ Long physicalSize = 0L;
+ try (FileReader fr = new FileReader(tmpFile); BufferedReader brf = new BufferedReader(fr);) {
+ String line = null;
+ while ((line = brf.readLine()) != null) {
+ if (line.startsWith("size=")) {
+ physicalSize = Long.parseLong(line.split("=")[1]);
+ } else if (line.startsWith("virtualsize=")) {
+ size = Long.parseLong(line.split("=")[1]);
+ }
+ if (size == null) {
+ size = physicalSize;
+ }
+ }
+ } catch (IOException ex) {
+ LOGGER.warn("Failed to read from template.properties", ex);
+ }
+ return new Pair<>(size, physicalSize);
+ }
+
+ protected static MetadataTemplateDetails getMetadataTemplateDetails(Hypervisor.HypervisorType hypervisorType,
+ CPU.CPUArch arch) {
+ return METADATA_TEMPLATE_LIST
+ .stream()
+ .filter(x -> Objects.equals(x.getHypervisorType(), hypervisorType) &&
+ Objects.equals(x.getArch(), arch))
+ .findFirst()
+ .orElse(null);
+ }
+
+ protected static String getMetadataFilePath() {
+ return METADATA_FILE;
+ }
+
+ protected static Ini.Section getMetadataSectionForHypervisorAndArch(Ini ini,
+ Hypervisor.HypervisorType hypervisorType, CPU.CPUArch arch) {
+ String key = String.format("%s-%s", hypervisorType.name().toLowerCase(),
+ arch.getType().toLowerCase());
+ Ini.Section section = ini.get(key);
+ if (section == null && !Hypervisor.HypervisorType.KVM.equals(hypervisorType)) {
+ key = String.format("%s", hypervisorType.name().toLowerCase());
+ section = ini.get(key);
+ }
+ return section;
+ }
+
+ protected static String getMountCommand(String nfsVersion, String device, String dir) {
+ String cmd = MOUNT_COMMAND_BASE;
+ if (StringUtils.isNotBlank(nfsVersion)) {
+ cmd = String.format("%s -o vers=%s", cmd, nfsVersion);
+ }
+ return String.format("%s %s %s", cmd, device, dir);
+ }
+
+ /**
+ * This method parses the metadata file consisting of the system VM Templates information
+ * @return the version of the system VM Template that is to be used. This is done in order
+ * to fallback on the latest available version of the system VM Template when there doesn't
+ * exist a template corresponding to the current code version.
+ */
+ public static String parseMetadataFile() {
+ String metadataFilePath = getMetadataFilePath();
+ String errMsg = String.format("Failed to parse system VM Template metadata file: %s", metadataFilePath);
+ final Ini ini = new Ini();
+ try (FileReader reader = new FileReader(metadataFilePath)) {
+ ini.load(reader);
+ } catch (IOException e) {
+ LOGGER.error(errMsg, e);
+ throw new CloudRuntimeException(errMsg, e);
+ }
+ if (!ini.containsKey("default")) {
+ errMsg = String.format("%s as unable to default section", errMsg);
+ LOGGER.error(errMsg);
+ throw new CloudRuntimeException(errMsg);
+ }
+ Ini.Section defaultSection = ini.get("default");
+ String defaultDownloadRepository = defaultSection.get(TEMPLATES_DOWNLOAD_REPOSITORY_KEY);
+ String customDownloadRepository = ServerPropertiesUtil.getProperty(TEMPLATES_CUSTOM_DOWNLOAD_REPOSITORY_KEY);
+ boolean updateCustomDownloadRepository = StringUtils.isNotBlank(customDownloadRepository) &&
+ StringUtils.isNotBlank(defaultDownloadRepository);
+ for (Pair<Hypervisor.HypervisorType, CPU.CPUArch> hypervisorTypeArchPair : AVAILABLE_SYSTEM_TEMPLATES_HYPERVISOR_ARCH_LIST) {
+ String key = String.format("%s-%s", hypervisorTypeArchPair.first().name().toLowerCase(),
+ hypervisorTypeArchPair.second().getType().toLowerCase());
+ Ini.Section section = getMetadataSectionForHypervisorAndArch(ini, hypervisorTypeArchPair.first(),
+ hypervisorTypeArchPair.second());
+ if (section == null) {
+ LOGGER.error("Failed to find details for {} in template metadata file: {}",
+ getHypervisorArchLog(hypervisorTypeArchPair.first(), hypervisorTypeArchPair.second()),
+ metadataFilePath);
+ continue;
+ }
+ String url = section.get(TEMPLATE_DOWNLOAD_URL_KEY);
+ if (StringUtils.isNotBlank(url) && updateCustomDownloadRepository) {
+ url = url.replaceFirst(defaultDownloadRepository.trim(),
+ customDownloadRepository.trim());
+ LOGGER.debug("Updated download URL for {} using custom repository to {}", key, url);
+ }
+ METADATA_TEMPLATE_LIST.add(new MetadataTemplateDetails(
+ hypervisorTypeArchPair.first(),
+ section.get("templatename"),
+ section.get("filename"),
+ url,
+ section.get("checksum"),
+ hypervisorTypeArchPair.second(),
+ section.get("guestos")));
+ }
+ return defaultSection.get("version").trim();
+ }
+
+ public static void mountStore(String storeUrl, String path, String nfsVersion) {
+ try {
+ if (storeUrl == null) {
+ return;
+ }
+ URI uri = new URI(UriUtils.encodeURIComponent(storeUrl));
+ String host = uri.getHost();
+ String mountPath = uri.getPath();
+ Script.runSimpleBashScript(getMountCommand(nfsVersion, host + ":" + mountPath, path));
+ } catch (Exception e) {
+ String msg = "NFS Store URL is not in the correct format";
+ LOGGER.error(msg, e);
+ throw new CloudRuntimeException(msg, e);
+ }
+ }
+
+ public static void unmountStore(String filePath) {
+ try {
+ LOGGER.info("Unmounting store");
+ String umountCmd = String.format(UMOUNT_COMMAND, filePath);
+ Script.runSimpleBashScript(umountCmd);
+ try {
+ Files.deleteIfExists(Paths.get(filePath));
+ } catch (IOException e) {
+ LOGGER.error(String.format("Failed to cleanup mounted store at: %s", filePath), e);
+ }
+ } catch (Exception e) {
+ String msg = String.format("Failed to unmount store mounted at %s", filePath);
+ LOGGER.error(msg, e);
+ throw new CloudRuntimeException(msg, e);
+ }
+ }
+
+ protected File getTempDownloadDir() {
+ return tempDownloadDir;
+ }
+
+ protected void readTemplateProperties(String path, SystemVMTemplateDetails details) {
+ Pair<Long, Long> templateSizes = readTemplatePropertiesSizes(path);
+ details.setSize(templateSizes.first());
+ details.setPhysicalSize(templateSizes.second());
+ }
+
+ protected List<Long> getEligibleZoneIds() {
List<Long> zoneIds = new ArrayList<>();
List<ImageStoreVO> stores = imageStoreDao.findByProtocol("nfs");
for (ImageStoreVO store : stores) {
@@ -484,20 +586,11 @@
return new Pair<>(url, storeId);
}
- public static void mountStore(String storeUrl, String path, String nfsVersion) {
- try {
- if (storeUrl == null) {
- return;
- }
- URI uri = new URI(UriUtils.encodeURIComponent(storeUrl));
- String host = uri.getHost();
- String mountPath = uri.getPath();
- Script.runSimpleBashScript(getMountCommand(nfsVersion, host + ":" + mountPath, path));
- } catch (Exception e) {
- String msg = "NFS Store URL is not in the correct format";
- LOGGER.error(msg, e);
- throw new CloudRuntimeException(msg, e);
+ protected String getSystemVmTemplateVersion() {
+ if (StringUtils.isEmpty(systemVmTemplateVersion)) {
+ return String.format("%s.%s", CS_MAJOR_VERSION, CS_TINY_VERSION);
}
+ return systemVmTemplateVersion;
}
private VMTemplateVO createTemplateObjectInDB(SystemVMTemplateDetails details) {
@@ -527,7 +620,7 @@
return template;
}
- private VMTemplateZoneVO createOrUpdateTemplateZoneEntry(long zoneId, long templateId) {
+ protected VMTemplateZoneVO createOrUpdateTemplateZoneEntry(long zoneId, long templateId) {
VMTemplateZoneVO templateZoneVO = vmTemplateZoneDao.findByZoneTemplate(zoneId, templateId);
if (templateZoneVO == null) {
templateZoneVO = new VMTemplateZoneVO(zoneId, templateId, new java.util.Date());
@@ -541,33 +634,37 @@
return templateZoneVO;
}
- private void createCrossZonesTemplateZoneRefEntries(Long templateId) {
+ protected void createCrossZonesTemplateZoneRefEntries(Long templateId) {
List<DataCenterVO> dcs = dataCenterDao.listAll();
for (DataCenterVO dc : dcs) {
VMTemplateZoneVO templateZoneVO = createOrUpdateTemplateZoneEntry(dc.getId(), templateId);
if (templateZoneVO == null) {
- throw new CloudRuntimeException(String.format("Failed to create template_zone_ref record for the systemVM Template (id: %s) and zone: %s", templateId, dc));
+ throw new CloudRuntimeException(String.format("Failed to create template-zone record for the system " +
+ "VM Template (ID : %d) and zone: %s", templateId, dc));
}
}
}
- private void createTemplateStoreRefEntry(SystemVMTemplateDetails details) {
- TemplateDataStoreVO templateDataStoreVO = new TemplateDataStoreVO(details.storeId, details.getId(), details.getCreated(), 0,
- VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED, null, null, null, details.getInstallPath(), details.getUrl());
+ protected void createTemplateStoreRefEntry(SystemVMTemplateDetails details) {
+ TemplateDataStoreVO templateDataStoreVO = new TemplateDataStoreVO(details.getStoreId(), details.getId(),
+ details.getCreated(), 0, VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED,
+ null, null, null, details.getInstallPath(), details.getUrl());
templateDataStoreVO.setDataStoreRole(DataStoreRole.Image);
templateDataStoreVO = templateDataStoreDao.persist(templateDataStoreVO);
if (templateDataStoreVO == null) {
- throw new CloudRuntimeException(String.format("Failed to create template_store_ref record for the systemVM Template for hypervisor: %s", details.getHypervisorType().name()));
+ throw new CloudRuntimeException(String.format("Failed to create template-store record for the system VM " +
+ "template (ID : %d) and store (ID: %d)", details.getId(), details.getStoreId()));
}
}
- public void updateTemplateDetails(SystemVMTemplateDetails details) {
+ protected void updateTemplateDetails(SystemVMTemplateDetails details) {
VMTemplateVO template = vmTemplateDao.findById(details.getId());
template.setSize(details.getSize());
template.setState(VirtualMachineTemplate.State.Active);
vmTemplateDao.update(template.getId(), template);
- TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByStoreTemplate(details.getStoreId(), template.getId());
+ TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByStoreTemplate(details.getStoreId(),
+ template.getId());
templateDataStoreVO.setSize(details.getSize());
templateDataStoreVO.setPhysicalSize(details.getPhysicalSize());
templateDataStoreVO.setDownloadPercent(100);
@@ -576,11 +673,11 @@
templateDataStoreVO.setState(ObjectInDataStoreStateMachine.State.Ready);
boolean updated = templateDataStoreDao.update(templateDataStoreVO.getId(), templateDataStoreVO);
if (!updated) {
- throw new CloudRuntimeException("Failed to update template_store_ref entry for registered systemVM Template");
+ throw new CloudRuntimeException("Failed to update template-store record for registered system VM Template");
}
}
- public void updateSeededTemplateDetails(long templateId, long storeId, long size, long physicalSize) {
+ protected void updateSeededTemplateDetails(long templateId, long storeId, long size, long physicalSize) {
VMTemplateVO template = vmTemplateDao.findById(templateId);
template.setSize(size);
vmTemplateDao.update(template.getId(), template);
@@ -591,108 +688,77 @@
templateDataStoreVO.setLastUpdated(new Date(DateUtil.currentGMTTime().getTime()));
boolean updated = templateDataStoreDao.update(templateDataStoreVO.getId(), templateDataStoreVO);
if (!updated) {
- throw new CloudRuntimeException("Failed to update template_store_ref entry for seeded systemVM template");
+ throw new CloudRuntimeException("Failed to update template-store record for seeded system VM Template");
}
}
- public void updateSystemVMEntries(Long templateId, Hypervisor.HypervisorType hypervisorType) {
+ protected void updateSystemVMEntries(Long templateId, Hypervisor.HypervisorType hypervisorType) {
vmInstanceDao.updateSystemVmTemplateId(templateId, hypervisorType);
}
- private void updateSystemVmTemplateGuestOsId() {
- String systemVmGuestOsName = "Debian GNU/Linux 12 (64-bit)"; // default
+ protected void updateHypervisorGuestOsMap() {
try {
- GuestOSVO guestOS = guestOSDao.findOneByDisplayName(systemVmGuestOsName);
- if (guestOS != null) {
- LOGGER.debug("Updating SystemVM Template Guest OS [{}] id", systemVmGuestOsName);
- SystemVmTemplateRegistration.LINUX_12_ID = Math.toIntExact(guestOS.getId());
- hypervisorGuestOsMap.put(Hypervisor.HypervisorType.KVM, LINUX_12_ID);
- hypervisorGuestOsMap.put(Hypervisor.HypervisorType.Hyperv, LINUX_12_ID);
- hypervisorGuestOsMap.put(Hypervisor.HypervisorType.LXC, LINUX_12_ID);
- hypervisorGuestOsMap.put(Hypervisor.HypervisorType.Ovm3, LINUX_12_ID);
+ GuestOSVO guestOS = guestOSDao.findOneByDisplayName(DEFAULT_SYSTEM_VM_GUEST_OS_NAME);
+ if (guestOS == null) {
+ LOGGER.warn("Couldn't find Guest OS by name [{}] to update system VM Template guest OS ID",
+ DEFAULT_SYSTEM_VM_GUEST_OS_NAME);
+ return;
}
+ LOGGER.debug("Updating system VM Template guest OS [{}] ID", DEFAULT_SYSTEM_VM_GUEST_OS_NAME);
+ SystemVmTemplateRegistration.LINUX_12_ID = Math.toIntExact(guestOS.getId());
+ hypervisorGuestOsMap.put(Hypervisor.HypervisorType.KVM, LINUX_12_ID);
+ hypervisorGuestOsMap.put(Hypervisor.HypervisorType.Hyperv, LINUX_12_ID);
+ hypervisorGuestOsMap.put(Hypervisor.HypervisorType.LXC, LINUX_12_ID);
+ hypervisorGuestOsMap.put(Hypervisor.HypervisorType.Ovm3, LINUX_12_ID);
} catch (Exception e) {
- LOGGER.warn("Couldn't update SystemVM Template Guest OS id, due to {}", e.getMessage());
+ LOGGER.warn("Couldn't update System VM template guest OS ID, due to {}", e.getMessage());
}
}
- public void updateConfigurationParams(Map<String, String> configParams) {
- for (Map.Entry<String, String> config : configParams.entrySet()) {
- boolean updated = configurationDao.update(config.getKey(), config.getValue());
- if (!updated) {
- throw new CloudRuntimeException(String.format("Failed to update configuration parameter %s", config.getKey()));
- }
+ protected void updateConfigurationParams(Hypervisor.HypervisorType hypervisorType, String templateName, Long zoneId) {
+ String configName = ROUTER_TEMPLATE_CONFIGURATION_NAMES.get(hypervisorType);
+ boolean updated = configurationDao.update(configName, templateName);
+ if (!updated) {
+ throw new CloudRuntimeException(String.format("Failed to update configuration parameter %s", configName));
+ }
+ if (zoneId != null) {
+ dataCenterDetailsDao.removeDetail(zoneId, configName);
+ }
+ updated = configurationDao.update(MINIMUM_SYSTEM_VM_VERSION_KEY, getSystemVmTemplateVersion());
+ if (!updated) {
+ throw new CloudRuntimeException(String.format("Failed to update configuration parameter %s", configName));
+ }
+ if (zoneId != null) {
+ dataCenterDetailsDao.removeDetail(zoneId, MINIMUM_SYSTEM_VM_VERSION_KEY);
}
}
- private static Pair<Long, Long> readTemplatePropertiesSizes(String path) {
- File tmpFile = new File(path);
- Long size = null;
- Long physicalSize = 0L;
- try (FileReader fr = new FileReader(tmpFile); BufferedReader brf = new BufferedReader(fr);) {
- String line = null;
- while ((line = brf.readLine()) != null) {
- if (line.startsWith("size=")) {
- physicalSize = Long.parseLong(line.split("=")[1]);
- } else if (line.startsWith("virtualsize=")) {
- size = Long.parseLong(line.split("=")[1]);
- }
- if (size == null) {
- size = physicalSize;
- }
- }
- } catch (IOException ex) {
- LOGGER.warn("Failed to read from template.properties", ex);
- }
- return new Pair<>(size, physicalSize);
- }
-
- public static void readTemplateProperties(String path, SystemVMTemplateDetails details) {
- Pair<Long, Long> templateSizes = readTemplatePropertiesSizes(path);
- details.setSize(templateSizes.first());
- details.setPhysicalSize(templateSizes.second());
- }
-
- private void updateTemplateTablesOnFailure(long templateId) {
+ protected void updateTemplateEntriesOnFailure(long templateId) {
VMTemplateVO template = vmTemplateDao.createForUpdate(templateId);
template.setState(VirtualMachineTemplate.State.Inactive);
vmTemplateDao.update(template.getId(), template);
vmTemplateDao.remove(templateId);
- TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByTemplate(template.getId(), DataStoreRole.Image);
+ TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByTemplate(template.getId(),
+ DataStoreRole.Image);
+ if (templateDataStoreVO == null) {
+ return;
+ }
templateDataStoreDao.remove(templateDataStoreVO.getId());
}
- public static void unmountStore(String filePath) {
- try {
- LOGGER.info("Unmounting store");
- String umountCmd = String.format(UMOUNT_COMMAND, filePath);
- Script.runSimpleBashScript(umountCmd);
- try {
- Files.deleteIfExists(Paths.get(filePath));
- } catch (IOException e) {
- LOGGER.error(String.format("Failed to cleanup mounted store at: %s", filePath), e);
- }
- } catch (Exception e) {
- String msg = String.format("Failed to unmount store mounted at %s", filePath);
- LOGGER.error(msg, e);
- throw new CloudRuntimeException(msg, e);
- }
- }
-
- private void setupTemplate(String templateName, Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch,
- String destTempFolder) throws CloudRuntimeException {
- String setupTmpltScript = Script.findScript(storageScriptsDir, "setup-sysvm-tmplt");
+ protected void setupTemplateOnStore(String templateName, MetadataTemplateDetails templateDetails,
+ String destTempFolder) throws CloudRuntimeException {
+ String setupTmpltScript = Script.findScript(STORAGE_SCRIPTS_DIR, "setup-sysvm-tmplt");
if (setupTmpltScript == null) {
- throw new CloudRuntimeException("Unable to find the createtmplt.sh");
+ throw new CloudRuntimeException("Unable to find the setup-sysvm-tmplt script");
}
Script scr = new Script(setupTmpltScript, SCRIPT_TIMEOUT, LOGGER);
scr.add("-u", templateName);
- MetadataTemplateDetails templateDetails = NewTemplateMap.get(getHypervisorArchKey(hypervisor, arch));
String filePath = StringUtils.isNotBlank(templateDetails.getDownloadedFilePath()) ?
templateDetails.getDownloadedFilePath() :
templateDetails.getDefaultFilePath();
scr.add("-f", filePath);
- scr.add("-h", hypervisor.name().toLowerCase(Locale.ROOT));
+ scr.add("-h", templateDetails.getHypervisorType().name().toLowerCase(Locale.ROOT));
scr.add("-d", destTempFolder);
String result = scr.execute();
if (result != null) {
@@ -702,17 +768,33 @@
}
}
- private Long performTemplateRegistrationOperations(Hypervisor.HypervisorType hypervisor,
- String name, CPU.CPUArch arch, String url, String checksum, ImageFormat format, long guestOsId,
- Long storeId, Long templateId, String filePath, TemplateDataStoreVO templateDataStoreVO) {
+ /**
+ * Register or update a system VM Template record and seed it on the target store.
+ *
+ * @param name display name of the template
+ * @param templateDetails metadata for the template
+ * @param url download URL of the template
+ * @param checksum expected checksum of the template file
+ * @param format image format of the template
+ * @param guestOsId guest OS id
+ * @param storeId target image store id
+ * @param templateId existing template id if present, otherwise {@code null}
+ * @param filePath temporary mount path for the store
+ * @param templateDataStoreVO existing template-store mapping; may be {@code null}
+ * @return the id of the template that was created or updated
+ */
+ protected Long performTemplateRegistrationOperations(String name, MetadataTemplateDetails templateDetails,
+ String url, String checksum, ImageFormat format, long guestOsId, Long storeId, Long templateId,
+ String filePath, TemplateDataStoreVO templateDataStoreVO) {
String templateName = UUID.randomUUID().toString();
Date created = new Date(DateUtil.currentGMTTime().getTime());
- SystemVMTemplateDetails details = new SystemVMTemplateDetails(templateName, name, created,
- url, checksum, format, (int) guestOsId, hypervisor, arch, storeId);
+ SystemVMTemplateDetails details = new SystemVMTemplateDetails(templateName, name, created, url, checksum,
+ format, (int) guestOsId, templateDetails.getHypervisorType(), templateDetails.getArch(), storeId);
if (templateId == null) {
VMTemplateVO template = createTemplateObjectInDB(details);
if (template == null) {
- throw new CloudRuntimeException(String.format("Failed to register Template for hypervisor: %s", hypervisor.name()));
+ throw new CloudRuntimeException(String.format("Failed to register Template for hypervisor: %s",
+ templateDetails.getHypervisorType().name()));
}
templateId = template.getId();
}
@@ -721,153 +803,126 @@
details.setId(templateId);
String destTempFolderName = String.valueOf(templateId);
String destTempFolder = filePath + PARTIAL_TEMPLATE_FOLDER + destTempFolderName;
- details.setInstallPath(PARTIAL_TEMPLATE_FOLDER + destTempFolderName + File.separator + templateName + "." + hypervisorImageFormat.get(hypervisor).getFileExtension());
+ details.setInstallPath(String.format("%s%s%s%s.%s", PARTIAL_TEMPLATE_FOLDER, destTempFolderName,
+ File.separator, templateName,
+ HYPERVISOR_IMAGE_FORMAT_MAP.get(templateDetails.getHypervisorType()).getFileExtension()));
if (templateDataStoreVO == null) {
createTemplateStoreRefEntry(details);
}
- setupTemplate(templateName, hypervisor, arch, destTempFolder);
+ setupTemplateOnStore(templateName, templateDetails, destTempFolder);
readTemplateProperties(destTempFolder + "/template.properties", details);
details.setUpdated(new Date(DateUtil.currentGMTTime().getTime()));
updateTemplateDetails(details);
return templateId;
}
- public void registerTemplate(Hypervisor.HypervisorType hypervisor, String name, Long storeId,
- VMTemplateVO templateVO, TemplateDataStoreVO templateDataStoreVO, String filePath) {
+ /**
+ * Add an existing system VM Template to a secondary image store and update related DB entries.
+ *
+ * @param templateVO the existing VM template (must not be null)
+ * @param templateDetails the metadata details of the template to be added
+ * @param templateDataStoreVO optional existing template-store mapping; may be null
+ * @param zoneId zone id where the operation is performed
+ * @param storeId target image store id
+ * @param filePath temporary mount path for the store
+ * @throws CloudRuntimeException on failure; the method attempts rollback/cleanup
+ */
+ protected void addExistingTemplateToStore(VMTemplateVO templateVO, MetadataTemplateDetails templateDetails,
+ TemplateDataStoreVO templateDataStoreVO, long zoneId, Long storeId, String filePath) {
try {
- performTemplateRegistrationOperations(hypervisor, name, templateVO.getArch(), templateVO.getUrl(),
+ performTemplateRegistrationOperations(templateVO.getName(), templateDetails, templateVO.getUrl(),
templateVO.getChecksum(), templateVO.getFormat(), templateVO.getGuestOSId(), storeId,
templateVO.getId(), filePath, templateDataStoreVO);
} catch (Exception e) {
- String errMsg = String.format("Failed to register Template for hypervisor: %s", hypervisor);
+ String errMsg = String.format("Failed to add %s to store ID: %d, zone ID: %d", templateVO, storeId, zoneId);
LOGGER.error(errMsg, e);
- updateTemplateTablesOnFailure(templateVO.getId());
cleanupStore(templateVO.getId(), filePath);
throw new CloudRuntimeException(errMsg, e);
}
}
- public void registerTemplateForNonExistingEntries(Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch,
- String name, Pair<String, Long> storeUrlAndId, String filePath) {
+ /**
+ * Registers a new system VM Template for the given hypervisor/arch when no existing template is present.
+ *
+ * @param name the name of the new template
+ * @param templateDetails the metadata details of the template to be registered
+ * @param zoneId the zone id for which the new template should be seeded
+ * @param storeId the store id on which the new template will be seeded
+ * @param filePath temporary mount path for the store
+ * @throws CloudRuntimeException on failure; the method attempts rollback/cleanup
+ */
+ protected void registerNewTemplate(String name, MetadataTemplateDetails templateDetails, long zoneId, Long storeId,
+ String filePath) {
Long templateId = null;
+ Hypervisor.HypervisorType hypervisor = templateDetails.getHypervisorType();
try {
- MetadataTemplateDetails templateDetails = getMetadataTemplateDetails(hypervisor, arch);
- templateId = performTemplateRegistrationOperations(hypervisor, name,
- templateDetails.getArch(), templateDetails.getUrl(),
- templateDetails.getChecksum(), hypervisorImageFormat.get(hypervisor),
- hypervisorGuestOsMap.get(hypervisor), storeUrlAndId.second(), null, filePath, null);
- Map<String, String> configParams = new HashMap<>();
- configParams.put(RouterTemplateConfigurationNames.get(hypervisor), templateDetails.getName());
- configParams.put("minreq.sysvmtemplate.version", getSystemVmTemplateVersion());
- updateConfigurationParams(configParams);
+ templateId = performTemplateRegistrationOperations(name, templateDetails, templateDetails.getUrl(),
+ templateDetails.getChecksum(), HYPERVISOR_IMAGE_FORMAT_MAP.get(hypervisor),
+ hypervisorGuestOsMap.get(hypervisor), storeId, null, filePath, null);
+ updateConfigurationParams(hypervisor, name, zoneId);
updateSystemVMEntries(templateId, hypervisor);
} catch (Exception e) {
String errMsg = String.format("Failed to register Template for hypervisor: %s", hypervisor);
LOGGER.error(errMsg, e);
if (templateId != null) {
- updateTemplateTablesOnFailure(templateId);
+ updateTemplateEntriesOnFailure(templateId);
cleanupStore(templateId, filePath);
}
throw new CloudRuntimeException(errMsg, e);
}
}
- protected void validateTemplateFileForHypervisorAndArch(Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch) {
+ /**
+ * Validate presence and integrity of metadata and local template file for the given hypervisor/arch.
+ *
+ * @param hypervisor target hypervisor type
+ * @param arch target CPU architecture
+ * @return validated MetadataTemplateDetails
+ * @throws CloudRuntimeException if template is not available, missing, or checksum validation fails
+ */
+ protected MetadataTemplateDetails getValidatedTemplateDetailsForHypervisorAndArch(
+ Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch) {
+ if (!AVAILABLE_SYSTEM_TEMPLATES_HYPERVISOR_ARCH_LIST.contains(new Pair<>(hypervisor, arch))) {
+ throw new CloudRuntimeException("No system VM Template available for the given hypervisor and arch");
+ }
MetadataTemplateDetails templateDetails = getMetadataTemplateDetails(hypervisor, arch);
+ if (templateDetails == null) {
+ throw new CloudRuntimeException("No template details found for the given hypervisor and arch");
+ }
File templateFile = getTemplateFile(templateDetails);
if (templateFile == null) {
throw new CloudRuntimeException("Failed to find local template file");
}
- if (isTemplateFileChecksumDifferent(templateDetails, templateFile)) {
+ if (templateDetails.isFileChecksumDifferent(templateFile)) {
throw new CloudRuntimeException("Checksum failed for local template file");
}
- }
-
- public void validateAndRegisterTemplate(Hypervisor.HypervisorType hypervisor, String name, Long storeId,
- VMTemplateVO templateVO, TemplateDataStoreVO templateDataStoreVO, String filePath) {
- validateTemplateFileForHypervisorAndArch(hypervisor, templateVO.getArch());
- registerTemplate(hypervisor, name, storeId, templateVO, templateDataStoreVO, filePath);
- }
-
- public void validateAndRegisterTemplateForNonExistingEntries(Hypervisor.HypervisorType hypervisor,
- CPU.CPUArch arch, String name, Pair<String, Long> storeUrlAndId, String filePath) {
- validateTemplateFileForHypervisorAndArch(hypervisor, arch);
- registerTemplateForNonExistingEntries(hypervisor, arch, name, storeUrlAndId, filePath);
- }
-
- protected static String getMetadataFilePath() {
- return METADATA_FILE;
+ return templateDetails;
}
/**
- * This method parses the metadata file consisting of the systemVM templates information
- * @return the version of the systemvm template that is to be used. This is done in order
- * to fallback on the latest available version of the systemVM template when there doesn't
- * exist a template corresponding to the current code version.
+ * Return the local template file. Downloads it if not present locally and url is present.
+ *
+ * @param templateDetails template metadata; may set `downloadedFilePath`
+ * @return the template {@code File} on disk, or {@code null} if not found/downloaded
*/
- public static String parseMetadataFile() {
- String metadataFilePath = getMetadataFilePath();
- String errMsg = String.format("Failed to parse systemVM Template metadata file: %s", metadataFilePath);
- final Ini ini = new Ini();
- try (FileReader reader = new FileReader(metadataFilePath)) {
- ini.load(reader);
- } catch (IOException e) {
- LOGGER.error(errMsg, e);
- throw new CloudRuntimeException(errMsg, e);
- }
- if (!ini.containsKey("default")) {
- errMsg = String.format("%s as unable to default section", errMsg);
- LOGGER.error(errMsg);
- throw new CloudRuntimeException(errMsg);
- }
- for (Pair<Hypervisor.HypervisorType, CPU.CPUArch> hypervisorType : hypervisorList) {
- String key = getHypervisorArchKey(hypervisorType.first(), hypervisorType.second());
- Ini.Section section = ini.get(key);
- if (section == null) {
- LOGGER.error("Failed to find details for {} in template metadata file: {}",
- key, metadataFilePath);
- continue;
- }
- NewTemplateMap.put(key, new MetadataTemplateDetails(
- hypervisorType.first(),
- section.get("templatename"),
- section.get("filename"),
- section.get("downloadurl"),
- section.get("checksum"),
- hypervisorType.second(),
- section.get("guestos")));
- }
- Ini.Section defaultSection = ini.get("default");
- return defaultSection.get("version").trim();
- }
-
-
- private static void cleanupStore(Long templateId, String filePath) {
- String destTempFolder = filePath + PARTIAL_TEMPLATE_FOLDER + String.valueOf(templateId);
- try {
- Files.deleteIfExists(Paths.get(destTempFolder));
- } catch (IOException e) {
- LOGGER.error(String.format("Failed to cleanup mounted store at: %s", filePath), e);
- }
- }
-
protected File getTemplateFile(MetadataTemplateDetails templateDetails) {
File templateFile = new File(templateDetails.getDefaultFilePath());
if (templateFile.exists()) {
return templateFile;
}
LOGGER.debug("{} is not present", templateFile.getAbsolutePath());
- if (DOWNLOADABLE_TEMPLATE_ARCH_TYPES.contains(templateDetails.getArch()) &&
- StringUtils.isNotBlank(templateDetails.getUrl())) {
+ if (StringUtils.isNotBlank(templateDetails.getUrl())) {
LOGGER.debug("Downloading the template file {} for {}",
templateDetails.getUrl(), templateDetails.getHypervisorArchLog());
Path path = Path.of(TEMPLATES_PATH);
if (!Files.isWritable(path)) {
- templateFile = new File(tempDownloadDir, templateDetails.getFilename());
+ templateFile = new File(getTempDownloadDir(), templateDetails.getFilename());
}
if (!templateFile.exists() &&
!HttpUtils.downloadFileWithProgress(templateDetails.getUrl(), templateFile.getAbsolutePath(),
LOGGER)) {
+ LOGGER.error("Failed to download template for {} using url: {}",
+ templateDetails.getHypervisorArchLog(), templateDetails.getUrl());
return null;
}
templateDetails.setDownloadedFilePath(templateFile.getAbsolutePath());
@@ -875,32 +930,28 @@
return templateFile;
}
- protected boolean isTemplateFileChecksumDifferent(MetadataTemplateDetails templateDetails, File templateFile) {
- String templateChecksum = DigestHelper.calculateChecksum(templateFile);
- if (!templateChecksum.equals(templateDetails.getChecksum())) {
- LOGGER.error("Checksum {} for file {} does not match checksum {} from metadata",
- templateChecksum, templateFile, templateDetails.getChecksum());
- return true;
- }
- return false;
- }
-
- protected void validateTemplates(List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorsArchInUse) {
+ /**
+ * Validate that templates for the provided hypervisor/architecture pairs which are in use and are valid.
+ *
+ * If a template is missing or validation fails for any required pair, a
+ * {@link CloudRuntimeException} is thrown to abort the upgrade. If system VM Template for a hypervisor/arch is
+ * not considered available then validation is skipped for that pair.
+ *
+ * @param hypervisorArchList list of hypervisor/architecture pairs to validate
+ */
+ protected void validateTemplates(List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorArchList) {
boolean templatesFound = true;
- for (Pair<Hypervisor.HypervisorType, CPU.CPUArch> hypervisorArch : hypervisorsArchInUse) {
- MetadataTemplateDetails matchedTemplate = getMetadataTemplateDetails(hypervisorArch.first(),
- hypervisorArch.second());
- if (matchedTemplate == null) {
- templatesFound = false;
- break;
- }
- File tempFile = getTemplateFile(matchedTemplate);
- if (tempFile == null) {
- LOGGER.warn("Failed to download template for {}, moving ahead",
- matchedTemplate.getHypervisorArchLog());
+ for (Pair<Hypervisor.HypervisorType, CPU.CPUArch> hypervisorArch : hypervisorArchList) {
+ if (!AVAILABLE_SYSTEM_TEMPLATES_HYPERVISOR_ARCH_LIST.contains(hypervisorArch)) {
+ LOGGER.info("No system VM Template available for {}. Skipping validation.",
+ getHypervisorArchLog(hypervisorArch.first(), hypervisorArch.second()));
continue;
}
- if (isTemplateFileChecksumDifferent(matchedTemplate, tempFile)) {
+ try {
+ getValidatedTemplateDetailsForHypervisorAndArch(hypervisorArch.first(), hypervisorArch.second());
+ } catch (CloudRuntimeException e) {
+ LOGGER.error("Validation failed for {}: {}",
+ getHypervisorArchLog(hypervisorArch.first(), hypervisorArch.second()), e.getMessage());
templatesFound = false;
break;
}
@@ -912,10 +963,20 @@
}
}
- protected void registerTemplatesForZone(long zoneId, String filePath) {
+ /**
+ * Register or ensure system VM Templates are present on the NFS store for a given zone.
+ *
+ * Mounts the zone image store, enumerates hypervisors and architectures in the zone,
+ * and for each template either adds an existing template to the store or registers
+ * a new template as required.
+ *
+ * @param zoneId the zone id
+ * @param storeMountPath temporary mount path for the store
+ */
+ protected void registerTemplatesForZone(long zoneId, String storeMountPath) {
Pair<String, Long> storeUrlAndId = getNfsStoreInZone(zoneId);
String nfsVersion = getNfsVersion(storeUrlAndId.second());
- mountStore(storeUrlAndId.first(), filePath, nfsVersion);
+ mountStore(storeUrlAndId.first(), storeMountPath, nfsVersion);
List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorArchList =
clusterDao.listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
for (Pair<Hypervisor.HypervisorType, CPU.CPUArch> hypervisorArch : hypervisorArchList) {
@@ -925,7 +986,8 @@
if (templateDetails == null) {
continue;
}
- VMTemplateVO templateVO = getRegisteredTemplate(templateDetails.getName(), templateDetails.getArch());
+ VMTemplateVO templateVO = getRegisteredTemplate(templateDetails.getName(),
+ templateDetails.getHypervisorType(), templateDetails.getArch(), templateDetails.getUrl());
if (templateVO != null) {
TemplateDataStoreVO templateDataStoreVO =
templateDataStoreDao.findByStoreTemplate(storeUrlAndId.second(), templateVO.getId());
@@ -935,22 +997,22 @@
continue;
}
}
- registerTemplate(hypervisorType, templateDetails.getName(), storeUrlAndId.second(), templateVO,
- templateDataStoreVO, filePath);
- updateRegisteredTemplateDetails(templateVO.getId(), templateDetails);
+ addExistingTemplateToStore(templateVO, templateDetails, templateDataStoreVO, zoneId,
+ storeUrlAndId.second(), storeMountPath);
+ updateRegisteredTemplateDetails(templateVO.getId(), templateDetails, zoneId);
continue;
}
- registerTemplateForNonExistingEntries(hypervisorType, templateDetails.getArch(), templateDetails.getName(),
- storeUrlAndId, filePath);
+ registerNewTemplate(templateDetails.getName(), templateDetails, zoneId, storeUrlAndId.second(),
+ storeMountPath);
}
}
- public void registerTemplates(List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorsArchInUse) {
+ protected void registerTemplates(List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorsArchInUse) {
GlobalLock lock = GlobalLock.getInternLock("UpgradeDatabase-Lock");
try {
LOGGER.info("Grabbing lock to register Templates.");
if (!lock.lock(LOCK_WAIT_TIMEOUT)) {
- throw new CloudRuntimeException("Unable to acquire lock to register SystemVM Template.");
+ throw new CloudRuntimeException("Unable to acquire lock to register system VM Template.");
}
try {
validateTemplates(hypervisorsArchInUse);
@@ -970,13 +1032,13 @@
unmountStore(filePath);
} catch (Exception e) {
unmountStore(filePath);
- throw new CloudRuntimeException("Failed to register SystemVM Template. Upgrade failed");
+ throw new CloudRuntimeException("Failed to register system VM Template. Upgrade Failed");
}
}
}
});
} catch (Exception e) {
- throw new CloudRuntimeException("Failed to register SystemVM Template. Upgrade failed");
+ throw new CloudRuntimeException("Failed to register system VM Template. Upgrade Failed");
}
} finally {
lock.unlock();
@@ -984,7 +1046,18 @@
}
}
- private void updateRegisteredTemplateDetails(Long templateId, MetadataTemplateDetails templateDetails) {
+ /**
+ * Update the DB record for an existing template to mark it as a system template,
+ * set the guest OS (if resolvable), and propagate the change to system VM entries
+ * and related configuration for the template's hypervisor.
+ *
+ * @param templateId id of the template to update
+ * @param templateDetails metadata used to update the template record
+ * @param zoneId zone id whose per-zone details (if any) should be cleared; may be null
+ * @throws CloudRuntimeException if updating the template record fails
+ */
+ protected void updateRegisteredTemplateDetails(Long templateId, MetadataTemplateDetails templateDetails,
+ Long zoneId) {
VMTemplateVO templateVO = vmTemplateDao.findById(templateId);
templateVO.setTemplateType(Storage.TemplateType.SYSTEM);
GuestOSVO guestOS = guestOSDao.findOneByDisplayName(templateDetails.getGuestOs());
@@ -993,20 +1066,18 @@
}
boolean updated = vmTemplateDao.update(templateVO.getId(), templateVO);
if (!updated) {
- String errMsg = String.format("updateSystemVmTemplates:Exception while updating Template with id %s to be marked as 'system'", templateId);
+ String errMsg = String.format("Exception while updating template with id %s to be marked as 'system'",
+ templateId);
LOGGER.error(errMsg);
throw new CloudRuntimeException(errMsg);
}
Hypervisor.HypervisorType hypervisorType = templateDetails.getHypervisorType();
updateSystemVMEntries(templateId, hypervisorType);
- // Change value of global configuration parameter router.template.* for the corresponding hypervisor and minreq.sysvmtemplate.version for the ACS version
- Map<String, String> configParams = new HashMap<>();
- configParams.put(RouterTemplateConfigurationNames.get(hypervisorType), templateDetails.getName());
- configParams.put("minreq.sysvmtemplate.version", getSystemVmTemplateVersion());
- updateConfigurationParams(configParams);
+ updateConfigurationParams(hypervisorType, templateDetails.getName(), zoneId);
}
- private void updateTemplateUrlChecksumAndGuestOsId(VMTemplateVO templateVO, MetadataTemplateDetails templateDetails) {
+ protected void updateTemplateUrlChecksumAndGuestOsId(VMTemplateVO templateVO,
+ MetadataTemplateDetails templateDetails) {
templateVO.setUrl(templateDetails.getUrl());
templateVO.setChecksum(DigestHelper.prependAlgorithm(templateDetails.getChecksum()));
GuestOSVO guestOS = guestOSDao.findOneByDisplayName(templateDetails.getGuestOs());
@@ -1015,78 +1086,64 @@
}
boolean updated = vmTemplateDao.update(templateVO.getId(), templateVO);
if (!updated) {
- String errMsg = String.format("updateSystemVmTemplates:Exception while updating 'url' and 'checksum' for hypervisor type %s", templateDetails.getHypervisorType());
+ String errMsg = String.format("Exception while updating 'url' and 'checksum' for hypervisor type %s",
+ templateDetails.getHypervisorType());
LOGGER.error(errMsg);
throw new CloudRuntimeException(errMsg);
}
}
- protected boolean registerOrUpdateSystemVmTemplate(MetadataTemplateDetails templateDetails,
- List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorsInUse) {
- LOGGER.debug("Updating System VM template for {}", templateDetails.getHypervisorArchLog());
- VMTemplateVO registeredTemplate = getRegisteredTemplate(templateDetails.getName(), templateDetails.getArch());
- // change template type to SYSTEM
+ /**
+ * Updates or registers the system VM Template for the given hypervisor/arch if not already present.
+ * Returns true if a new template was registered.
+ * If there is an existing system VM Template for the given hypervisor/arch, its details are updated.
+ * If no existing template is found, new templates are registered for the valid hypervisor/arch which are in use.
+ */
+ protected boolean updateOrRegisterSystemVmTemplate(MetadataTemplateDetails templateDetails,
+ List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorArchInUse) {
+ String systemVmTemplateLog = String.format("%s system VM Template for %s", getSystemVmTemplateVersion(),
+ templateDetails.getHypervisorArchLog());
+ LOGGER.debug("Registering or updating {}", systemVmTemplateLog,
+ templateDetails.getHypervisorArchLog());
+ VMTemplateVO registeredTemplate = getRegisteredTemplate(templateDetails.getName(),
+ templateDetails.getHypervisorType(), templateDetails.getArch(), templateDetails.getUrl());
if (registeredTemplate != null) {
- updateRegisteredTemplateDetails(registeredTemplate.getId(), templateDetails);
- } else {
- boolean isHypervisorArchMatchMetadata = hypervisorsInUse.stream()
- .anyMatch(p -> p.first().equals(templateDetails.getHypervisorType())
- && Objects.equals(p.second(), templateDetails.getArch()));
- if (isHypervisorArchMatchMetadata) {
- try {
- registerTemplates(hypervisorsInUse);
- return true;
- } catch (final Exception e) {
- throw new CloudRuntimeException(String.format("Failed to register %s templates for hypervisors: [%s]. " +
- "Cannot upgrade system VMs",
- getSystemVmTemplateVersion(),
- StringUtils.join(hypervisorsInUse.stream()
- .map(x -> getHypervisorArchKey(x.first(), x.second()))
- .collect(Collectors.toList()), ",")), e);
- }
- } else {
- LOGGER.warn("Cannot upgrade {} system VM template for {} as it is not used, not failing upgrade",
- getSystemVmTemplateVersion(), templateDetails.getHypervisorArchLog());
- VMTemplateVO templateVO = vmTemplateDao.findLatestTemplateByTypeAndHypervisorAndArch(
- templateDetails.getHypervisorType(), templateDetails.getArch(), Storage.TemplateType.SYSTEM);
- if (templateVO != null) {
- updateTemplateUrlChecksumAndGuestOsId(templateVO, templateDetails);
- }
- }
+ LOGGER.info("{} is already registered, updating details for: {}",
+ systemVmTemplateLog, templateDetails.getHypervisorArchLog(), registeredTemplate);
+ updateRegisteredTemplateDetails(registeredTemplate.getId(), templateDetails, null);
+ return false;
}
- return false;
- }
-
- public void updateSystemVmTemplates(final Connection conn) {
- LOGGER.debug("Updating System Vm template IDs");
- updateSystemVmTemplateGuestOsId();
- Transaction.execute(new TransactionCallbackNoReturn() {
- @Override
- public void doInTransactionWithoutResult(final TransactionStatus status) {
- List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorsInUse;
- try {
- hypervisorsInUse = clusterDao.listDistinctHypervisorsAndArchExcludingExternalType(null);
- } catch (final Exception e) {
- throw new CloudRuntimeException("Exception while getting hypervisor types from clusters", e);
- }
- Collection<MetadataTemplateDetails> templateEntries = NewTemplateMap.values();
- for (MetadataTemplateDetails templateDetails : templateEntries) {
- try {
- if (registerOrUpdateSystemVmTemplate(templateDetails, hypervisorsInUse)) {
- break;
- }
- } catch (final Exception e) {
- String errMsg = "Exception while registering/updating system VM Templates for hypervisors in metadata";
- LOGGER.error(errMsg, e);
- throw new CloudRuntimeException(errMsg, e);
- }
- }
- LOGGER.debug("Updating System Vm Template IDs Complete");
+ boolean isHypervisorArchMatchMetadata = hypervisorArchInUse.stream()
+ .anyMatch(p -> p.first().equals(templateDetails.getHypervisorType())
+ && Objects.equals(p.second(), templateDetails.getArch()));
+ if (!isHypervisorArchMatchMetadata) {
+ LOGGER.warn("Skipping upgrading {} as it is not used, not failing upgrade",
+ getSystemVmTemplateVersion(), templateDetails.getHypervisorArchLog());
+ VMTemplateVO templateVO = vmTemplateDao.findLatestTemplateByTypeAndHypervisorAndArch(
+ templateDetails.getHypervisorType(), templateDetails.getArch(), Storage.TemplateType.SYSTEM);
+ if (templateVO != null) {
+ updateTemplateUrlChecksumAndGuestOsId(templateVO, templateDetails);
}
- });
+ return false;
+ }
+ try {
+ registerTemplates(hypervisorArchInUse);
+ return true;
+ } catch (final Exception e) {
+ throw new CloudRuntimeException(String.format("Failed to register %s templates for hypervisors: [%s]. " +
+ "Cannot upgrade system VMs",
+ getSystemVmTemplateVersion(),
+ StringUtils.join(hypervisorArchInUse.stream()
+ .map(x -> String.format("%s-%s", x.first().name(), x.second().name()))
+ .collect(Collectors.toList()), ",")), e);
+ }
}
- public String getNfsVersion(long storeId) {
+ /**
+ * Return NFS version for the store: store-specific config if present
+ * or global config if absent. Returns null if not set.
+ */
+ protected String getNfsVersion(long storeId) {
final String configKey = "secstorage.nfs.version";
final Map<String, String> storeDetails = imageStoreDetailsDao.getDetails(storeId);
if (storeDetails != null && storeDetails.containsKey(configKey)) {
@@ -1099,6 +1156,148 @@
return null;
}
+ /**
+ * Validate metadata for the given template's hypervisor/arch and add the existing template
+ * to the specified secondary store. On success, database entries are created/updated.
+ *
+ * @param templateVO template to add
+ * @param templateDataStoreVO existing template-store mapping; may be null
+ * @param zoneId zone id where the operation is performed
+ * @param storeId target image store id
+ * @param filePath temporary mount path for the store
+ * @throws CloudRuntimeException on failure; the method attempts rollback/cleanup
+ */
+ public void validateAndAddTemplateToStore(VMTemplateVO templateVO, TemplateDataStoreVO templateDataStoreVO,
+ long zoneId, long storeId, String filePath) {
+ MetadataTemplateDetails templateDetails = getValidatedTemplateDetailsForHypervisorAndArch(
+ templateVO.getHypervisorType(), templateVO.getArch());
+ addExistingTemplateToStore(templateVO, templateDetails, templateDataStoreVO, zoneId, storeId, filePath);
+ }
+
+ /**
+ * Validate metadata for the given hypervisor/arch and register a new system VM Template
+ * on the specified store and zone. Creates DB entries and seeds the template on the store.
+ *
+ * @param hypervisor hypervisor type
+ * @param arch cpu architecture
+ * @param name template name to register
+ * @param zoneId zone id where the operation is performed
+ * @param storeId target image store id
+ * @param filePath temporary mount path for the store
+ * @throws CloudRuntimeException on failure; the method attempts rollback/cleanup
+ */
+ public void validateAndRegisterNewTemplate(Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch, String name,
+ long zoneId, long storeId, String filePath) {
+ MetadataTemplateDetails templateDetails = getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, arch);
+ registerNewTemplate(name, templateDetails, zoneId, storeId, filePath);
+ }
+
+ /**
+ * Check whether the template at the given `path` on NFS `url` is already seeded.
+ * If found, updates DB with sizes and returns true; otherwise returns false.
+ *
+ * @throws CloudRuntimeException on any error
+ */
+ public boolean validateIfSeeded(TemplateDataStoreVO templDataStoreVO, String url, String path, String nfsVersion) {
+ String filePath = null;
+ try {
+ filePath = Files.createTempDirectory(TEMPORARY_SECONDARY_STORE).toString();
+ if (filePath == null) {
+ throw new CloudRuntimeException("Failed to create temporary directory to mount secondary store");
+ }
+ mountStore(url, filePath, nfsVersion);
+ int lastIdx = path.lastIndexOf(File.separator);
+ String partialDirPath = path.substring(0, lastIdx);
+ String templatePath = filePath + File.separator + partialDirPath;
+ File templateProps = new File(templatePath + "/template.properties");
+ if (templateProps.exists()) {
+ Pair<Long, Long> templateSizes = readTemplatePropertiesSizes(templatePath + "/template.properties");
+ updateSeededTemplateDetails(templDataStoreVO.getTemplateId(), templDataStoreVO.getDataStoreId(),
+ templateSizes.first(), templateSizes.second());
+ LOGGER.info("System VM template already seeded, skipping registration");
+ return true;
+ }
+ LOGGER.info("System VM template not seeded");
+ return false;
+ } catch (Exception e) {
+ LOGGER.error("Failed to verify if the template is seeded", e);
+ throw new CloudRuntimeException("Failed to verify if the template is seeded", e);
+ } finally {
+ unmountStore(filePath);
+ try {
+ Files.delete(Path.of(filePath));
+ } catch (IOException e) {
+ LOGGER.error("Failed to delete temporary directory: {}", filePath);
+ }
+ }
+ }
+
+ /**
+ * Finds a registered system VM Template matching the provided criteria.
+ *
+ * <p>The method first attempts to locate the latest template by {@code templateName},
+ * {@code hypervisorType} and {@code arch}. If none is found and a non-blank {@code url}
+ * is provided, it falls back to searching for an active system template by the
+ * URL path segment (the substring after the last '/' in the URL).</p>
+ *
+ * @param templateName the template name to search for
+ * @param hypervisorType the hypervisor type
+ * @param arch the CPU architecture
+ * @param url optional download URL used as a fallback; may be {@code null} or blank
+ * @return the matching {@code VMTemplateVO} if found; {@code null} otherwise
+ */
+ public VMTemplateVO getRegisteredTemplate(String templateName, Hypervisor.HypervisorType hypervisorType,
+ CPU.CPUArch arch, String url) {
+ VMTemplateVO registeredTemplate = vmTemplateDao.findLatestTemplateByName(templateName, hypervisorType, arch);
+ if (registeredTemplate == null && StringUtils.isNotBlank(url)) {
+ String urlPath = url.substring(url.lastIndexOf("/") + 1);
+ LOGGER.debug("No template found by name, falling back to search existing SYSTEM template by " +
+ "urlPath: {}, hypervisor: {}, arch:{}", urlPath, hypervisorType, arch);
+ registeredTemplate = vmTemplateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(hypervisorType, arch,
+ urlPath);
+ }
+ LOGGER.debug("Found existing registered template for hypervisor: {}, arch: {}: {}", hypervisorType,
+ arch, registeredTemplate);
+ return registeredTemplate;
+ }
+
+ /**
+ * Update or register system VM Templates based on metadata.
+ *
+ * Runs the registration logic inside a database transaction: obtains the
+ * set of hypervisors/architectures in use, iterates over metadata entries
+ * and attempts to register or update each template.
+ *
+ * @param conn retained for compatibility with callers (not used directly)
+ */
+ public void updateSystemVmTemplates(final Connection conn) {
+ LOGGER.debug("Updating System VM templates");
+ updateHypervisorGuestOsMap();
+ Transaction.execute(new TransactionCallbackNoReturn() {
+ @Override
+ public void doInTransactionWithoutResult(final TransactionStatus status) {
+ List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorsInUse;
+ try {
+ hypervisorsInUse = clusterDao.listDistinctHypervisorsAndArchExcludingExternalType(null);
+ } catch (final Exception e) {
+ throw new CloudRuntimeException("Exception while getting hypervisor types from clusters", e);
+ }
+ for (MetadataTemplateDetails templateDetails : METADATA_TEMPLATE_LIST) {
+ try {
+ if (updateOrRegisterSystemVmTemplate(templateDetails, hypervisorsInUse)) {
+ break;
+ }
+ } catch (final Exception e) {
+ String errMsg = "Exception while registering/updating system VM Templates for hypervisors in metadata";
+ LOGGER.error(errMsg, e);
+ throw new CloudRuntimeException(errMsg, e);
+ }
+ }
+ LOGGER.debug("Updating System VM Templates Complete");
+ }
+ });
+ }
+
protected static class MetadataTemplateDetails {
private final Hypervisor.HypervisorType hypervisorType;
private final String name;
@@ -1160,6 +1359,16 @@
return TEMPLATES_PATH + filename;
}
+ public boolean isFileChecksumDifferent(File file) {
+ String fileChecksum = DigestHelper.calculateChecksum(file);
+ if (!fileChecksum.equals(getChecksum())) {
+ LOGGER.error("Checksum {} for file {} does not match checksum {} from metadata",
+ fileChecksum, file, getChecksum());
+ return true;
+ }
+ return false;
+ }
+
public String getHypervisorArchLog() {
return SystemVmTemplateRegistration.getHypervisorArchLog(hypervisorType, arch);
}
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade2214to30.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade2214to30.java
index 524b6a3..d4cdbcb 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade2214to30.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade2214to30.java
@@ -77,8 +77,6 @@
encryptData(conn);
// drop keys
dropKeysIfExist(conn);
- //update template ID for system Vms
- //updateSystemVms(conn); This is not required as system template update is handled during 4.2 upgrade
// update domain network ref
updateDomainNetworkRef(conn);
// update networks that use redundant routers to the new network offering
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade302to40.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade302to40.java
index aa42725..bd8ddaa 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade302to40.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade302to40.java
@@ -62,7 +62,6 @@
@Override
public void performDataMigration(Connection conn) {
- //updateVmWareSystemVms(conn); This is not required as system template update is handled during 4.2 upgrade
correctVRProviders(conn);
correctMultiplePhysicaNetworkSetups(conn);
addHostDetailsUniqueKey(conn);
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade304to305.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade304to305.java
index 3167dd8..38dc90b 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade304to305.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade304to305.java
@@ -65,7 +65,6 @@
addVpcProvider(conn);
updateRouterNetworkRef(conn);
fixZoneUsingExternalDevices(conn);
-// updateSystemVms(conn);
fixForeignKeys(conn);
encryptClusterDetails(conn);
}
@@ -81,54 +80,6 @@
return new InputStream[] {script};
}
- private void updateSystemVms(Connection conn) {
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- boolean VMware = false;
- try {
- pstmt = conn.prepareStatement("select distinct(hypervisor_type) from `cloud`.`cluster` where removed is null");
- rs = pstmt.executeQuery();
- while (rs.next()) {
- if ("VMware".equals(rs.getString(1))) {
- VMware = true;
- }
- }
- } catch (SQLException e) {
- throw new CloudRuntimeException("Error while iterating through list of hypervisors in use", e);
- }
- // Just update the VMware system template. Other hypervisor templates are unchanged from previous 3.0.x versions.
- logger.debug("Updating VMware System Vms");
- try {
- //Get 3.0.5 VMware system Vm template Id
- pstmt = conn.prepareStatement("select id from `cloud`.`vm_template` where name = 'systemvm-vmware-3.0.5' and removed is null");
- rs = pstmt.executeQuery();
- if (rs.next()) {
- long templateId = rs.getLong(1);
- rs.close();
- pstmt.close();
- // change template type to SYSTEM
- pstmt = conn.prepareStatement("update `cloud`.`vm_template` set type='SYSTEM' where id = ?");
- pstmt.setLong(1, templateId);
- pstmt.executeUpdate();
- pstmt.close();
- // update template ID of system Vms
- pstmt = conn.prepareStatement("update `cloud`.`vm_instance` set vm_template_id = ? where type <> 'User' and hypervisor_type = 'VMware'");
- pstmt.setLong(1, templateId);
- pstmt.executeUpdate();
- pstmt.close();
- } else {
- if (VMware) {
- throw new CloudRuntimeException("3.0.5 VMware SystemVm Template not found. Cannot upgrade system Vms");
- } else {
- logger.warn("3.0.5 VMware SystemVm Template not found. VMware hypervisor is not used, so not failing upgrade");
- }
- }
- } catch (SQLException e) {
- throw new CloudRuntimeException("Error while updating VMware systemVM Template", e);
- }
- logger.debug("Updating System VM Template IDs Complete");
- }
-
private void addVpcProvider(Connection conn) {
//Encrypt config params and change category to Hidden
logger.debug("Adding VPC provider to all physical Networks in the system");
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java
index 94e6149..a78f93f 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java
@@ -1195,9 +1195,9 @@
plannerName = "FirstFitPlanner";
} else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.firstfit.toString())) {
plannerName = "FirstFitPlanner";
- } else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.userconcentratedpod_firstfit.toString())) {
+ } else if (globalValue.equals("userconcentratedpod_firstfit")) {
plannerName = "UserConcentratedPodPlanner";
- } else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.userconcentratedpod_random.toString())) {
+ } else if (globalValue.equals("userconcentratedpod_random")) {
plannerName = "UserConcentratedPodPlanner";
} else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.userdispersing.toString())) {
plannerName = "UserDispersingPlanner";
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
index a383826..35e7065 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
@@ -159,7 +159,7 @@
try (PreparedStatement pstmt = conn.prepareStatement(createNewColumn)) {
pstmt.execute();
} catch (SQLException e) {
- String message = String.format("Unable to crate new backups' column date due to [%s].", e.getMessage());
+ String message = String.format("Unable to create new backups' column date due to [%s].", e.getMessage());
logger.error(message, e);
throw new CloudRuntimeException(message, e);
}
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42210to42300.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42210to42300.java
new file mode 100644
index 0000000..df47438
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42210to42300.java
@@ -0,0 +1,45 @@
+// 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.upgrade.dao;
+
+import java.io.InputStream;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class Upgrade42210to42300 extends DbUpgradeAbstractImpl implements DbUpgrade, DbUpgradeSystemVmTemplate {
+
+ @Override
+ public String[] getUpgradableVersionRange() {
+ return new String[]{"4.22.1.0", "4.23.0.0"};
+ }
+
+ @Override
+ public String getUpgradedVersion() {
+ return "4.23.0.0";
+ }
+
+ @Override
+ public InputStream[] getPrepareScripts() {
+ final String scriptFile = "META-INF/db/schema-42210to42300.sql";
+ final InputStream script = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFile);
+ if (script == null) {
+ throw new CloudRuntimeException("Unable to find " + scriptFile);
+ }
+
+ return new InputStream[] {script};
+ }
+}
diff --git a/engine/schema/src/main/java/com/cloud/user/UserAccountVO.java b/engine/schema/src/main/java/com/cloud/user/UserAccountVO.java
index e4fcbad..c5ca410 100644
--- a/engine/schema/src/main/java/com/cloud/user/UserAccountVO.java
+++ b/engine/schema/src/main/java/com/cloud/user/UserAccountVO.java
@@ -226,10 +226,6 @@
return created;
}
-// public void setCreated(Date created) {
-// this.created = created;
-// }
-
@Override
public Date getRemoved() {
return removed;
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
index 79d0b0e..761053a 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
@@ -782,7 +782,7 @@
result.add(new Ternary<Integer, Integer, Integer>(rs.getInt(1), rs.getInt(2), rs.getInt(3)));
}
} catch (Exception e) {
- logger.warn("Error counting Instances by size for dcId= " + dcId, e);
+ logger.warn("Error counting Instances by size for Data Center ID = " + dcId, e);
}
return result;
}
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
index 703fabd..b4ad7d2 100755
--- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
@@ -900,7 +900,7 @@
return rs.getLong(1);
}
} catch (Exception e) {
- logger.warn(String.format("Error counting Instances by host tag for dcId= %s, hostTag= %s", dcId, hostTag), e);
+ logger.warn("Error counting Instances by host tag for dcId = {}, hostTag = {}", dcId, hostTag, e);
}
return 0L;
}
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDetailsDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDetailsDao.java
index ea9ac5a..4cbdc51 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDetailsDao.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDetailsDao.java
@@ -22,4 +22,5 @@
import com.cloud.vm.VMInstanceDetailVO;
public interface VMInstanceDetailsDao extends GenericDao<VMInstanceDetailVO, Long>, ResourceDetailsDao<VMInstanceDetailVO> {
+ int removeDetailsWithPrefix(long vmId, String prefix);
}
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDetailsDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDetailsDaoImpl.java
index ca11b00..4c2fdd6 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDetailsDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDetailsDaoImpl.java
@@ -17,10 +17,13 @@
package com.cloud.vm.dao;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.VMInstanceDetailVO;
@Component
@@ -31,4 +34,18 @@
super.addDetail(new VMInstanceDetailVO(resourceId, key, value, display));
}
+ @Override
+ public int removeDetailsWithPrefix(long vmId, String prefix) {
+ if (StringUtils.isBlank(prefix)) {
+ return 0;
+ }
+ SearchBuilder<VMInstanceDetailVO> sb = createSearchBuilder();
+ sb.and("vmId", sb.entity().getResourceId(), SearchCriteria.Op.EQ);
+ sb.and("prefix", sb.entity().getName(), SearchCriteria.Op.LIKE);
+ sb.done();
+ SearchCriteria<VMInstanceDetailVO> sc = sb.create();
+ sc.setParameters("vmId", vmId);
+ sc.setParameters("prefix", prefix + "%");
+ return super.remove(sc);
+ }
}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingDetailsVO.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingDetailsVO.java
new file mode 100644
index 0000000..6bdf760
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingDetailsVO.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.backup;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.apache.cloudstack.api.ResourceDetail;
+
+@Entity
+@Table(name = "backup_offering_details")
+public class BackupOfferingDetailsVO implements ResourceDetail {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private long id;
+
+ @Column(name = "backup_offering_id")
+ private long resourceId;
+
+ @Column(name = "name")
+ private String name;
+
+ @Column(name = "value")
+ private String value;
+
+ @Column(name = "display")
+ private boolean display = true;
+
+ protected BackupOfferingDetailsVO() {
+ }
+
+ public BackupOfferingDetailsVO(long backupOfferingId, String name, String value, boolean display) {
+ this.resourceId = backupOfferingId;
+ this.name = name;
+ this.value = value;
+ this.display = display;
+ }
+
+ @Override
+ public long getResourceId() {
+ return resourceId;
+ }
+
+ public void setResourceId(long backupOfferingId) {
+ this.resourceId = backupOfferingId;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ @Override
+ public boolean isDisplay() {
+ return display;
+ }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingVO.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingVO.java
index d30385a..ebeb7d4 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingVO.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingVO.java
@@ -17,6 +17,8 @@
package org.apache.cloudstack.backup;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+
import java.util.Date;
import java.util.UUID;
@@ -131,4 +133,9 @@
public Date getCreated() {
return created;
}
+
+ @Override
+ public String toString() {
+ return String.format("Backup offering %s.", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "name", "uuid"));
+ }
}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDaoImpl.java
index a41e4e7..708faee 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDaoImpl.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDaoImpl.java
@@ -20,6 +20,8 @@
import javax.annotation.PostConstruct;
import javax.inject.Inject;
+import com.cloud.domain.DomainVO;
+import com.cloud.domain.dao.DomainDao;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.backup.BackupOfferingVO;
@@ -30,10 +32,16 @@
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
+import java.util.List;
+
public class BackupOfferingDaoImpl extends GenericDaoBase<BackupOfferingVO, Long> implements BackupOfferingDao {
@Inject
DataCenterDao dataCenterDao;
+ @Inject
+ BackupOfferingDetailsDao backupOfferingDetailsDao;
+ @Inject
+ DomainDao domainDao;
private SearchBuilder<BackupOfferingVO> backupPoliciesSearch;
@@ -51,8 +59,9 @@
@Override
public BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering, Boolean crossZoneInstanceCreation) {
- DataCenterVO zone = dataCenterDao.findById(offering.getZoneId());
+ DataCenterVO zone = dataCenterDao.findById(offering.getZoneId());
+ List<Long> domainIds = backupOfferingDetailsDao.findDomainIds(offering.getId());
BackupOfferingResponse response = new BackupOfferingResponse();
response.setId(offering.getUuid());
response.setName(offering.getName());
@@ -64,6 +73,18 @@
response.setZoneId(zone.getUuid());
response.setZoneName(zone.getName());
}
+ if (domainIds != null && !domainIds.isEmpty()) {
+ String domainUUIDs = domainIds.stream().map(Long::valueOf).map(domainId -> {
+ DomainVO domain = domainDao.findById(domainId);
+ return domain != null ? domain.getUuid() : "";
+ }).filter(name -> !name.isEmpty()).reduce((a, b) -> a + "," + b).orElse("");
+ String domainNames = domainIds.stream().map(Long::valueOf).map(domainId -> {
+ DomainVO domain = domainDao.findById(domainId);
+ return domain != null ? domain.getName() : "";
+ }).filter(name -> !name.isEmpty()).reduce((a, b) -> a + "," + b).orElse("");
+ response.setDomain(domainNames);
+ response.setDomainId(domainUUIDs);
+ }
if (crossZoneInstanceCreation) {
response.setCrossZoneInstanceCreation(true);
}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDao.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDao.java
new file mode 100644
index 0000000..390fcba
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDao.java
@@ -0,0 +1,32 @@
+// 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.backup.dao;
+
+import java.util.List;
+
+import org.apache.cloudstack.backup.BackupOfferingDetailsVO;
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
+
+import com.cloud.utils.db.GenericDao;
+
+public interface BackupOfferingDetailsDao extends GenericDao<BackupOfferingDetailsVO, Long>, ResourceDetailsDao<BackupOfferingDetailsVO> {
+ List<Long> findDomainIds(final long resourceId);
+ List<Long> findZoneIds(final long resourceId);
+ String getDetail(Long backupOfferingId, String key);
+ List<Long> findOfferingIdsByDomainIds(List<Long> domainIds);
+ void updateBackupOfferingDomainIdsDetail(long backupOfferingId, List<Long> filteredDomainIds);
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDaoImpl.java
new file mode 100644
index 0000000..f052c93
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDaoImpl.java
@@ -0,0 +1,101 @@
+// 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.backup.dao;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.backup.BackupOfferingDetailsVO;
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
+import org.springframework.stereotype.Component;
+
+@Component
+public class BackupOfferingDetailsDaoImpl extends ResourceDetailsDaoBase<BackupOfferingDetailsVO> implements BackupOfferingDetailsDao {
+
+ @Override
+ public void addDetail(long resourceId, String key, String value, boolean display) {
+ super.addDetail(new BackupOfferingDetailsVO(resourceId, key, value, display));
+ }
+
+ @Override
+ public List<Long> findDomainIds(long resourceId) {
+ final List<Long> domainIds = new ArrayList<>();
+ for (final BackupOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.DOMAIN_ID)) {
+ final Long domainId = Long.valueOf(detail.getValue());
+ if (domainId > 0) {
+ domainIds.add(domainId);
+ }
+ }
+ return domainIds;
+ }
+
+ @Override
+ public List<Long> findZoneIds(long resourceId) {
+ final List<Long> zoneIds = new ArrayList<>();
+ for (final BackupOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.ZONE_ID)) {
+ final Long zoneId = Long.valueOf(detail.getValue());
+ if (zoneId > 0) {
+ zoneIds.add(zoneId);
+ }
+ }
+ return zoneIds;
+ }
+
+ @Override
+ public String getDetail(Long backupOfferingId, String key) {
+ String detailValue = null;
+ BackupOfferingDetailsVO backupOfferingDetail = findDetail(backupOfferingId, key);
+ if (backupOfferingDetail != null) {
+ detailValue = backupOfferingDetail.getValue();
+ }
+ return detailValue;
+ }
+
+ @Override
+ public List<Long> findOfferingIdsByDomainIds(List<Long> domainIds) {
+ Object[] dIds = domainIds.stream().map(s -> String.valueOf(s)).collect(Collectors.toList()).toArray();
+ return findResourceIdsByNameAndValueIn("domainid", dIds);
+ }
+
+ @DB
+ @Override
+ public void updateBackupOfferingDomainIdsDetail(long backupOfferingId, List<Long> filteredDomainIds) {
+ SearchBuilder<BackupOfferingDetailsVO> sb = createSearchBuilder();
+ List<BackupOfferingDetailsVO> detailsVO = new ArrayList<>();
+ sb.and("offeringId", sb.entity().getResourceId(), SearchCriteria.Op.EQ);
+ sb.and("detailName", sb.entity().getName(), SearchCriteria.Op.EQ);
+ sb.done();
+ SearchCriteria<BackupOfferingDetailsVO> sc = sb.create();
+ sc.setParameters("offeringId", String.valueOf(backupOfferingId));
+ sc.setParameters("detailName", ApiConstants.DOMAIN_ID);
+ remove(sc);
+ for (Long domainId : filteredDomainIds) {
+ detailsVO.add(new BackupOfferingDetailsVO(backupOfferingId, ApiConstants.DOMAIN_ID, String.valueOf(domainId), false));
+ }
+ if (!detailsVO.isEmpty()) {
+ for (BackupOfferingDetailsVO detailVO : detailsVO) {
+ persist(detailVO);
+ }
+ }
+ }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
index d57dec8..c475a42 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
@@ -209,10 +209,8 @@
public VolumeDataStoreVO(long hostId, long volumeId, Date lastUpdated, int downloadPercent, Status downloadState, String localDownloadPath, String errorString,
String jobId, String installPath, String downloadUrl, String checksum) {
- // super();
dataStoreId = hostId;
this.volumeId = volumeId;
- // this.zoneId = zoneId;
this.lastUpdated = lastUpdated;
this.downloadPercent = downloadPercent;
this.downloadState = downloadState;
diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml
index d308a9e..1846c3c 100644
--- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml
+++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml
@@ -71,6 +71,7 @@
<bean id="NetworkDaoImpl" class="org.apache.cloudstack.quota.dao.NetworkDaoImpl" />
<bean id="VpcDaoImpl" class="org.apache.cloudstack.quota.dao.VpcDaoImpl" />
<bean id="volumeDaoImpl" class="com.cloud.storage.dao.VolumeDaoImpl" />
- <bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" />
+ <bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" />
<bean id="backupOfferingDaoImpl" class="org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl" />
+ <bean id="backupOfferingDetailsDaoImpl" class="org.apache.cloudstack.backup.dao.BackupOfferingDetailsDaoImpl" />
</beans>
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-307to410.sql b/engine/schema/src/main/resources/META-INF/db/schema-307to410.sql
index 55d78b5..3b0cfa8 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-307to410.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-307to410.sql
@@ -3,7 +3,7 @@
-- 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 compliances
+-- "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
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42100to42200.sql b/engine/schema/src/main/resources/META-INF/db/schema-42100to42200.sql
index b523016..858c46a 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-42100to42200.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-42100to42200.sql
@@ -87,3 +87,8 @@
CALL `cloud`.`IDEMPOTENT_DROP_UNIQUE_KEY`('counter', 'uc_counter__provider__source__value');
CALL `cloud`.`IDEMPOTENT_ADD_UNIQUE_KEY`('cloud.counter', 'uc_counter__provider__source__value__removed', '(provider, source, value, removed)');
+
+-- Change scope for configuration - 'use.https.to.upload from' from StoragePool to Zone
+UPDATE `cloud`.`configuration` SET `scope` = 2 WHERE `name` = 'use.https.to.upload';
+-- Delete the configuration for 'use.https.to.upload' from StoragePool
+DELETE FROM `cloud`.`storage_pool_details` WHERE `name` = 'use.https.to.upload';
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300-cleanup.sql
new file mode 100644
index 0000000..e2b066a
--- /dev/null
+++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300-cleanup.sql
@@ -0,0 +1,20 @@
+-- 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.
+
+--;
+-- Schema upgrade cleanup from 4.22.1.0 to 4.23.0.0
+--;
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql
new file mode 100644
index 0000000..d330ecd
--- /dev/null
+++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql
@@ -0,0 +1,51 @@
+-- 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.
+
+--;
+-- Schema upgrade from 4.22.1.0 to 4.23.0.0
+--;
+
+CREATE TABLE `cloud`.`backup_offering_details` (
+ `id` bigint unsigned NOT NULL auto_increment,
+ `backup_offering_id` bigint unsigned NOT NULL COMMENT 'Backup offering id',
+ `name` varchar(255) NOT NULL,
+ `value` varchar(1024) NOT NULL,
+ `display` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should detail be displayed to the end user',
+ PRIMARY KEY (`id`),
+ CONSTRAINT `fk_offering_details__backup_offering_id` FOREIGN KEY `fk_offering_details__backup_offering_id`(`backup_offering_id`) REFERENCES `backup_offering`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Update value to random for the config 'vm.allocation.algorithm' or 'volume.allocation.algorithm' if configured as userconcentratedpod_random
+-- Update value to firstfit for the config 'vm.allocation.algorithm' or 'volume.allocation.algorithm' if configured as userconcentratedpod_firstfit
+UPDATE `cloud`.`configuration` SET value='random' WHERE name IN ('vm.allocation.algorithm', 'volume.allocation.algorithm') AND value='userconcentratedpod_random';
+UPDATE `cloud`.`configuration` SET value='firstfit' WHERE name IN ('vm.allocation.algorithm', 'volume.allocation.algorithm') AND value='userconcentratedpod_firstfit';
+
+-- Create webhook_filter table
+DROP TABLE IF EXISTS `cloud`.`webhook_filter`;
+CREATE TABLE IF NOT EXISTS `cloud`.`webhook_filter` (
+ `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id of the webhook filter',
+ `uuid` varchar(255) COMMENT 'uuid of the webhook filter',
+ `webhook_id` bigint unsigned NOT NULL COMMENT 'id of the webhook',
+ `type` varchar(20) COMMENT 'type of the filter',
+ `mode` varchar(20) COMMENT 'mode of the filter',
+ `match_type` varchar(20) COMMENT 'match type of the filter',
+ `value` varchar(256) NOT NULL COMMENT 'value of the filter used for matching',
+ `created` datetime NOT NULL COMMENT 'date created',
+ PRIMARY KEY (`id`),
+ INDEX `i_webhook_filter__webhook_id`(`webhook_id`),
+ CONSTRAINT `fk_webhook_filter__webhook_id` FOREIGN KEY(`webhook_id`) REFERENCES `webhook`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
diff --git a/engine/schema/src/test/java/com/cloud/network/dao/NetworkDaoImplTest.java b/engine/schema/src/test/java/com/cloud/network/dao/NetworkDaoImplTest.java
index ab5f435..a78eab5 100644
--- a/engine/schema/src/test/java/com/cloud/network/dao/NetworkDaoImplTest.java
+++ b/engine/schema/src/test/java/com/cloud/network/dao/NetworkDaoImplTest.java
@@ -22,7 +22,6 @@
import com.cloud.network.Networks;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
-import com.cloud.utils.db.TransactionLegacy;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -30,7 +29,6 @@
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
-
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
@@ -46,26 +44,21 @@
List<NetworkVO> listNetworkVoMock;
@Test
- public void listByPhysicalNetworkTrafficTypeTestSetParametersValidation() throws Exception {
+ public void listByPhysicalNetworkTrafficTypeTestSetParametersValidation() {
NetworkDaoImpl networkDaoImplSpy = Mockito.spy(NetworkDaoImpl.class);
- TransactionLegacy txn = TransactionLegacy.open("runNetworkDaoImplTest");
- try {
- networkDaoImplSpy.AllFieldsSearch = searchBuilderNetworkVoMock;
- Mockito.doReturn(searchCriteriaNetworkVoMock).when(searchBuilderNetworkVoMock).create();
- Mockito.doNothing().when(searchCriteriaNetworkVoMock).setParameters(Mockito.anyString(), Mockito.any());
- Mockito.doReturn(listNetworkVoMock).when(networkDaoImplSpy).listBy(Mockito.any(SearchCriteria.class));
+ networkDaoImplSpy.AllFieldsSearch = searchBuilderNetworkVoMock;
+ Mockito.doReturn(searchCriteriaNetworkVoMock).when(searchBuilderNetworkVoMock).create();
+ Mockito.doNothing().when(searchCriteriaNetworkVoMock).setParameters(Mockito.anyString(), Mockito.any());
+ Mockito.doReturn(listNetworkVoMock).when(networkDaoImplSpy).listBy(Mockito.any(SearchCriteria.class));
- long expectedPhysicalNetwork = 2513l;
+ long expectedPhysicalNetwork = 2513l;
- for (Networks.TrafficType trafficType : Networks.TrafficType.values()) {
- List<NetworkVO> result = networkDaoImplSpy.listByPhysicalNetworkTrafficType(expectedPhysicalNetwork, trafficType);
- Assert.assertEquals(listNetworkVoMock, result);
- Mockito.verify(searchCriteriaNetworkVoMock).setParameters("trafficType", trafficType);
- }
-
- Mockito.verify(searchCriteriaNetworkVoMock, Mockito.times(Networks.TrafficType.values().length)).setParameters("physicalNetwork", expectedPhysicalNetwork);
- } finally {
- txn.close();
+ for (Networks.TrafficType trafficType : Networks.TrafficType.values()) {
+ List<NetworkVO> result = networkDaoImplSpy.listByPhysicalNetworkTrafficType(expectedPhysicalNetwork, trafficType);
+ Assert.assertEquals(listNetworkVoMock, result);
+ Mockito.verify(searchCriteriaNetworkVoMock).setParameters("trafficType", trafficType);
}
+
+ Mockito.verify(searchCriteriaNetworkVoMock, Mockito.times(Networks.TrafficType.values().length)).setParameters("physicalNetworkId", expectedPhysicalNetwork);
}
}
diff --git a/engine/schema/src/test/java/com/cloud/storage/dao/VMTemplateDaoImplTest.java b/engine/schema/src/test/java/com/cloud/storage/dao/VMTemplateDaoImplTest.java
index 3c8e4c0..5cff778 100644
--- a/engine/schema/src/test/java/com/cloud/storage/dao/VMTemplateDaoImplTest.java
+++ b/engine/schema/src/test/java/com/cloud/storage/dao/VMTemplateDaoImplTest.java
@@ -76,7 +76,8 @@
VMTemplateVO expectedTemplate = new VMTemplateVO();
List<VMTemplateVO> returnedList = Collections.singletonList(expectedTemplate);
doReturn(returnedList).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
- VMTemplateVO result = templateDao.findLatestTemplateByName("test", CPU.CPUArch.getDefault());
+ VMTemplateVO result = templateDao.findLatestTemplateByName("test", Hypervisor.HypervisorType.KVM,
+ CPU.CPUArch.getDefault());
assertNotNull("Expected a non-null template", result);
assertEquals("Expected the returned template to be the first element", expectedTemplate, result);
}
@@ -85,7 +86,8 @@
public void testFindLatestTemplateByName_ReturnsNullWhenNoTemplateFound() {
List<VMTemplateVO> emptyList = Collections.emptyList();
doReturn(emptyList).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
- VMTemplateVO result = templateDao.findLatestTemplateByName("test", CPU.CPUArch.getDefault());
+ VMTemplateVO result = templateDao.findLatestTemplateByName("test", Hypervisor.HypervisorType.VMware,
+ CPU.CPUArch.getDefault());
assertNull("Expected null when no templates are found", result);
}
@@ -94,7 +96,8 @@
VMTemplateVO expectedTemplate = new VMTemplateVO();
List<VMTemplateVO> returnedList = Collections.singletonList(expectedTemplate);
doReturn(returnedList).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
- VMTemplateVO result = templateDao.findLatestTemplateByName("test", null);
+ VMTemplateVO result = templateDao.findLatestTemplateByName("test", Hypervisor.HypervisorType.XenServer,
+ null);
assertNotNull("Expected a non-null template even if arch is null", result);
assertEquals("Expected the returned template to be the first element", expectedTemplate, result);
}
@@ -337,4 +340,82 @@
VMTemplateVO readyTemplate = templateDao.findSystemVMReadyTemplate(zoneId, Hypervisor.HypervisorType.KVM, CPU.CPUArch.arm64.getType());
Assert.assertEquals(CPU.CPUArch.arm64, readyTemplate.getArch());
}
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_ReturnsTemplate() {
+ VMTemplateVO expectedTemplate = mock(VMTemplateVO.class);
+ SearchBuilder<VMTemplateVO> sb = mock(SearchBuilder.class);
+ when(sb.entity()).thenReturn(expectedTemplate);
+ SearchCriteria<VMTemplateVO>sc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(templateDao.createSearchBuilder()).thenReturn(sb);
+ List<VMTemplateVO> templates = Collections.singletonList(expectedTemplate);
+ doReturn(templates).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
+
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "testPath");
+
+ assertNotNull(result);
+ assertEquals(expectedTemplate, result);
+ }
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_ReturnsNullWhenNoTemplatesFound() {
+ VMTemplateVO template = mock(VMTemplateVO.class);
+ SearchBuilder<VMTemplateVO> sb = mock(SearchBuilder.class);
+ when(sb.entity()).thenReturn(template);
+ SearchCriteria<VMTemplateVO>sc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(templateDao.createSearchBuilder()).thenReturn(sb);
+ doReturn(Collections.emptyList()).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
+
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "testPath");
+
+ assertNull(result);
+ }
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_NullHypervisor() {
+ VMTemplateVO expectedTemplate = mock(VMTemplateVO.class);
+ SearchBuilder<VMTemplateVO> sb = mock(SearchBuilder.class);
+ when(sb.entity()).thenReturn(expectedTemplate);
+ SearchCriteria<VMTemplateVO>sc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(templateDao.createSearchBuilder()).thenReturn(sb);
+ List<VMTemplateVO> templates = Collections.singletonList(expectedTemplate);
+ doReturn(templates).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
+
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ null, CPU.CPUArch.amd64, "testPath");
+
+ assertNotNull(result);
+ assertEquals(expectedTemplate, result);
+ }
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_NullArch() {
+ VMTemplateVO expectedTemplate = mock(VMTemplateVO.class);
+ SearchBuilder<VMTemplateVO> sb = mock(SearchBuilder.class);
+ when(sb.entity()).thenReturn(expectedTemplate);
+ SearchCriteria<VMTemplateVO>sc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(templateDao.createSearchBuilder()).thenReturn(sb);
+ List<VMTemplateVO> templates = Collections.singletonList(expectedTemplate);
+ doReturn(templates).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
+
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ Hypervisor.HypervisorType.KVM, null, "testPath");
+
+ assertNotNull(result);
+ assertEquals(expectedTemplate, result);
+ }
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_EmptyUrlPathSuffix() {
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "");
+
+ assertNull(result);
+ }
}
diff --git a/engine/schema/src/test/java/com/cloud/upgrade/SystemVmTemplateRegistrationTest.java b/engine/schema/src/test/java/com/cloud/upgrade/SystemVmTemplateRegistrationTest.java
index b943f48..8028e78 100644
--- a/engine/schema/src/test/java/com/cloud/upgrade/SystemVmTemplateRegistrationTest.java
+++ b/engine/schema/src/test/java/com/cloud/upgrade/SystemVmTemplateRegistrationTest.java
@@ -17,6 +17,7 @@
package com.cloud.upgrade;
+import static com.cloud.upgrade.SystemVmTemplateRegistration.DEFAULT_SYSTEM_VM_GUEST_OS_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -25,24 +26,41 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.File;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
+import java.util.Map;
+import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
+import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.utils.security.DigestHelper;
import org.apache.commons.lang3.StringUtils;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -53,15 +71,27 @@
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.cpu.CPU;
+import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.DataCenterDetailsDao;
import com.cloud.hypervisor.Hypervisor;
+import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.Storage;
+import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VMTemplateZoneVO;
+import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VMTemplateZoneDao;
+import com.cloud.template.VirtualMachineTemplate;
import com.cloud.utils.HttpUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.UriUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
+import com.cloud.vm.dao.VMInstanceDao;
@RunWith(MockitoJUnitRunner.class)
public class SystemVmTemplateRegistrationTest {
@@ -72,10 +102,42 @@
@Mock
VMTemplateDao vmTemplateDao;
+ @Mock
+ GuestOSDao guestOSDao;
+
+ @Mock
+ TemplateDataStoreDao templateDataStoreDao;
+
+ @Mock
+ ConfigurationDao configurationDao;
+
+ @Mock
+ DataCenterDao dataCenterDao;
+
+ @Mock
+ DataCenterDetailsDao dataCenterDetailsDao;
+
+ @Mock
+ VMTemplateZoneDao vmTemplateZoneDao;
+
+ @Mock
+ ImageStoreDao imageStoreDao;
+
+ @Mock
+ ImageStoreDetailsDao imageStoreDetailsDao;
+
+ @Mock
+ VMInstanceDao vmInstanceDao;
+
@Spy
@InjectMocks
SystemVmTemplateRegistration systemVmTemplateRegistration = new SystemVmTemplateRegistration();
+ @Before
+ public void setup() {
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.clear();
+ }
+
private void setupMetadataFile(MockedStatic<SystemVmTemplateRegistration> mockedStatic, String content) {
try {
String location = "metadata.ini";
@@ -98,7 +160,7 @@
setupMetadataFile(mockedStatic, null);
CloudRuntimeException exception = assertThrows(CloudRuntimeException.class,
SystemVmTemplateRegistration::parseMetadataFile);
- assertTrue(exception.getMessage().contains("Failed to parse systemVM Template metadata file"));
+ assertTrue(exception.getMessage().contains("Failed to parse system VM Template metadata file"));
}
}
@@ -109,7 +171,7 @@
setupMetadataFile(mockedStatic, "abc");
CloudRuntimeException exception = assertThrows(CloudRuntimeException.class,
SystemVmTemplateRegistration::parseMetadataFile);
- assertTrue(exception.getMessage().contains("Failed to parse systemVM Template metadata file"));
+ assertTrue(exception.getMessage().contains("Failed to parse system VM Template metadata file"));
}
}
@@ -141,21 +203,25 @@
String version = SystemVmTemplateRegistration.parseMetadataFile();
assertEquals("x.y.z.0", version);
}
- assertNull(SystemVmTemplateRegistration.NewTemplateMap.get("xenserver"));
+ assertNull(SystemVmTemplateRegistration.getMetadataTemplateDetails(Hypervisor.HypervisorType.XenServer,
+ CPU.CPUArch.getDefault()));
SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
- SystemVmTemplateRegistration.NewTemplateMap.get("kvm-x86_64");
+ SystemVmTemplateRegistration.getMetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
+ CPU.CPUArch.amd64);
assertNotNull(templateDetails);
assertEquals(CPU.CPUArch.amd64, templateDetails.getArch());
assertEquals(Hypervisor.HypervisorType.KVM, templateDetails.getHypervisorType());
templateDetails =
- SystemVmTemplateRegistration.NewTemplateMap.get("kvm-aarch64");
+ SystemVmTemplateRegistration.getMetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
+ CPU.CPUArch.arm64);
assertNotNull(templateDetails);
assertEquals(CPU.CPUArch.arm64, templateDetails.getArch());
assertEquals(Hypervisor.HypervisorType.KVM, templateDetails.getHypervisorType());
templateDetails =
- SystemVmTemplateRegistration.NewTemplateMap.get("vmware");
+ SystemVmTemplateRegistration.getMetadataTemplateDetails(Hypervisor.HypervisorType.VMware,
+ CPU.CPUArch.getDefault());
assertNotNull(templateDetails);
- assertNull(templateDetails.getArch());
+ assertEquals(CPU.CPUArch.getDefault(), templateDetails.getArch());
assertEquals(Hypervisor.HypervisorType.VMware, templateDetails.getHypervisorType());
}
@@ -193,11 +259,10 @@
SystemVmTemplateRegistration.MetadataTemplateDetails details =
new SystemVmTemplateRegistration.MetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
"name", "file", "url", "checksum", CPU.CPUArch.amd64, "guestos");
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- details.getHypervisorType(), details.getArch()), details);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(null).when(systemVmTemplateRegistration).getTemplateFile(details);
try {
- systemVmTemplateRegistration.validateTemplateFileForHypervisorAndArch(details.getHypervisorType(),
+ systemVmTemplateRegistration.getValidatedTemplateDetailsForHypervisorAndArch(details.getHypervisorType(),
details.getArch());
fail("Expected CloudRuntimeException due to missing template file");
} catch (CloudRuntimeException e) {
@@ -211,12 +276,11 @@
new SystemVmTemplateRegistration.MetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
"name", "file", "url", "checksum", CPU.CPUArch.amd64, "guestos");
File dummyFile = new File("dummy.txt");
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- details.getHypervisorType(), details.getArch()), details);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(dummyFile).when(systemVmTemplateRegistration).getTemplateFile(details);
- doReturn(true).when(systemVmTemplateRegistration).isTemplateFileChecksumDifferent(details, dummyFile);
- try {
- systemVmTemplateRegistration.validateTemplateFileForHypervisorAndArch(details.getHypervisorType(),
+ try (MockedStatic<DigestHelper> digestMock = Mockito.mockStatic(DigestHelper.class)) {
+ digestMock.when(() -> DigestHelper.calculateChecksum(dummyFile)).thenReturn("differentChecksum");
+ systemVmTemplateRegistration.getValidatedTemplateDetailsForHypervisorAndArch(details.getHypervisorType(),
details.getArch());
fail("Expected CloudRuntimeException due to checksum failure");
} catch (CloudRuntimeException e) {
@@ -230,42 +294,55 @@
new SystemVmTemplateRegistration.MetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
"name", "file", "url", "checksum", CPU.CPUArch.amd64, "guestos");
File dummyFile = new File("dummy.txt");
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- details.getHypervisorType(), details.getArch()), details);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(dummyFile).when(systemVmTemplateRegistration).getTemplateFile(details);
- doReturn(false).when(systemVmTemplateRegistration).isTemplateFileChecksumDifferent(details, dummyFile);
- systemVmTemplateRegistration.validateTemplateFileForHypervisorAndArch(details.getHypervisorType(),
- details.getArch());
+ try (MockedStatic<DigestHelper> digestMock = Mockito.mockStatic(DigestHelper.class)) {
+ digestMock.when(() -> DigestHelper.calculateChecksum(dummyFile)).thenReturn("checksum");
+ systemVmTemplateRegistration.getValidatedTemplateDetailsForHypervisorAndArch(details.getHypervisorType(),
+ details.getArch());
+ }
}
@Test
- public void testValidateAndRegisterTemplate() {
+ public void testValidateAndAddExistingTemplateToStore() {
+ long zoneId = 1L;
Hypervisor.HypervisorType hypervisor = Hypervisor.HypervisorType.KVM;
- String name = "TestTemplate";
- Long storeId = 123L;
VMTemplateVO templateVO = new VMTemplateVO();
- templateVO.setArch(CPU.CPUArch.x86);
+ templateVO.setHypervisorType(hypervisor);
+ templateVO.setArch(CPU.CPUArch.getDefault());
TemplateDataStoreVO templateDataStoreVO = new TemplateDataStoreVO();
+ Long storeId = 123L;
String filePath = "/dummy/path";
- doNothing().when(systemVmTemplateRegistration).validateTemplateFileForHypervisorAndArch(hypervisor, templateVO.getArch());
- doNothing().when(systemVmTemplateRegistration).registerTemplate(hypervisor, name, storeId, templateVO, templateDataStoreVO, filePath);
- systemVmTemplateRegistration.validateAndRegisterTemplate(hypervisor, name, storeId, templateVO, templateDataStoreVO, filePath);
- verify(systemVmTemplateRegistration).validateTemplateFileForHypervisorAndArch(eq(hypervisor), eq(templateVO.getArch()));
- verify(systemVmTemplateRegistration).registerTemplate(eq(hypervisor), eq(name), eq(storeId), eq(templateVO), eq(templateDataStoreVO), eq(filePath));
+ SystemVmTemplateRegistration.MetadataTemplateDetails details =
+ mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ doReturn(details).when(systemVmTemplateRegistration)
+ .getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, templateVO.getArch());
+ doNothing().when(systemVmTemplateRegistration).addExistingTemplateToStore(templateVO, details,
+ templateDataStoreVO, zoneId, storeId, filePath);
+ systemVmTemplateRegistration.validateAndAddTemplateToStore(templateVO, templateDataStoreVO, zoneId, storeId,
+ filePath);
+ verify(systemVmTemplateRegistration)
+ .getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, templateVO.getArch());
+ verify(systemVmTemplateRegistration).addExistingTemplateToStore(templateVO, details, templateDataStoreVO,
+ zoneId, storeId, filePath);
}
@Test
- public void testValidateAndRegisterTemplateForNonExistingEntries() {
+ public void testValidateAndAddExistingTemplateToStoreForNonExistingEntries() {
+ long zoneId = 1L;
Hypervisor.HypervisorType hypervisor = Hypervisor.HypervisorType.KVM;
CPU.CPUArch arch = CPU.CPUArch.amd64;
String name = "TestTemplateNonExisting";
- Pair<String, Long> storeUrlAndId = new Pair<>("nfs://dummy", 456L);
+ long storeId = 123L;
String filePath = "/dummy/path/nonexisting";
- doNothing().when(systemVmTemplateRegistration).validateTemplateFileForHypervisorAndArch(hypervisor, arch);
- doNothing().when(systemVmTemplateRegistration).registerTemplateForNonExistingEntries(hypervisor, arch, name, storeUrlAndId, filePath);
- systemVmTemplateRegistration.validateAndRegisterTemplateForNonExistingEntries(hypervisor, arch, name, storeUrlAndId, filePath);
- verify(systemVmTemplateRegistration).validateTemplateFileForHypervisorAndArch(eq(hypervisor), eq(arch));
- verify(systemVmTemplateRegistration).registerTemplateForNonExistingEntries(eq(hypervisor), eq(arch), eq(name), eq(storeUrlAndId), eq(filePath));
+ SystemVmTemplateRegistration.MetadataTemplateDetails details =
+ mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ doReturn(details).when(systemVmTemplateRegistration)
+ .getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, arch);
+ doNothing().when(systemVmTemplateRegistration).registerNewTemplate(name, details, zoneId, storeId, filePath);
+ systemVmTemplateRegistration.validateAndRegisterNewTemplate(hypervisor, arch, name, zoneId, storeId, filePath);
+ verify(systemVmTemplateRegistration).getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, arch);
+ verify(systemVmTemplateRegistration).registerNewTemplate(name, details, zoneId, storeId, filePath);
}
@Test
@@ -316,86 +393,73 @@
}
@Test
- public void testIsTemplateFileChecksumDifferent_noMismatch() {
- SystemVmTemplateRegistration.MetadataTemplateDetails details =
- Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- when(details.getChecksum()).thenReturn("dummyChecksum");
- File file = new File("dummy.txt");
- try (MockedStatic<DigestHelper> digestMock = Mockito.mockStatic(DigestHelper.class)) {
- digestMock.when(() -> DigestHelper.calculateChecksum(file)).thenReturn("dummyChecksum");
- boolean result = systemVmTemplateRegistration.isTemplateFileChecksumDifferent(details, file);
- assertFalse(result);
- }
- }
-
- @Test
- public void testIsTemplateFileChecksumDifferent_mismatch() {
- SystemVmTemplateRegistration.MetadataTemplateDetails details =
- Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- when(details.getChecksum()).thenReturn("expectedChecksum");
- File file = new File("dummy.txt");
- try (MockedStatic<DigestHelper> digestMock = Mockito.mockStatic(DigestHelper.class)) {
- digestMock.when(() -> DigestHelper.calculateChecksum(file)).thenReturn("actualChecksum");
- boolean result = systemVmTemplateRegistration.isTemplateFileChecksumDifferent(details, file);
- assertTrue(result);
- }
- }
-
- @Test(expected = CloudRuntimeException.class)
- public void testValidateTemplates_metadataTemplateFailure() {
+ public void testValidateTemplates_metadataTemplateSkip() {
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.VMware;
+ CPU.CPUArch arch = CPU.CPUArch.arm64;
List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> list = new ArrayList<>();
- list.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
+ list.add(new Pair<>(hypervisorType, arch));
systemVmTemplateRegistration.validateTemplates(list);
+ verify(systemVmTemplateRegistration, never()).getValidatedTemplateDetailsForHypervisorAndArch(hypervisorType,
+ arch);
}
@Test(expected = CloudRuntimeException.class)
public void testValidateTemplates_fileFailure() {
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ CPU.CPUArch arch = CPU.CPUArch.amd64;
List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> list = new ArrayList<>();
- list.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
-
+ list.add(new Pair<>(hypervisorType, arch));
SystemVmTemplateRegistration.MetadataTemplateDetails details =
Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64), details);
+ when(details.getHypervisorType()).thenReturn(hypervisorType);
+ when(details.getArch()).thenReturn(arch);
File mockFile = Mockito.mock(File.class);
+ when(details.isFileChecksumDifferent(mockFile)).thenReturn(true);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(mockFile).when(systemVmTemplateRegistration).getTemplateFile(details);
- doReturn(true).when(systemVmTemplateRegistration).isTemplateFileChecksumDifferent(details, mockFile);
systemVmTemplateRegistration.validateTemplates(list);
}
+ @Test(expected = CloudRuntimeException.class)
public void testValidateTemplates_downloadableFileNotFound() {
CPU.CPUArch arch = SystemVmTemplateRegistration.DOWNLOADABLE_TEMPLATE_ARCH_TYPES.get(0);
List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> list = new ArrayList<>();
- list.add(new Pair<>(Hypervisor.HypervisorType.KVM, arch));
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ list.add(new Pair<>(hypervisorType, arch));
SystemVmTemplateRegistration.MetadataTemplateDetails details =
Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- Hypervisor.HypervisorType.KVM, arch), details);
+ when(details.getHypervisorType()).thenReturn(hypervisorType);
+ when(details.getArch()).thenReturn(arch);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(null).when(systemVmTemplateRegistration).getTemplateFile(details);
systemVmTemplateRegistration.validateTemplates(list);
}
@Test
public void testValidateTemplates_success() {
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ CPU.CPUArch arch = CPU.CPUArch.amd64;
List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> list = new ArrayList<>();
- list.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
-
+ list.add(new Pair<>(hypervisorType, arch));
SystemVmTemplateRegistration.MetadataTemplateDetails details =
Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64), details);
+ when(details.getHypervisorType()).thenReturn(hypervisorType);
+ when(details.getArch()).thenReturn(arch);
File mockFile = Mockito.mock(File.class);
+ when(details.isFileChecksumDifferent(mockFile)).thenReturn(false);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(mockFile).when(systemVmTemplateRegistration).getTemplateFile(details);
- doReturn(false).when(systemVmTemplateRegistration).isTemplateFileChecksumDifferent(details, mockFile);
systemVmTemplateRegistration.validateTemplates(list);
}
@Test
- public void testRegisterTemplatesForZone() {
+ public void testAddExistingTemplatesForZoneToStore() {
long zoneId = 1L;
String filePath = "dummyFilePath";
String nfsVersion = "nfs3";
Pair<String, Long> storeUrlAndId = new Pair<>("nfs://dummy", 100L);
+ String name = "existing";
+ String url = "url";
doReturn(storeUrlAndId).when(systemVmTemplateRegistration).getNfsStoreInZone(zoneId);
doReturn(nfsVersion).when(systemVmTemplateRegistration).getNfsVersion(storeUrlAndId.second());
try (MockedStatic<SystemVmTemplateRegistration> mockedStatic = Mockito.mockStatic(
@@ -407,21 +471,1169 @@
doReturn(hypervisorArchList).when(clusterDao).listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
SystemVmTemplateRegistration.MetadataTemplateDetails details =
Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- String name = "existing";
- Mockito.when(details.getArch()).thenReturn(CPU.CPUArch.getDefault());
- Mockito.when(details.getName()).thenReturn(name);
+ when(details.getArch()).thenReturn(CPU.CPUArch.getDefault());
+ when(details.getName()).thenReturn(name);
+ when(details.getUrl()).thenReturn(url);
mockedStatic.when(() -> SystemVmTemplateRegistration.getMetadataTemplateDetails(Mockito.any(),
Mockito.any())).thenReturn(details);
- when(systemVmTemplateRegistration.getRegisteredTemplate(name, arch))
- .thenReturn(null);
- doNothing().when(systemVmTemplateRegistration).registerTemplateForNonExistingEntries(
- hypervisorType, arch,
- name, storeUrlAndId, filePath);
+ doNothing().when(systemVmTemplateRegistration).registerNewTemplate(name, details, zoneId,
+ storeUrlAndId.second(), filePath);
systemVmTemplateRegistration.registerTemplatesForZone(zoneId, filePath);
mockedStatic.verify(() -> SystemVmTemplateRegistration.mountStore(storeUrlAndId.first(), filePath,
nfsVersion));
- verify(systemVmTemplateRegistration).registerTemplateForNonExistingEntries(hypervisorType,
- arch, name, storeUrlAndId, filePath);
+ verify(systemVmTemplateRegistration).registerNewTemplate(name, details, zoneId,
+ storeUrlAndId.second(), filePath);
}
}
+
+ @Test
+ public void updateOrRegisterSystemVmTemplate_UpdatesRegisteredTemplate() {
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ VMTemplateVO registeredTemplate = Mockito.mock(VMTemplateVO.class);
+ when(registeredTemplate.getId()).thenReturn(1L);
+ doReturn(registeredTemplate).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ "templateName", Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "http://example.com/template");
+ doNothing().when(systemVmTemplateRegistration).updateRegisteredTemplateDetails(1L, templateDetails,
+ null);
+
+ boolean result = systemVmTemplateRegistration.updateOrRegisterSystemVmTemplate(templateDetails,
+ new ArrayList<>());
+
+ assertFalse(result);
+ verify(systemVmTemplateRegistration).updateRegisteredTemplateDetails(1L, templateDetails, null);
+ }
+
+ @Test
+ public void updateOrRegisterSystemVmTemplate_SkipsUnusedHypervisorArch() {
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ doReturn(null).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ "templateName", Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "http://example.com/template");
+ doReturn(null).when(vmTemplateDao).findLatestTemplateByTypeAndHypervisorAndArch(
+ Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, Storage.TemplateType.SYSTEM);
+
+ boolean result = systemVmTemplateRegistration.updateOrRegisterSystemVmTemplate(templateDetails, new ArrayList<>());
+
+ assertFalse(result);
+ verify(systemVmTemplateRegistration, never()).registerTemplates(anyList());
+ }
+
+ @Test
+ public void updateOrRegisterSystemVmTemplate_RegistersNewTemplate() {
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ doReturn(null).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ "templateName", Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "http://example.com/template");
+ List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorsInUse = new ArrayList<>();
+ hypervisorsInUse.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
+ doNothing().when(systemVmTemplateRegistration).registerTemplates(hypervisorsInUse);
+
+ boolean result = systemVmTemplateRegistration.updateOrRegisterSystemVmTemplate(templateDetails, hypervisorsInUse);
+
+ assertTrue(result);
+ verify(systemVmTemplateRegistration).registerTemplates(eq(hypervisorsInUse));
+ }
+
+ @Test
+ public void updateOrRegisterSystemVmTemplate_ThrowsExceptionOnRegistrationFailure() {
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ doReturn(null).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ "templateName", Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "http://example.com/template");
+ List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorsInUse = new ArrayList<>();
+ hypervisorsInUse.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
+ doThrow(new CloudRuntimeException("Registration failed")).when(systemVmTemplateRegistration).registerTemplates(hypervisorsInUse);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class,
+ () -> systemVmTemplateRegistration.updateOrRegisterSystemVmTemplate(templateDetails, hypervisorsInUse));
+
+ assertTrue(exception.getMessage().contains("Failed to register"));
+ }
+
+ @Test
+ public void updateRegisteredTemplateDetails_UpdatesTemplateSuccessfully() {
+ Long templateId = 1L;
+ Long zoneId = 2L;
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+ GuestOSVO guestOS = Mockito.mock(GuestOSVO.class);
+
+ when(templateDetails.getGuestOs()).thenReturn("Debian");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(vmTemplateDao.findById(templateId)).thenReturn(templateVO);
+ when(guestOSDao.findOneByDisplayName("Debian")).thenReturn(guestOS);
+ when(guestOS.getId()).thenReturn(10L);
+ when(vmTemplateDao.update(templateVO.getId(), templateVO)).thenReturn(true);
+ doNothing().when(systemVmTemplateRegistration).updateSystemVMEntries(templateId, Hypervisor.HypervisorType.KVM);
+ doNothing().when(systemVmTemplateRegistration).updateConfigurationParams(Hypervisor.HypervisorType.KVM,
+ "templateName", zoneId);
+
+ systemVmTemplateRegistration.updateRegisteredTemplateDetails(templateId, templateDetails, zoneId);
+
+ verify(templateVO).setTemplateType(Storage.TemplateType.SYSTEM);
+ verify(templateVO).setGuestOSId(10);
+ verify(vmTemplateDao).update(templateVO.getId(), templateVO);
+ verify(systemVmTemplateRegistration).updateSystemVMEntries(templateId, Hypervisor.HypervisorType.KVM);
+ verify(systemVmTemplateRegistration).updateConfigurationParams(Hypervisor.HypervisorType.KVM,
+ "templateName", zoneId);
+ }
+
+ @Test
+ public void updateRegisteredTemplateDetails_ThrowsExceptionWhenUpdateFails() {
+ Long templateId = 1L;
+ Long zoneId = 2L;
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+
+ when(templateDetails.getGuestOs()).thenReturn("Debian");
+ when(vmTemplateDao.findById(templateId)).thenReturn(templateVO);
+ when(vmTemplateDao.update(templateVO.getId(), templateVO)).thenReturn(false);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class,
+ () -> systemVmTemplateRegistration.updateRegisteredTemplateDetails(templateId, templateDetails, zoneId));
+
+ assertTrue(exception.getMessage().contains("Exception while updating template with id"));
+ verify(systemVmTemplateRegistration, never()).updateSystemVMEntries(anyLong(), any());
+ verify(systemVmTemplateRegistration, never()).updateConfigurationParams(any(), any(), any());
+ }
+
+ @Test
+ public void updateRegisteredTemplateDetails_SkipsGuestOSUpdateWhenNotFound() {
+ Long templateId = 1L;
+ Long zoneId = 2L;
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+
+ when(templateDetails.getGuestOs()).thenReturn("NonExistentOS");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(vmTemplateDao.findById(templateId)).thenReturn(templateVO);
+ when(guestOSDao.findOneByDisplayName("NonExistentOS")).thenReturn(null);
+ when(vmTemplateDao.update(templateVO.getId(), templateVO)).thenReturn(true);
+ doNothing().when(systemVmTemplateRegistration).updateSystemVMEntries(templateId, Hypervisor.HypervisorType.KVM);
+ doNothing().when(systemVmTemplateRegistration).updateConfigurationParams(Hypervisor.HypervisorType.KVM,
+ "templateName", zoneId);
+
+ systemVmTemplateRegistration.updateRegisteredTemplateDetails(templateId, templateDetails, zoneId);
+
+ verify(templateVO, never()).setGuestOSId(anyInt());
+ verify(vmTemplateDao).update(templateVO.getId(), templateVO);
+ verify(systemVmTemplateRegistration).updateSystemVMEntries(templateId, Hypervisor.HypervisorType.KVM);
+ verify(systemVmTemplateRegistration).updateConfigurationParams(Hypervisor.HypervisorType.KVM,
+ "templateName", zoneId);
+ }
+
+ @Test
+ public void registerTemplatesForZone_SuccessfullyRegistersNewTemplate() {
+ long zoneId = 1L;
+ String storeMountPath = "/mnt/nfs";
+ Pair<String, Long> storeUrlAndId = new Pair<>("nfs://dummy", 100L);
+ String nfsVersion = "nfs3";
+ List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorArchList = new ArrayList<>();
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ CPU.CPUArch arch = CPU.CPUArch.amd64;
+ hypervisorArchList.add(new Pair<>(hypervisorType, arch));
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getHypervisorType()).thenReturn(hypervisorType);
+ when(templateDetails.getArch()).thenReturn(arch);
+ String name = "TestTemplate";
+ String url = "http://example.com/template";
+ when(templateDetails.getName()).thenReturn(name);
+ when(templateDetails.getUrl()).thenReturn(url);
+ doReturn(storeUrlAndId).when(systemVmTemplateRegistration).getNfsStoreInZone(zoneId);
+ doReturn(nfsVersion).when(systemVmTemplateRegistration).getNfsVersion(storeUrlAndId.second());
+ doReturn(null).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ name, hypervisorType, arch, url);
+ doNothing().when(systemVmTemplateRegistration).registerNewTemplate(
+ name, templateDetails, zoneId, storeUrlAndId.second(), storeMountPath);
+ doReturn(hypervisorArchList).when(clusterDao).listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
+ try (MockedStatic<SystemVmTemplateRegistration> mockedStatic =
+ Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ mockedStatic.when(() -> SystemVmTemplateRegistration.getMetadataTemplateDetails(
+ hypervisorType, arch)).thenReturn(templateDetails);
+
+ systemVmTemplateRegistration.registerTemplatesForZone(zoneId, storeMountPath);
+
+ mockedStatic.verify(() -> SystemVmTemplateRegistration.mountStore(
+ eq(storeUrlAndId.first()), eq(storeMountPath), eq(nfsVersion)), times(1));
+ verify(systemVmTemplateRegistration).registerNewTemplate(
+ templateDetails.getName(), templateDetails, zoneId, storeUrlAndId.second(), storeMountPath);
+ }
+ }
+
+ @Test
+ public void registerTemplatesForZone_SkipsWhenTemplateDetailsNotFound() {
+ long zoneId = 1L;
+ String storeMountPath = "/mnt/nfs";
+ Pair<String, Long> storeUrlAndId = new Pair<>("nfs://dummy", 100L);
+ String nfsVersion = "nfs3";
+ List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorArchList = new ArrayList<>();
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ CPU.CPUArch arch = CPU.CPUArch.amd64;
+ hypervisorArchList.add(new Pair<>(hypervisorType, arch));
+ doReturn(storeUrlAndId).when(systemVmTemplateRegistration).getNfsStoreInZone(zoneId);
+ doReturn(nfsVersion).when(systemVmTemplateRegistration).getNfsVersion(storeUrlAndId.second());
+ doReturn(hypervisorArchList).when(clusterDao).listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
+
+ try (MockedStatic<SystemVmTemplateRegistration> mockedStatic =
+ Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ mockedStatic.when(() -> SystemVmTemplateRegistration.getMetadataTemplateDetails(
+ hypervisorType, arch)).thenReturn(null);
+
+ systemVmTemplateRegistration.registerTemplatesForZone(zoneId, storeMountPath);
+
+ mockedStatic.verify(() -> SystemVmTemplateRegistration.mountStore(
+ eq(storeUrlAndId.first()), eq(storeMountPath), eq(nfsVersion)), times(1));
+ verify(systemVmTemplateRegistration, never()).registerNewTemplate(any(), any(), anyLong(), anyLong(), any());
+ }
+ }
+
+ @Test
+ public void registerTemplatesForZone_AddsExistingTemplateToStore() {
+ long zoneId = 1L;
+ String storeMountPath = "/mnt/nfs";
+ Pair<String, Long> storeUrlAndId = new Pair<>("nfs://dummy", 100L);
+ String nfsVersion = "nfs3";
+ List<Pair<Hypervisor.HypervisorType, CPU.CPUArch>> hypervisorArchList = new ArrayList<>();
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ CPU.CPUArch arch = CPU.CPUArch.amd64;
+ hypervisorArchList.add(new Pair<>(hypervisorType, arch));
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getHypervisorType()).thenReturn(hypervisorType);
+ when(templateDetails.getArch()).thenReturn(arch);
+ String name = "TestTemplate";
+ String url = "http://example.com/template";
+ when(templateDetails.getName()).thenReturn(name);
+ when(templateDetails.getUrl()).thenReturn(url);
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+ long templateId = 100L;
+ when(templateVO.getId()).thenReturn(templateId);
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+ String installPath = "/template/install/path";
+ when(templateDataStoreVO.getInstallPath()).thenReturn(installPath);
+
+ doReturn(storeUrlAndId).when(systemVmTemplateRegistration).getNfsStoreInZone(zoneId);
+ doReturn(nfsVersion).when(systemVmTemplateRegistration).getNfsVersion(storeUrlAndId.second());
+ doReturn(hypervisorArchList).when(clusterDao).listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
+ doReturn(templateVO).when(systemVmTemplateRegistration).getRegisteredTemplate(name, hypervisorType, arch, url);
+ doReturn(templateDataStoreVO).when(templateDataStoreDao)
+ .findByStoreTemplate(storeUrlAndId.second(), templateId);
+ doReturn(false).when(systemVmTemplateRegistration).validateIfSeeded(
+ templateDataStoreVO, storeUrlAndId.first(), installPath, nfsVersion);
+ doNothing().when(systemVmTemplateRegistration).addExistingTemplateToStore(
+ templateVO, templateDetails, templateDataStoreVO, zoneId, storeUrlAndId.second(), storeMountPath);
+ doNothing().when(systemVmTemplateRegistration).updateRegisteredTemplateDetails(
+ templateId, templateDetails, zoneId);
+
+ try (MockedStatic<SystemVmTemplateRegistration> mockedStatic =
+ Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ mockedStatic.when(() -> SystemVmTemplateRegistration.getMetadataTemplateDetails(
+ hypervisorType, arch)).thenReturn(templateDetails);
+
+ systemVmTemplateRegistration.registerTemplatesForZone(zoneId, storeMountPath);
+
+ verify(systemVmTemplateRegistration).addExistingTemplateToStore(
+ templateVO, templateDetails, templateDataStoreVO, zoneId, storeUrlAndId.second(), storeMountPath);
+ verify(systemVmTemplateRegistration).updateRegisteredTemplateDetails(templateId, templateDetails, zoneId);
+ }
+ }
+
+ @Test
+ public void performTemplateRegistrationOperations_CreatesNewTemplateWhenNotExists() {
+ String name = "TestTemplate";
+ String url = "http://example.com/template";
+ String checksum = "abc123";
+ Storage.ImageFormat format = Storage.ImageFormat.QCOW2;
+ long guestOsId = 1L;
+ Long storeId = 100L;
+ Long templateId = null;
+ String filePath = "/mnt/nfs";
+ TemplateDataStoreVO templateDataStoreVO = null;
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ doReturn(new VMTemplateVO()).when(vmTemplateDao).persist(any());
+ doNothing().when(systemVmTemplateRegistration).createCrossZonesTemplateZoneRefEntries(anyLong());
+ doNothing().when(systemVmTemplateRegistration).createTemplateStoreRefEntry(any());
+ doNothing().when(systemVmTemplateRegistration).setupTemplateOnStore(anyString(), any(), anyString());
+ doNothing().when(systemVmTemplateRegistration).readTemplateProperties(anyString(), any());
+ doNothing().when(systemVmTemplateRegistration).updateTemplateDetails(any());
+
+ Long result = systemVmTemplateRegistration.performTemplateRegistrationOperations(name, templateDetails, url, checksum, format, guestOsId, storeId, templateId, filePath, templateDataStoreVO);
+
+ assertNotNull(result);
+ verify(vmTemplateDao).persist(any());
+ verify(systemVmTemplateRegistration).createCrossZonesTemplateZoneRefEntries(anyLong());
+ verify(systemVmTemplateRegistration).createTemplateStoreRefEntry(any());
+ verify(systemVmTemplateRegistration).setupTemplateOnStore(anyString(), any(), anyString());
+ verify(systemVmTemplateRegistration).updateTemplateDetails(any());
+ }
+
+ @Test
+ public void performTemplateRegistrationOperations_UpdatesExistingTemplate() {
+ String name = "TestTemplate";
+ String url = "http://example.com/template";
+ String checksum = "abc123";
+ Storage.ImageFormat format = Storage.ImageFormat.QCOW2;
+ long guestOsId = 1L;
+ Long storeId = 100L;
+ Long templateId = 1L;
+ String filePath = "/mnt/nfs";
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ doNothing().when(systemVmTemplateRegistration).createCrossZonesTemplateZoneRefEntries(anyLong());
+ doNothing().when(systemVmTemplateRegistration).setupTemplateOnStore(anyString(), any(), anyString());
+ doNothing().when(systemVmTemplateRegistration).readTemplateProperties(anyString(), any());
+ doNothing().when(systemVmTemplateRegistration).updateTemplateDetails(any());
+
+ Long result = systemVmTemplateRegistration.performTemplateRegistrationOperations(name, templateDetails, url, checksum, format, guestOsId, storeId, templateId, filePath, templateDataStoreVO);
+
+ assertNotNull(result);
+ assertEquals(templateId, result);
+ verify(vmTemplateDao, never()).persist(any());
+ verify(systemVmTemplateRegistration).createCrossZonesTemplateZoneRefEntries(anyLong());
+ verify(systemVmTemplateRegistration, never()).createTemplateStoreRefEntry(any());
+ verify(systemVmTemplateRegistration).setupTemplateOnStore(anyString(), any(), anyString());
+ verify(systemVmTemplateRegistration).updateTemplateDetails(any());
+ }
+
+ @Test
+ public void performTemplateRegistrationOperations_ThrowsExceptionWhenTemplateCreationFails() {
+ String name = "TestTemplate";
+ String url = "http://example.com/template";
+ String checksum = "abc123";
+ Storage.ImageFormat format = Storage.ImageFormat.QCOW2;
+ long guestOsId = 1L;
+ Long storeId = 100L;
+ Long templateId = null;
+ String filePath = "/mnt/nfs";
+ TemplateDataStoreVO templateDataStoreVO = null;
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ doReturn(null).when(vmTemplateDao).persist(any());
+
+ assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.performTemplateRegistrationOperations(name, templateDetails, url, checksum, format, guestOsId, storeId, templateId, filePath, templateDataStoreVO);
+ });
+
+ verify(vmTemplateDao).persist(any());
+ verify(systemVmTemplateRegistration, never()).createCrossZonesTemplateZoneRefEntries(anyLong());
+ verify(systemVmTemplateRegistration, never()).createTemplateStoreRefEntry(any());
+ verify(systemVmTemplateRegistration, never()).setupTemplateOnStore(anyString(), any(), anyString());
+ verify(systemVmTemplateRegistration, never()).updateTemplateDetails(any());
+ }
+
+ @Test
+ public void setupTemplateOnStore_ThrowsExceptionWhenScriptNotFound() {
+ String templateName = "templateName";
+ String destTempFolder = "/tmp/folder";
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+
+ try (MockedStatic<Script> scriptMock = Mockito.mockStatic(Script.class)) {
+ scriptMock.when(() -> Script.findScript(SystemVmTemplateRegistration.STORAGE_SCRIPTS_DIR,
+ "setup-sysvm-tmplt")).thenReturn(null);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.setupTemplateOnStore(templateName, templateDetails, destTempFolder);
+ });
+
+ assertTrue(exception.getMessage().contains("Unable to find the setup-sysvm-tmplt script"));
+ }
+ }
+
+ @Test
+ public void updateTemplateEntriesOnFailure_RemovesTemplateAndDataStoreEntry() {
+ long templateId = 1L;
+ VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+
+ when(vmTemplateDao.createForUpdate(templateId)).thenReturn(template);
+ when(template.getId()).thenReturn(templateId);
+ when(templateDataStoreDao.findByTemplate(templateId, DataStoreRole.Image)).thenReturn(templateDataStoreVO);
+
+ systemVmTemplateRegistration.updateTemplateEntriesOnFailure(templateId);
+
+ verify(vmTemplateDao).update(templateId, template);
+ verify(vmTemplateDao).remove(templateId);
+ verify(templateDataStoreDao).remove(templateDataStoreVO.getId());
+ }
+
+ @Test
+ public void updateTemplateEntriesOnFailure_SkipsDataStoreRemovalWhenNotFound() {
+ long templateId = 1L;
+ VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
+
+ when(vmTemplateDao.createForUpdate(templateId)).thenReturn(template);
+ when(template.getId()).thenReturn(templateId);
+ when(templateDataStoreDao.findByTemplate(templateId, DataStoreRole.Image)).thenReturn(null);
+
+ systemVmTemplateRegistration.updateTemplateEntriesOnFailure(templateId);
+
+ verify(vmTemplateDao).update(templateId, template);
+ verify(vmTemplateDao).remove(templateId);
+ verify(templateDataStoreDao, never()).remove(anyLong());
+ }
+
+ @Test
+ public void updateConfigurationParams_UpdatesConfigurationSuccessfully() {
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ String templateName = "templateName";
+ long zoneId = 1L;
+ String configName = SystemVmTemplateRegistration.ROUTER_TEMPLATE_CONFIGURATION_NAMES.get(hypervisorType);
+
+ when(configurationDao.update(configName, templateName)).thenReturn(true);
+ when(configurationDao.update(SystemVmTemplateRegistration.MINIMUM_SYSTEM_VM_VERSION_KEY,
+ systemVmTemplateRegistration.getSystemVmTemplateVersion())).thenReturn(true);
+
+ systemVmTemplateRegistration.updateConfigurationParams(hypervisorType, templateName, zoneId);
+
+ verify(configurationDao).update(configName, templateName);
+ verify(dataCenterDetailsDao).removeDetail(zoneId, configName);
+ verify(configurationDao).update(SystemVmTemplateRegistration.MINIMUM_SYSTEM_VM_VERSION_KEY,
+ systemVmTemplateRegistration.getSystemVmTemplateVersion());
+ verify(dataCenterDetailsDao).removeDetail(zoneId, SystemVmTemplateRegistration.MINIMUM_SYSTEM_VM_VERSION_KEY);
+ }
+
+ @Test
+ public void updateConfigurationParams_ThrowsExceptionWhenConfigUpdateFails() {
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ String templateName = "templateName";
+ Long zoneId = 1L;
+ String configName = SystemVmTemplateRegistration.ROUTER_TEMPLATE_CONFIGURATION_NAMES.get(hypervisorType);
+
+ when(configurationDao.update(configName, templateName)).thenReturn(false);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.updateConfigurationParams(hypervisorType, templateName, zoneId);
+ });
+
+ assertTrue(exception.getMessage().contains("Failed to update configuration parameter"));
+ verify(configurationDao).update(configName, templateName);
+ verify(dataCenterDetailsDao, never()).removeDetail(anyLong(), anyString());
+ }
+
+ @Test
+ public void updateConfigurationParams_SkipsZoneDetailsRemovalWhenZoneIdIsNull() {
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.VMware;
+ String templateName = "templateName";
+ Long zoneId = null;
+ String configName = SystemVmTemplateRegistration.ROUTER_TEMPLATE_CONFIGURATION_NAMES.get(hypervisorType);
+
+ when(configurationDao.update(configName, templateName)).thenReturn(true);
+ when(configurationDao.update(SystemVmTemplateRegistration.MINIMUM_SYSTEM_VM_VERSION_KEY,
+ systemVmTemplateRegistration.getSystemVmTemplateVersion())).thenReturn(true);
+
+ systemVmTemplateRegistration.updateConfigurationParams(hypervisorType, templateName, zoneId);
+
+ verify(configurationDao).update(configName, templateName);
+ verify(dataCenterDetailsDao, never()).removeDetail(anyLong(), eq(configName));
+ verify(configurationDao).update(SystemVmTemplateRegistration.MINIMUM_SYSTEM_VM_VERSION_KEY,
+ systemVmTemplateRegistration.getSystemVmTemplateVersion());
+ verify(dataCenterDetailsDao, never()).removeDetail(anyLong(),
+ eq(SystemVmTemplateRegistration.MINIMUM_SYSTEM_VM_VERSION_KEY));
+ }
+
+ @Test
+ public void createOrUpdateTemplateZoneEntry_CreatesNewEntryWhenNotExists() {
+ long zoneId = 1L;
+ long templateId = 100L;
+ VMTemplateZoneVO newTemplateZoneVO = Mockito.mock(VMTemplateZoneVO.class);
+
+ when(vmTemplateZoneDao.findByZoneTemplate(zoneId, templateId)).thenReturn(null);
+ when(vmTemplateZoneDao.persist(any(VMTemplateZoneVO.class))).thenReturn(newTemplateZoneVO);
+
+ VMTemplateZoneVO result = systemVmTemplateRegistration.createOrUpdateTemplateZoneEntry(zoneId, templateId);
+
+ assertNotNull(result);
+ verify(vmTemplateZoneDao).persist(any(VMTemplateZoneVO.class));
+ }
+
+ @Test
+ public void createOrUpdateTemplateZoneEntry_UpdatesExistingEntry() {
+ long zoneId = 1L;
+ long templateId = 100L;
+ VMTemplateZoneVO existingTemplateZoneVO = Mockito.mock(VMTemplateZoneVO.class);
+
+ when(vmTemplateZoneDao.findByZoneTemplate(zoneId, templateId)).thenReturn(existingTemplateZoneVO);
+ when(vmTemplateZoneDao.update(existingTemplateZoneVO.getId(), existingTemplateZoneVO)).thenReturn(true);
+
+ VMTemplateZoneVO result = systemVmTemplateRegistration.createOrUpdateTemplateZoneEntry(zoneId, templateId);
+
+ assertNotNull(result);
+ verify(vmTemplateZoneDao).update(existingTemplateZoneVO.getId(), existingTemplateZoneVO);
+ }
+
+ @Test
+ public void createOrUpdateTemplateZoneEntry_ReturnsNullWhenUpdateFails() {
+ long zoneId = 1L;
+ long templateId = 100L;
+ VMTemplateZoneVO existingTemplateZoneVO = Mockito.mock(VMTemplateZoneVO.class);
+
+ when(vmTemplateZoneDao.findByZoneTemplate(zoneId, templateId)).thenReturn(existingTemplateZoneVO);
+ when(vmTemplateZoneDao.update(existingTemplateZoneVO.getId(), existingTemplateZoneVO)).thenReturn(false);
+
+ VMTemplateZoneVO result = systemVmTemplateRegistration.createOrUpdateTemplateZoneEntry(zoneId, templateId);
+
+ assertNull(result);
+ verify(vmTemplateZoneDao).update(existingTemplateZoneVO.getId(), existingTemplateZoneVO);
+ }
+
+ @Test
+ public void createCrossZonesTemplateZoneRefEntries_ThrowsExceptionWhenEntryCreationFails() {
+ long templateId = 100L;
+ DataCenterVO dataCenter = Mockito.mock(DataCenterVO.class);
+ List<DataCenterVO> dataCenters = List.of(dataCenter);
+
+ when(dataCenter.getId()).thenReturn(1L);
+ when(dataCenterDao.listAll()).thenReturn(dataCenters);
+ when(systemVmTemplateRegistration.createOrUpdateTemplateZoneEntry(1L, templateId)).thenReturn(null);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.createCrossZonesTemplateZoneRefEntries(templateId);
+ });
+
+ assertTrue(exception.getMessage().contains("Failed to create template-zone record"));
+ }
+
+ @Test
+ public void createTemplateStoreRefEntry_CreatesEntrySuccessfully() {
+ SystemVmTemplateRegistration.SystemVMTemplateDetails details = Mockito.mock(SystemVmTemplateRegistration.SystemVMTemplateDetails.class);
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+
+ when(details.getStoreId()).thenReturn(1L);
+ when(details.getId()).thenReturn(100L);
+ when(templateDataStoreDao.persist(any(TemplateDataStoreVO.class))).thenReturn(templateDataStoreVO);
+
+ systemVmTemplateRegistration.createTemplateStoreRefEntry(details);
+
+ verify(templateDataStoreDao).persist(any(TemplateDataStoreVO.class));
+ }
+
+ @Test
+ public void createTemplateStoreRefEntry_ThrowsExceptionWhenCreationFails() {
+ SystemVmTemplateRegistration.SystemVMTemplateDetails details = Mockito.mock(SystemVmTemplateRegistration.SystemVMTemplateDetails.class);
+
+ when(details.getStoreId()).thenReturn(1L);
+ when(details.getId()).thenReturn(100L);
+ when(templateDataStoreDao.persist(any(TemplateDataStoreVO.class))).thenReturn(null);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.createTemplateStoreRefEntry(details);
+ });
+
+ assertTrue(exception.getMessage().contains("Failed to create template-store record"));
+ }
+
+ @Test
+ public void updateTemplateDetails_UpdatesTemplateAndStoreSuccessfully() {
+ SystemVmTemplateRegistration.SystemVMTemplateDetails details =
+ Mockito.mock(SystemVmTemplateRegistration.SystemVMTemplateDetails.class);
+ VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+
+ when(details.getId()).thenReturn(1L);
+ when(details.getStoreId()).thenReturn(2L);
+ when(details.getSize()).thenReturn(1024L);
+ when(details.getPhysicalSize()).thenReturn(2048L);
+ when(template.getId()).thenReturn(1L);
+ when(vmTemplateDao.findById(1L)).thenReturn(template);
+ when(templateDataStoreDao.findByStoreTemplate(2L, 1L)).thenReturn(templateDataStoreVO);
+ when(templateDataStoreDao.update(anyLong(), any(TemplateDataStoreVO.class))).thenReturn(true);
+
+ systemVmTemplateRegistration.updateTemplateDetails(details);
+
+ verify(template).setSize(1024L);
+ verify(template).setState(VirtualMachineTemplate.State.Active);
+ verify(vmTemplateDao).update(template.getId(), template);
+ verify(templateDataStoreVO).setSize(1024L);
+ verify(templateDataStoreVO).setPhysicalSize(2048L);
+ verify(templateDataStoreVO).setDownloadPercent(100);
+ verify(templateDataStoreVO).setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
+ verify(templateDataStoreVO).setLastUpdated(details.getUpdated());
+ verify(templateDataStoreVO).setState(ObjectInDataStoreStateMachine.State.Ready);
+ verify(templateDataStoreDao).update(templateDataStoreVO.getId(), templateDataStoreVO);
+ }
+
+ @Test
+ public void updateTemplateDetails_ThrowsExceptionWhenStoreUpdateFails() {
+ SystemVmTemplateRegistration.SystemVMTemplateDetails details =
+ Mockito.mock(SystemVmTemplateRegistration.SystemVMTemplateDetails.class);
+ VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+
+ when(details.getId()).thenReturn(1L);
+ when(details.getStoreId()).thenReturn(2L);
+ when(details.getSize()).thenReturn(1024L);
+ when(details.getPhysicalSize()).thenReturn(2048L);
+ when(template.getId()).thenReturn(1L);
+ when(vmTemplateDao.findById(1L)).thenReturn(template);
+ when(templateDataStoreDao.findByStoreTemplate(2L, 1L)).thenReturn(templateDataStoreVO);
+ when(templateDataStoreDao.update(anyLong(), any(TemplateDataStoreVO.class))).thenReturn(false);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.updateTemplateDetails(details);
+ });
+
+ assertTrue(exception.getMessage().contains("Failed to update template-store record"));
+ verify(templateDataStoreDao).update(templateDataStoreVO.getId(), templateDataStoreVO);
+ }
+
+ @Test
+ public void getNfsStoreInZone_ReturnsStoreDetailsWhenStoreExists() {
+ long zoneId = 1L;
+ ImageStoreVO storeVO = Mockito.mock(ImageStoreVO.class);
+
+ when(imageStoreDao.findOneByZoneAndProtocol(zoneId, "nfs")).thenReturn(storeVO);
+ when(storeVO.getUrl()).thenReturn("nfs://example.com/store");
+ when(storeVO.getId()).thenReturn(100L);
+
+ Pair<String, Long> result = systemVmTemplateRegistration.getNfsStoreInZone(zoneId);
+
+ assertNotNull(result);
+ assertEquals("nfs://example.com/store", result.first());
+ assertEquals(100L, result.second().longValue());
+ }
+
+ @Test
+ public void getNfsStoreInZone_ThrowsExceptionWhenStoreNotFound() {
+ long zoneId = 1L;
+
+ when(imageStoreDao.findOneByZoneAndProtocol(zoneId, "nfs")).thenReturn(null);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.getNfsStoreInZone(zoneId);
+ });
+
+ assertTrue(exception.getMessage().contains("Failed to fetch NFS store in zone"));
+ }
+
+ @Test
+ public void readTemplateProperties_SetsTemplateSizesCorrectly() {
+ String path = "/template/path";
+ SystemVmTemplateRegistration.SystemVMTemplateDetails details = Mockito.mock(SystemVmTemplateRegistration.SystemVMTemplateDetails.class);
+ Pair<Long, Long> templateSizes = new Pair<>(1024L, 2048L);
+
+ try (MockedStatic<SystemVmTemplateRegistration> mockedStatic = Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ mockedStatic.when(() -> SystemVmTemplateRegistration.readTemplatePropertiesSizes(path)).thenReturn(templateSizes);
+
+ systemVmTemplateRegistration.readTemplateProperties(path, details);
+
+ verify(details).setSize(1024L);
+ verify(details).setPhysicalSize(2048L);
+ }
+ }
+
+ @Test
+ public void readTemplateProperties_ThrowsExceptionWhenPathIsInvalid() {
+ String path = "/invalid/path";
+ SystemVmTemplateRegistration.SystemVMTemplateDetails details = Mockito.mock(SystemVmTemplateRegistration.SystemVMTemplateDetails.class);
+
+ try (MockedStatic<SystemVmTemplateRegistration> mockedStatic = Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ mockedStatic.when(() -> SystemVmTemplateRegistration.readTemplatePropertiesSizes(path))
+ .thenThrow(new CloudRuntimeException("Invalid path"));
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.readTemplateProperties(path, details);
+ });
+
+ assertTrue(exception.getMessage().contains("Invalid path"));
+ }
+ }
+
+ @Test
+ public void getEligibleZoneIds_ReturnsUniqueZoneIds() {
+ ImageStoreVO store1 = Mockito.mock(ImageStoreVO.class);
+ ImageStoreVO store2 = Mockito.mock(ImageStoreVO.class);
+ ImageStoreVO store3 = Mockito.mock(ImageStoreVO.class);
+
+ when(store1.getDataCenterId()).thenReturn(1L);
+ when(store2.getDataCenterId()).thenReturn(2L);
+ when(store3.getDataCenterId()).thenReturn(1L);
+ when(imageStoreDao.findByProtocol("nfs")).thenReturn(List.of(store1, store2, store3));
+
+ List<Long> result = systemVmTemplateRegistration.getEligibleZoneIds();
+
+ assertNotNull(result);
+ assertEquals(2, result.size());
+ assertTrue(result.contains(1L));
+ assertTrue(result.contains(2L));
+ }
+
+ @Test
+ public void getEligibleZoneIds_ReturnsEmptyListWhenNoStoresExist() {
+ when(imageStoreDao.findByProtocol("nfs")).thenReturn(new ArrayList<>());
+
+ List<Long> result = systemVmTemplateRegistration.getEligibleZoneIds();
+
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void getNfsVersion_ReturnsStoreSpecificVersionWhenPresent() {
+ long storeId = 1L;
+ String configKey = "secstorage.nfs.version";
+ String expectedVersion = "nfs4";
+ Map<String, String> storeDetails = Map.of(configKey, expectedVersion);
+
+ when(imageStoreDetailsDao.getDetails(storeId)).thenReturn(storeDetails);
+
+ String result = systemVmTemplateRegistration.getNfsVersion(storeId);
+
+ assertNotNull(result);
+ assertEquals(expectedVersion, result);
+ }
+
+ @Test
+ public void getNfsVersion_ReturnsGlobalVersionWhenStoreSpecificVersionNotPresent() {
+ long storeId = 1L;
+ String expectedVersion = "nfs3";
+ ConfigurationVO globalConfig = Mockito.mock(ConfigurationVO.class);
+
+ when(imageStoreDetailsDao.getDetails(storeId)).thenReturn(null);
+ when(configurationDao.findByName(anyString())).thenReturn(globalConfig);
+ when(globalConfig.getValue()).thenReturn(expectedVersion);
+
+ String result = systemVmTemplateRegistration.getNfsVersion(storeId);
+
+ assertNotNull(result);
+ assertEquals(expectedVersion, result);
+ }
+
+ @Test
+ public void getNfsVersion_ReturnsNullWhenNoVersionConfigured() {
+ long storeId = 1L;
+
+ when(imageStoreDetailsDao.getDetails(storeId)).thenReturn(null);
+ when(configurationDao.findByName(anyString())).thenReturn(null);
+
+ String result = systemVmTemplateRegistration.getNfsVersion(storeId);
+
+ assertNull(result);
+ }
+
+ @Test
+ public void validateIfSeeded_ReturnsTrueWhenTemplateIsSeeded() throws Exception {
+ TemplateDataStoreVO templDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+ String url = "nfs://example.com/store";
+ Path local = Files.createTempDirectory("local");
+ Files.createDirectory(local.resolve("template"));
+ String path = "/template/path";
+ String nfsVersion = "nfs3";
+ Path secondary = Files.createTempDirectory("secondary");
+ Files.createDirectory(secondary.resolve("template"));
+ Files.createFile(secondary.resolve("template").resolve("template.properties"));
+ String tempDir = secondary.toString();
+ Pair<Long, Long> templateSizes = new Pair<>(1024L, 2048L);
+
+ when(templDataStoreVO.getTemplateId()).thenReturn(1L);
+ when(templDataStoreVO.getDataStoreId()).thenReturn(2L);
+ doNothing().when(systemVmTemplateRegistration).updateSeededTemplateDetails(anyLong(), anyLong(), anyLong(), anyLong());
+ try (MockedStatic<Files> filesMock = Mockito.mockStatic(Files.class);
+ MockedStatic<SystemVmTemplateRegistration> mockedStatic = Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ filesMock.when(() -> Files.createTempDirectory(SystemVmTemplateRegistration.TEMPORARY_SECONDARY_STORE)).thenReturn(Path.of(tempDir));
+ mockedStatic.when(() -> SystemVmTemplateRegistration.readTemplatePropertiesSizes(anyString())).thenReturn(templateSizes);
+
+ boolean result = systemVmTemplateRegistration.validateIfSeeded(templDataStoreVO, url, path, nfsVersion);
+
+ assertTrue(result);
+ verify(systemVmTemplateRegistration).updateSeededTemplateDetails(1L, 2L, 1024L, 2048L);
+ }
+ }
+
+ @Test
+ public void validateIfSeeded_ReturnsFalseWhenTemplateIsNotSeeded() throws Exception {
+ TemplateDataStoreVO templDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+ String url = "nfs://example.com/store";
+ String path = "/template/path";
+ String nfsVersion = "nfs3";
+ String tempDir = "/tmp/secondary";
+
+ try (MockedStatic<Files> filesMock = Mockito.mockStatic(Files.class)) {
+ filesMock.when(() -> Files.createTempDirectory(SystemVmTemplateRegistration.TEMPORARY_SECONDARY_STORE)).thenReturn(Path.of(tempDir));
+
+ boolean result = systemVmTemplateRegistration.validateIfSeeded(templDataStoreVO, url, path, nfsVersion);
+
+ assertFalse(result);
+ verify(systemVmTemplateRegistration, never()).updateSeededTemplateDetails(anyLong(), anyLong(), anyLong(), anyLong());
+ }
+ }
+
+ @Test
+ public void validateIfSeeded_ThrowsExceptionWhenTempDirectoryCreationFails() {
+ TemplateDataStoreVO templDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+ String url = "nfs://example.com/store";
+ String path = "/template/path";
+ String nfsVersion = "nfs3";
+
+ try (MockedStatic<Files> filesMock = Mockito.mockStatic(Files.class)) {
+ filesMock.when(() -> Files.createTempDirectory(SystemVmTemplateRegistration.TEMPORARY_SECONDARY_STORE)).thenThrow(IOException.class);
+
+ assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.validateIfSeeded(templDataStoreVO, url, path, nfsVersion);
+ });
+ }
+ }
+
+ @Test
+ public void validateIfSeeded_ThrowsExceptionWhenUnmountFails() throws Exception {
+ TemplateDataStoreVO templDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+ String url = "nfs://example.com/store";
+ String path = "/template/path";
+ String nfsVersion = "nfs3";
+ String tempDir = "/tmp/secondary";
+
+ try (MockedStatic<Files> filesMock = Mockito.mockStatic(Files.class);
+ MockedStatic<SystemVmTemplateRegistration> mockedStatic = Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ filesMock.when(() -> Files.createTempDirectory(SystemVmTemplateRegistration.TEMPORARY_SECONDARY_STORE)).thenReturn(Path.of(tempDir));
+ mockedStatic.when(() -> SystemVmTemplateRegistration.unmountStore(anyString())).thenThrow(CloudRuntimeException.class);
+
+ assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.validateIfSeeded(templDataStoreVO, url, path, nfsVersion);
+ });
+ }
+ }
+
+ @Test
+ public void registerNewTemplate_RegistersTemplateSuccessfully() {
+ String name = "templateName";
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getUrl()).thenReturn("a");
+ when(templateDetails.getChecksum()).thenReturn("b");
+ long zoneId = 1L;
+ Long storeId = 2L;
+ String filePath = "/tmp/store";
+ Long templateId = 100L;
+ Hypervisor.HypervisorType hypervisor = Hypervisor.HypervisorType.KVM;
+
+ when(templateDetails.getHypervisorType()).thenReturn(hypervisor);
+ doReturn(templateId).when(systemVmTemplateRegistration)
+ .performTemplateRegistrationOperations(
+ name, templateDetails, "a", "b",
+ SystemVmTemplateRegistration.HYPERVISOR_IMAGE_FORMAT_MAP.get(hypervisor),
+ SystemVmTemplateRegistration.hypervisorGuestOsMap.get(hypervisor),
+ storeId, null, filePath, null);
+ doNothing().when(systemVmTemplateRegistration).updateConfigurationParams(hypervisor, name, zoneId);
+ doNothing().when(systemVmTemplateRegistration).updateSystemVMEntries(templateId, hypervisor);
+
+ systemVmTemplateRegistration.registerNewTemplate(name, templateDetails, zoneId, storeId, filePath);
+
+ verify(systemVmTemplateRegistration).performTemplateRegistrationOperations(
+ name, templateDetails, templateDetails.getUrl(), templateDetails.getChecksum(),
+ SystemVmTemplateRegistration.HYPERVISOR_IMAGE_FORMAT_MAP.get(hypervisor),
+ SystemVmTemplateRegistration.hypervisorGuestOsMap.get(hypervisor),
+ storeId, null, filePath, null);
+ verify(systemVmTemplateRegistration).updateConfigurationParams(hypervisor, name, zoneId);
+ verify(systemVmTemplateRegistration).updateSystemVMEntries(templateId, hypervisor);
+ }
+
+ @Test
+ public void registerNewTemplate_ThrowsExceptionWhenRegistrationFails() {
+ String name = "templateName";
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getUrl()).thenReturn("a");
+ when(templateDetails.getChecksum()).thenReturn("b");
+ long zoneId = 1L;
+ Long storeId = 2L;
+ String filePath = "/tmp/store";
+ Hypervisor.HypervisorType hypervisor = Hypervisor.HypervisorType.KVM;
+
+ when(templateDetails.getHypervisorType()).thenReturn(hypervisor);
+ doThrow(new CloudRuntimeException("Registration failed")).when(systemVmTemplateRegistration)
+ .performTemplateRegistrationOperations(
+ name, templateDetails, "a", "b",
+ SystemVmTemplateRegistration.HYPERVISOR_IMAGE_FORMAT_MAP.get(hypervisor),
+ SystemVmTemplateRegistration.hypervisorGuestOsMap.get(hypervisor),
+ storeId, null, filePath, null);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.registerNewTemplate(name, templateDetails, zoneId, storeId, filePath);
+ });
+
+ assertTrue(exception.getMessage().contains("Failed to register Template for"));
+ verify(systemVmTemplateRegistration).performTemplateRegistrationOperations(
+ name, templateDetails, templateDetails.getUrl(), templateDetails.getChecksum(),
+ SystemVmTemplateRegistration.HYPERVISOR_IMAGE_FORMAT_MAP.get(hypervisor),
+ SystemVmTemplateRegistration.hypervisorGuestOsMap.get(hypervisor),
+ storeId, null, filePath, null);
+ verify(systemVmTemplateRegistration, never()).updateConfigurationParams(any(), any(), anyLong());
+ verify(systemVmTemplateRegistration, never()).updateSystemVMEntries(anyLong(), any());
+ }
+
+ @Test
+ public void registerNewTemplate_CleansUpOnFailure() {
+ String name = "templateName";
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getUrl()).thenReturn("a");
+ when(templateDetails.getChecksum()).thenReturn("b");
+ long zoneId = 1L;
+ Long storeId = 2L;
+ String filePath = "/tmp/store";
+ Long templateId = 100L;
+ Hypervisor.HypervisorType hypervisor = Hypervisor.HypervisorType.KVM;
+
+ when(templateDetails.getHypervisorType()).thenReturn(hypervisor);
+ doReturn(templateId).when(systemVmTemplateRegistration)
+ .performTemplateRegistrationOperations(
+ name, templateDetails, "a", "b",
+ SystemVmTemplateRegistration.HYPERVISOR_IMAGE_FORMAT_MAP.get(hypervisor),
+ SystemVmTemplateRegistration.hypervisorGuestOsMap.get(hypervisor),
+ storeId, null, filePath, null);
+ doThrow(new CloudRuntimeException("Update failed")).when(systemVmTemplateRegistration)
+ .updateConfigurationParams(hypervisor, name, zoneId);
+ doNothing().when(systemVmTemplateRegistration).updateTemplateEntriesOnFailure(templateId);
+
+ try (MockedStatic<SystemVmTemplateRegistration> mockedStatic =
+ Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.registerNewTemplate(name, templateDetails, zoneId, storeId, filePath);
+ });
+
+ assertTrue(exception.getMessage().contains("Failed to register Template for"));
+ verify(systemVmTemplateRegistration).updateTemplateEntriesOnFailure(templateId);
+ mockedStatic.verify(() -> SystemVmTemplateRegistration.cleanupStore(templateId, filePath));
+ }
+ }
+
+ @Test
+ public void addExistingTemplateToStore_AddsTemplateSuccessfully() {
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+ when(templateVO.getId()).thenReturn(1L);
+ when(templateVO.getName()).thenReturn("templateName");
+ when(templateVO.getUrl()).thenReturn("http://example.com/template");
+ when(templateVO.getChecksum()).thenReturn("abc123");
+ when(templateVO.getFormat()).thenReturn(Storage.ImageFormat.QCOW2);
+ when(templateVO.getGuestOSId()).thenReturn(1L);
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+ long zoneId = 1L;
+ Long storeId = 2L;
+ String filePath = "/tmp/store";
+
+ doReturn(1L).when(systemVmTemplateRegistration)
+ .performTemplateRegistrationOperations("templateName", templateDetails,
+ "http://example.com/template", "abc123", Storage.ImageFormat.QCOW2,
+ 1L, storeId, 1L, filePath, templateDataStoreVO);
+
+ systemVmTemplateRegistration.addExistingTemplateToStore(templateVO, templateDetails, templateDataStoreVO, zoneId, storeId, filePath);
+
+ verify(systemVmTemplateRegistration).performTemplateRegistrationOperations(
+ templateVO.getName(), templateDetails, templateVO.getUrl(), templateVO.getChecksum(),
+ templateVO.getFormat(), templateVO.getGuestOSId(), storeId, templateVO.getId(), filePath, templateDataStoreVO);
+ }
+
+ @Test
+ public void addExistingTemplateToStore_CleansUpOnFailure() {
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+ when(templateVO.getId()).thenReturn(1L);
+ when(templateVO.getName()).thenReturn("templateName");
+ when(templateVO.getUrl()).thenReturn("http://example.com/template");
+ when(templateVO.getChecksum()).thenReturn("abc123");
+ when(templateVO.getFormat()).thenReturn(Storage.ImageFormat.QCOW2);
+ when(templateVO.getGuestOSId()).thenReturn(1L);
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+ long zoneId = 1L;
+ Long storeId = 2L;
+ String filePath = "/tmp/store";
+
+ doThrow(new CloudRuntimeException("Operation failed")).when(systemVmTemplateRegistration)
+ .performTemplateRegistrationOperations("templateName", templateDetails,
+ "http://example.com/template", "abc123", Storage.ImageFormat.QCOW2,
+ 1L, storeId, 1L, filePath, templateDataStoreVO);
+
+ try (MockedStatic<SystemVmTemplateRegistration> mockedStatic =
+ Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.addExistingTemplateToStore(templateVO, templateDetails, templateDataStoreVO, zoneId, storeId, filePath);
+ });
+
+ assertTrue(exception.getMessage().contains("Failed to add"));
+ mockedStatic.verify(() -> SystemVmTemplateRegistration.cleanupStore(templateVO.getId(), filePath));
+ }
+ }
+
+ @Test
+ public void updateSeededTemplateDetails_UpdatesTemplateAndStoreSuccessfully() {
+ long templateId = 1L;
+ long storeId = 2L;
+ long size = 1024L;
+ long physicalSize = 2048L;
+ VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
+ when(template.getId()).thenReturn(templateId);
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+
+ when(vmTemplateDao.findById(templateId)).thenReturn(template);
+ when(templateDataStoreDao.findByStoreTemplate(storeId, templateId)).thenReturn(templateDataStoreVO);
+ when(templateDataStoreDao.update(anyLong(), any(TemplateDataStoreVO.class))).thenReturn(true);
+
+ systemVmTemplateRegistration.updateSeededTemplateDetails(templateId, storeId, size, physicalSize);
+
+ verify(template).setSize(size);
+ verify(vmTemplateDao).update(template.getId(), template);
+ verify(templateDataStoreVO).setSize(size);
+ verify(templateDataStoreVO).setPhysicalSize(physicalSize);
+ verify(templateDataStoreVO).setLastUpdated(any(Date.class));
+ verify(templateDataStoreDao).update(templateDataStoreVO.getId(), templateDataStoreVO);
+ }
+
+ @Test
+ public void updateSeededTemplateDetails_ThrowsExceptionWhenStoreUpdateFails() {
+ long templateId = 1L;
+ long storeId = 2L;
+ long size = 1024L;
+ long physicalSize = 2048L;
+ VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
+ when(template.getId()).thenReturn(templateId);
+ TemplateDataStoreVO templateDataStoreVO = Mockito.mock(TemplateDataStoreVO.class);
+
+ when(vmTemplateDao.findById(templateId)).thenReturn(template);
+ when(templateDataStoreDao.findByStoreTemplate(storeId, templateId)).thenReturn(templateDataStoreVO);
+ when(templateDataStoreDao.update(anyLong(), any(TemplateDataStoreVO.class))).thenReturn(false);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.updateSeededTemplateDetails(templateId, storeId, size, physicalSize);
+ });
+
+ assertTrue(exception.getMessage().contains("Failed to update template-store record for seeded system VM Template"));
+ verify(templateDataStoreDao).update(templateDataStoreVO.getId(), templateDataStoreVO);
+ }
+
+ @Test
+ public void updateSystemVMEntries_UpdatesTemplateIdSuccessfully() {
+ long templateId = 1L;
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+
+ systemVmTemplateRegistration.updateSystemVMEntries(templateId, hypervisorType);
+
+ verify(vmInstanceDao).updateSystemVmTemplateId(templateId, hypervisorType);
+ }
+
+ @Test
+ public void updateHypervisorGuestOsMap_UpdatesGuestOsMapSuccessfully() {
+ GuestOSVO guestOS = Mockito.mock(GuestOSVO.class);
+ when(guestOS.getId()).thenReturn(10L);
+ when(guestOSDao.findOneByDisplayName(DEFAULT_SYSTEM_VM_GUEST_OS_NAME)).thenReturn(guestOS);
+
+ systemVmTemplateRegistration.updateHypervisorGuestOsMap();
+
+ verify(guestOSDao).findOneByDisplayName(DEFAULT_SYSTEM_VM_GUEST_OS_NAME);
+ assertEquals(10, SystemVmTemplateRegistration.LINUX_12_ID.intValue());
+ assertEquals(10, SystemVmTemplateRegistration.hypervisorGuestOsMap.get(Hypervisor.HypervisorType.KVM).intValue());
+ assertEquals(10, SystemVmTemplateRegistration.hypervisorGuestOsMap.get(Hypervisor.HypervisorType.Hyperv).intValue());
+ assertEquals(10, SystemVmTemplateRegistration.hypervisorGuestOsMap.get(Hypervisor.HypervisorType.LXC).intValue());
+ assertEquals(10, SystemVmTemplateRegistration.hypervisorGuestOsMap.get(Hypervisor.HypervisorType.Ovm3).intValue());
+ }
+
+ @Test
+ public void updateHypervisorGuestOsMap_SkipsUpdateWhenGuestOsNotFound() {
+ Integer value = SystemVmTemplateRegistration.hypervisorGuestOsMap.get(Hypervisor.HypervisorType.KVM);
+ when(guestOSDao.findOneByDisplayName(DEFAULT_SYSTEM_VM_GUEST_OS_NAME)).thenReturn(null);
+
+ systemVmTemplateRegistration.updateHypervisorGuestOsMap();
+
+ verify(guestOSDao).findOneByDisplayName(DEFAULT_SYSTEM_VM_GUEST_OS_NAME);
+ assertEquals(value, SystemVmTemplateRegistration.hypervisorGuestOsMap.get(Hypervisor.HypervisorType.KVM));
+ }
+
+ @Test
+ public void updateHypervisorGuestOsMap_LogsWarningOnException() {
+ when(guestOSDao.findOneByDisplayName(DEFAULT_SYSTEM_VM_GUEST_OS_NAME)).thenThrow(new RuntimeException("Database error"));
+
+ systemVmTemplateRegistration.updateHypervisorGuestOsMap();
+
+ verify(guestOSDao).findOneByDisplayName(DEFAULT_SYSTEM_VM_GUEST_OS_NAME);
+ }
+
+ @Test
+ public void updateTemplateUrlChecksumAndGuestOsId_UpdatesSuccessfully() {
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ GuestOSVO guestOS = Mockito.mock(GuestOSVO.class);
+
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ when(templateDetails.getChecksum()).thenReturn("abc123");
+ when(templateDetails.getGuestOs()).thenReturn("Debian");
+ when(guestOSDao.findOneByDisplayName("Debian")).thenReturn(guestOS);
+ when(guestOS.getId()).thenReturn(10L);
+ when(templateVO.getId()).thenReturn(1L);
+ when(vmTemplateDao.update(templateVO.getId(), templateVO)).thenReturn(true);
+
+ systemVmTemplateRegistration.updateTemplateUrlChecksumAndGuestOsId(templateVO, templateDetails);
+
+ verify(templateVO).setUrl("http://example.com/template");
+ verify(templateVO).setChecksum("abc123");
+ verify(templateVO).setGuestOSId(10L);
+ verify(vmTemplateDao).update(templateVO.getId(), templateVO);
+ }
+
+ @Test
+ public void updateTemplateUrlChecksumAndGuestOsId_SkipsGuestOsUpdateWhenNotFound() {
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ when(templateDetails.getChecksum()).thenReturn("abc123");
+ when(templateDetails.getGuestOs()).thenReturn("NonExistentOS");
+ when(guestOSDao.findOneByDisplayName("NonExistentOS")).thenReturn(null);
+ when(templateVO.getId()).thenReturn(1L);
+ when(vmTemplateDao.update(templateVO.getId(), templateVO)).thenReturn(true);
+
+ systemVmTemplateRegistration.updateTemplateUrlChecksumAndGuestOsId(templateVO, templateDetails);
+
+ verify(templateVO).setUrl("http://example.com/template");
+ verify(templateVO).setChecksum("abc123");
+ verify(templateVO, never()).setGuestOSId(anyLong());
+ verify(vmTemplateDao).update(templateVO.getId(), templateVO);
+ }
+
+ @Test
+ public void updateTemplateUrlChecksumAndGuestOsId_ThrowsExceptionWhenUpdateFails() {
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ when(templateDetails.getChecksum()).thenReturn("abc123");
+ when(templateDetails.getGuestOs()).thenReturn("Debian");
+ when(templateVO.getId()).thenReturn(1L);
+ when(vmTemplateDao.update(templateVO.getId(), templateVO)).thenReturn(false);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class, () -> {
+ systemVmTemplateRegistration.updateTemplateUrlChecksumAndGuestOsId(templateVO, templateDetails);
+ });
+
+ assertTrue(exception.getMessage().contains("Exception while updating 'url' and 'checksum' for hypervisor type"));
+ verify(vmTemplateDao).update(templateVO.getId(), templateVO);
+ }
}
diff --git a/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDetailsDaoImplTest.java b/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDetailsDaoImplTest.java
new file mode 100644
index 0000000..06238e3
--- /dev/null
+++ b/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDetailsDaoImplTest.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 com.cloud.vm.dao;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.vm.VMInstanceDetailVO;
+
+@RunWith(MockitoJUnitRunner.class)
+public class VMInstanceDetailsDaoImplTest {
+ @Spy
+ @InjectMocks
+ private VMInstanceDetailsDaoImpl vmInstanceDetailsDaoImpl;
+
+ @Test
+ public void removeDetailsWithPrefixReturnsZeroWhenPrefixIsBlank() {
+ Assert.assertEquals(0, vmInstanceDetailsDaoImpl.removeDetailsWithPrefix(1L, ""));
+ Assert.assertEquals(0, vmInstanceDetailsDaoImpl.removeDetailsWithPrefix(1L, " "));
+ Assert.assertEquals(0, vmInstanceDetailsDaoImpl.removeDetailsWithPrefix(1L, null));
+ }
+
+ @Test
+ public void removeDetailsWithPrefixRemovesMatchingDetails() {
+ SearchBuilder<VMInstanceDetailVO> sb = mock(SearchBuilder.class);
+ VMInstanceDetailVO entity = mock(VMInstanceDetailVO.class);
+ when(sb.entity()).thenReturn(entity);
+ when(sb.and(anyString(), any(), any(SearchCriteria.Op.class))).thenReturn(sb);
+ SearchCriteria<VMInstanceDetailVO> sc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(vmInstanceDetailsDaoImpl.createSearchBuilder()).thenReturn(sb);
+ doReturn(3).when(vmInstanceDetailsDaoImpl).remove(sc);
+ int removedCount = vmInstanceDetailsDaoImpl.removeDetailsWithPrefix(1L, "testPrefix");
+ Assert.assertEquals(3, removedCount);
+ Mockito.verify(sc).setParameters("vmId", 1L);
+ Mockito.verify(sc).setParameters("prefix", "testPrefix%");
+ Mockito.verify(vmInstanceDetailsDaoImpl, Mockito.times(1)).remove(sc);
+ }
+
+ @Test
+ public void removeDetailsWithPrefixDoesNotRemoveWhenNoMatch() {
+ SearchBuilder<VMInstanceDetailVO> sb = mock(SearchBuilder.class);
+ VMInstanceDetailVO entity = mock(VMInstanceDetailVO.class);
+ when(sb.entity()).thenReturn(entity);
+ when(sb.and(anyString(), any(), any(SearchCriteria.Op.class))).thenReturn(sb);
+ SearchCriteria<VMInstanceDetailVO> sc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(vmInstanceDetailsDaoImpl.createSearchBuilder()).thenReturn(sb);
+ doReturn(0).when(vmInstanceDetailsDaoImpl).remove(sc);
+
+ int removedCount = vmInstanceDetailsDaoImpl.removeDetailsWithPrefix(1L, "nonExistentPrefix");
+
+ Assert.assertEquals(0, removedCount);
+ Mockito.verify(sc).setParameters("vmId", 1L);
+ Mockito.verify(sc).setParameters("prefix", "nonExistentPrefix%");
+ Mockito.verify(vmInstanceDetailsDaoImpl, Mockito.times(1)).remove(sc);
+ }
+}
diff --git a/engine/schema/src/test/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDaoImplTest.java b/engine/schema/src/test/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDaoImplTest.java
new file mode 100644
index 0000000..fc8f2d0
--- /dev/null
+++ b/engine/schema/src/test/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDaoImplTest.java
@@ -0,0 +1,251 @@
+// 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.backup.dao;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.backup.BackupOfferingDetailsVO;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.db.SearchCriteria;
+
+@RunWith(MockitoJUnitRunner.class)
+public class BackupOfferingDetailsDaoImplTest {
+
+ @Spy
+ @InjectMocks
+ private BackupOfferingDetailsDaoImpl backupOfferingDetailsDao;
+
+ private static final long RESOURCE_ID = 1L;
+ private static final long OFFERING_ID = 100L;
+ private static final String TEST_KEY = "testKey";
+ private static final String TEST_VALUE = "testValue";
+
+ @Test
+ public void testAddDetail() {
+ BackupOfferingDetailsVO detailVO = new BackupOfferingDetailsVO(RESOURCE_ID, TEST_KEY, TEST_VALUE, true);
+
+ Assert.assertEquals("Resource ID should match", RESOURCE_ID, detailVO.getResourceId());
+ Assert.assertEquals("Detail name/key should match", TEST_KEY, detailVO.getName());
+ Assert.assertEquals("Detail value should match", TEST_VALUE, detailVO.getValue());
+ Assert.assertTrue("Display flag should be true", detailVO.isDisplay());
+
+ BackupOfferingDetailsVO detailVOHidden = new BackupOfferingDetailsVO(RESOURCE_ID, "hiddenKey", "hiddenValue", false);
+ Assert.assertFalse("Display flag should be false", detailVOHidden.isDisplay());
+ }
+
+ @Test
+ public void testFindDomainIdsWithMultipleDomains() {
+ List<BackupOfferingDetailsVO> mockDetails = Arrays.asList(
+ createDetailVO(RESOURCE_ID, ApiConstants.DOMAIN_ID, "1", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.DOMAIN_ID, "2", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.DOMAIN_ID, "3", false)
+ );
+
+ Mockito.doReturn(mockDetails).when(backupOfferingDetailsDao)
+ .findDetails(RESOURCE_ID, ApiConstants.DOMAIN_ID);
+
+ List<Long> domainIds = backupOfferingDetailsDao.findDomainIds(RESOURCE_ID);
+
+ Assert.assertNotNull(domainIds);
+ Assert.assertEquals(3, domainIds.size());
+ Assert.assertEquals(Arrays.asList(1L, 2L, 3L), domainIds);
+ }
+
+ @Test
+ public void testFindDomainIdsWithEmptyList() {
+ Mockito.doReturn(Collections.emptyList()).when(backupOfferingDetailsDao)
+ .findDetails(RESOURCE_ID, ApiConstants.DOMAIN_ID);
+
+ List<Long> domainIds = backupOfferingDetailsDao.findDomainIds(RESOURCE_ID);
+
+ Assert.assertNotNull(domainIds);
+ Assert.assertTrue(domainIds.isEmpty());
+ }
+
+ @Test
+ public void testFindDomainIdsExcludesZeroOrNegativeValues() {
+ List<BackupOfferingDetailsVO> mockDetails = Arrays.asList(
+ createDetailVO(RESOURCE_ID, ApiConstants.DOMAIN_ID, "1", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.DOMAIN_ID, "0", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.DOMAIN_ID, "-1", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.DOMAIN_ID, "2", false)
+ );
+
+ Mockito.doReturn(mockDetails).when(backupOfferingDetailsDao)
+ .findDetails(RESOURCE_ID, ApiConstants.DOMAIN_ID);
+
+ List<Long> domainIds = backupOfferingDetailsDao.findDomainIds(RESOURCE_ID);
+
+ Assert.assertNotNull(domainIds);
+ Assert.assertEquals(2, domainIds.size());
+ Assert.assertEquals(Arrays.asList(1L, 2L), domainIds);
+ }
+
+ @Test
+ public void testFindZoneIdsWithMultipleZones() {
+ List<BackupOfferingDetailsVO> mockDetails = Arrays.asList(
+ createDetailVO(RESOURCE_ID, ApiConstants.ZONE_ID, "10", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.ZONE_ID, "20", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.ZONE_ID, "30", false)
+ );
+
+ Mockito.doReturn(mockDetails).when(backupOfferingDetailsDao)
+ .findDetails(RESOURCE_ID, ApiConstants.ZONE_ID);
+
+ List<Long> zoneIds = backupOfferingDetailsDao.findZoneIds(RESOURCE_ID);
+
+ Assert.assertNotNull(zoneIds);
+ Assert.assertEquals(3, zoneIds.size());
+ Assert.assertEquals(Arrays.asList(10L, 20L, 30L), zoneIds);
+ }
+
+ @Test
+ public void testFindZoneIdsWithEmptyList() {
+ Mockito.doReturn(Collections.emptyList()).when(backupOfferingDetailsDao)
+ .findDetails(RESOURCE_ID, ApiConstants.ZONE_ID);
+
+ List<Long> zoneIds = backupOfferingDetailsDao.findZoneIds(RESOURCE_ID);
+
+ Assert.assertNotNull(zoneIds);
+ Assert.assertTrue(zoneIds.isEmpty());
+ }
+
+ @Test
+ public void testFindZoneIdsExcludesZeroOrNegativeValues() {
+ List<BackupOfferingDetailsVO> mockDetails = Arrays.asList(
+ createDetailVO(RESOURCE_ID, ApiConstants.ZONE_ID, "10", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.ZONE_ID, "0", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.ZONE_ID, "-5", false),
+ createDetailVO(RESOURCE_ID, ApiConstants.ZONE_ID, "20", false)
+ );
+
+ Mockito.doReturn(mockDetails).when(backupOfferingDetailsDao)
+ .findDetails(RESOURCE_ID, ApiConstants.ZONE_ID);
+
+ List<Long> zoneIds = backupOfferingDetailsDao.findZoneIds(RESOURCE_ID);
+
+ Assert.assertNotNull(zoneIds);
+ Assert.assertEquals(2, zoneIds.size());
+ Assert.assertEquals(Arrays.asList(10L, 20L), zoneIds);
+ }
+
+ @Test
+ public void testGetDetailWhenDetailExists() {
+ BackupOfferingDetailsVO mockDetail = createDetailVO(OFFERING_ID, TEST_KEY, TEST_VALUE, true);
+
+ Mockito.doReturn(mockDetail).when(backupOfferingDetailsDao)
+ .findDetail(OFFERING_ID, TEST_KEY);
+
+ String detailValue = backupOfferingDetailsDao.getDetail(OFFERING_ID, TEST_KEY);
+
+ Assert.assertNotNull(detailValue);
+ Assert.assertEquals(TEST_VALUE, detailValue);
+ }
+
+ @Test
+ public void testGetDetailWhenDetailDoesNotExist() {
+ Mockito.doReturn(null).when(backupOfferingDetailsDao)
+ .findDetail(OFFERING_ID, TEST_KEY);
+
+ String detailValue = backupOfferingDetailsDao.getDetail(OFFERING_ID, TEST_KEY);
+
+ Assert.assertNull(detailValue);
+ }
+
+ @Test
+ public void testFindOfferingIdsByDomainIds() {
+ List<Long> domainIds = Arrays.asList(1L, 2L, 3L);
+ List<Long> expectedOfferingIds = Arrays.asList(100L, 101L, 102L);
+
+ Mockito.doReturn(expectedOfferingIds).when(backupOfferingDetailsDao)
+ .findResourceIdsByNameAndValueIn(Mockito.eq("domainid"), Mockito.any(Object[].class));
+
+ List<Long> offeringIds = backupOfferingDetailsDao.findOfferingIdsByDomainIds(domainIds);
+
+ Assert.assertNotNull(offeringIds);
+ Assert.assertEquals(expectedOfferingIds, offeringIds);
+ Mockito.verify(backupOfferingDetailsDao).findResourceIdsByNameAndValueIn(
+ Mockito.eq("domainid"), Mockito.any(Object[].class));
+ }
+
+ @Test
+ public void testFindOfferingIdsByDomainIdsWithEmptyList() {
+ List<Long> domainIds = Collections.emptyList();
+ List<Long> expectedOfferingIds = Collections.emptyList();
+
+ Mockito.doReturn(expectedOfferingIds).when(backupOfferingDetailsDao)
+ .findResourceIdsByNameAndValueIn(Mockito.eq("domainid"), Mockito.any(Object[].class));
+
+ List<Long> offeringIds = backupOfferingDetailsDao.findOfferingIdsByDomainIds(domainIds);
+
+ Assert.assertNotNull(offeringIds);
+ Assert.assertTrue(offeringIds.isEmpty());
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testUpdateBackupOfferingDomainIdsDetail() {
+ List<Long> newDomainIds = Arrays.asList(1L, 2L, 3L);
+
+ Mockito.doReturn(0).when(backupOfferingDetailsDao).remove(Mockito.any(SearchCriteria.class));
+ Mockito.doReturn(null).when(backupOfferingDetailsDao).persist(Mockito.any(BackupOfferingDetailsVO.class));
+
+ backupOfferingDetailsDao.updateBackupOfferingDomainIdsDetail(OFFERING_ID, newDomainIds);
+
+ Mockito.verify(backupOfferingDetailsDao, Mockito.times(3)).persist(Mockito.any(BackupOfferingDetailsVO.class));
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testUpdateBackupOfferingDomainIdsDetailWithEmptyList() {
+ List<Long> emptyDomainIds = Collections.emptyList();
+
+ Mockito.doReturn(0).when(backupOfferingDetailsDao).remove(Mockito.any(SearchCriteria.class));
+
+ backupOfferingDetailsDao.updateBackupOfferingDomainIdsDetail(OFFERING_ID, emptyDomainIds);
+
+ Mockito.verify(backupOfferingDetailsDao, Mockito.never()).persist(Mockito.any(BackupOfferingDetailsVO.class));
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testUpdateBackupOfferingDomainIdsDetailWithSingleDomain() {
+ List<Long> singleDomainId = Collections.singletonList(5L);
+
+ Mockito.doReturn(0).when(backupOfferingDetailsDao).remove(Mockito.any(SearchCriteria.class));
+ Mockito.doReturn(null).when(backupOfferingDetailsDao).persist(Mockito.any(BackupOfferingDetailsVO.class));
+
+ backupOfferingDetailsDao.updateBackupOfferingDomainIdsDetail(OFFERING_ID, singleDomainId);
+
+ Mockito.verify(backupOfferingDetailsDao, Mockito.times(1)).persist(Mockito.any(BackupOfferingDetailsVO.class));
+ }
+
+ private BackupOfferingDetailsVO createDetailVO(long resourceId, String name, String value, boolean display) {
+ return new BackupOfferingDetailsVO(resourceId, name, value, display);
+ }
+}
diff --git a/engine/schema/templateConfig.sh b/engine/schema/templateConfig.sh
index 3a963e5..21a4ee7 100755
--- a/engine/schema/templateConfig.sh
+++ b/engine/schema/templateConfig.sh
@@ -27,6 +27,7 @@
export CS_VERSION="${subversion1}"."${subversion2}"
export CS_MINOR_VERSION="${minorversion}"
export VERSION="${CS_VERSION}.${CS_MINOR_VERSION}"
+ export CS_SYSTEMTEMPLATE_REPO="https://download.cloudstack.org/systemvm/"
}
function getGenericName() {
@@ -63,7 +64,7 @@
function createMetadataFile() {
local fileData=$(cat "$SOURCEFILE")
- echo -e "["default"]\nversion = $VERSION.${securityversion}\n" >> "$METADATAFILE"
+ echo -e "["default"]\nversion = $VERSION.${securityversion}\ndownloadrepository = $CS_SYSTEMTEMPLATE_REPO\n" >> "$METADATAFILE"
for template in "${templates[@]}"
do
section="${template%%:*}"
@@ -82,13 +83,21 @@
declare -a templates
getTemplateVersion $1
-templates=( "kvm-x86_64:https://download.cloudstack.org/systemvm/${CS_VERSION}/systemvmtemplate-$VERSION-x86_64-kvm.qcow2.bz2"
- "kvm-aarch64:https://download.cloudstack.org/systemvm/${CS_VERSION}/systemvmtemplate-$VERSION-aarch64-kvm.qcow2.bz2"
- "vmware:https://download.cloudstack.org/systemvm/${CS_VERSION}/systemvmtemplate-$VERSION-x86_64-vmware.ova"
- "xenserver:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-xen.vhd.bz2"
- "hyperv:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-hyperv.vhd.zip"
- "lxc:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-kvm.qcow2.bz2"
- "ovm3:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-ovm.raw.bz2" )
+declare -A template_specs=(
+ [kvm-x86_64]="x86_64-kvm.qcow2.bz2"
+ [kvm-aarch64]="aarch64-kvm.qcow2.bz2"
+ [vmware]="x86_64-vmware.ova"
+ [xenserver]="x86_64-xen.vhd.bz2"
+ [hyperv]="x86_64-hyperv.vhd.zip"
+ [lxc]="x86_64-kvm.qcow2.bz2"
+ [ovm3]="x86_64-ovm.raw.bz2"
+)
+
+templates=()
+for key in "${!template_specs[@]}"; do
+ url="${CS_SYSTEMTEMPLATE_REPO}/${CS_VERSION}/systemvmtemplate-$VERSION-${template_specs[$key]}"
+ templates+=("$key:$url")
+done
PARENTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )/dist/systemvm-templates/"
mkdir -p "$PARENTPATH"
diff --git a/engine/service/pom.xml b/engine/service/pom.xml
index c429ebf..673d9c4 100644
--- a/engine/service/pom.xml
+++ b/engine/service/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-engine-service</artifactId>
<packaging>war</packaging>
@@ -69,7 +69,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
- <version>3.4.0</version>
+ <version>3.5.1</version>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
diff --git a/engine/storage/cache/pom.xml b/engine/storage/cache/pom.xml
index 2e736ad..ac330ca 100644
--- a/engine/storage/cache/pom.xml
+++ b/engine/storage/cache/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRU.java b/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRU.java
index fc432ac..7042ee4 100644
--- a/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRU.java
+++ b/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRU.java
@@ -62,7 +62,6 @@
/* Avoid using configDao at this time, we can't be sure that the database is already upgraded
* and there might be fatal errors when using a dao.
*/
- //unusedTimeInterval = NumbersUtil.parseInt(configDao.getValue(Config.StorageCacheReplacementLRUTimeInterval.key()), 30);
}
public void setUnusedTimeInterval(Integer interval) {
diff --git a/engine/storage/configdrive/pom.xml b/engine/storage/configdrive/pom.xml
index d5ef49d..43eb249 100644
--- a/engine/storage/configdrive/pom.xml
+++ b/engine/storage/configdrive/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/storage/datamotion/pom.xml b/engine/storage/datamotion/pom.xml
index aa5a6d1..d3b6bb5 100644
--- a/engine/storage/datamotion/pom.xml
+++ b/engine/storage/datamotion/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/storage/image/pom.xml b/engine/storage/image/pom.xml
index 0232e40..2cdef35 100644
--- a/engine/storage/image/pom.xml
+++ b/engine/storage/image/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/storage/integration-test/pom.xml b/engine/storage/integration-test/pom.xml
index 2ca3146..13f0b45 100644
--- a/engine/storage/integration-test/pom.xml
+++ b/engine/storage/integration-test/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/storage/integration-test/src/test/java/org/apache/cloudstack/storage/test/VolumeServiceTest.java b/engine/storage/integration-test/src/test/java/org/apache/cloudstack/storage/test/VolumeServiceTest.java
index c478e2e..1e6a85e 100644
--- a/engine/storage/integration-test/src/test/java/org/apache/cloudstack/storage/test/VolumeServiceTest.java
+++ b/engine/storage/integration-test/src/test/java/org/apache/cloudstack/storage/test/VolumeServiceTest.java
@@ -87,8 +87,6 @@
@ContextConfiguration(locations = {"classpath:/storageContext.xml"})
public class VolumeServiceTest extends CloudStackTestNGBase {
- // @Inject
- // ImageDataStoreProviderManager imageProviderMgr;
@Inject
TemplateService imageService;
@Inject
@@ -232,23 +230,7 @@
DataStore store = createImageStore();
VMTemplateVO image = createImageData();
TemplateInfo template = imageDataFactory.getTemplate(image.getId(), store);
- // AsyncCallFuture<TemplateApiResult> future =
- // imageService.createTemplateAsync(template, store);
- // future.get();
template = imageDataFactory.getTemplate(image.getId(), store);
- /*
- * imageProviderMgr.configure("image Provider", new HashMap<String,
- * Object>()); VMTemplateVO image = createImageData();
- * ImageDataStoreProvider defaultProvider =
- * imageProviderMgr.getProvider("DefaultProvider");
- * ImageDataStoreLifeCycle lifeCycle =
- * defaultProvider.getLifeCycle(); ImageDataStore store =
- * lifeCycle.registerDataStore("defaultHttpStore", new
- * HashMap<String, String>());
- * imageService.registerTemplate(image.getId(),
- * store.getImageDataStoreId()); TemplateEntity te =
- * imageService.getTemplateEntity(image.getId()); return te;
- */
return template;
} catch (Exception e) {
Assert.fail("failed", e);
@@ -333,30 +315,6 @@
ClusterScope scope = new ClusterScope(clusterId, podId, dcId);
lifeCycle.attachCluster(store, scope);
- /*
- * PrimaryDataStoreProvider provider =
- * primaryDataStoreProviderMgr.getDataStoreProvider
- * ("sample primary data store provider");
- * primaryDataStoreProviderMgr.configure("primary data store mgr",
- * new HashMap<String, Object>());
- *
- * List<PrimaryDataStoreVO> ds =
- * primaryStoreDao.findPoolByName(this.primaryName); if (ds.size()
- * >= 1) { PrimaryDataStoreVO store = ds.get(0); if
- * (store.getRemoved() == null) { return
- * provider.getDataStore(store.getId()); } }
- *
- *
- * Map<String, String> params = new HashMap<String, String>();
- * params.put("url", this.getPrimaryStorageUrl());
- * params.put("dcId", dcId.toString()); params.put("clusterId",
- * clusterId.toString()); params.put("name", this.primaryName);
- * PrimaryDataStoreInfo primaryDataStoreInfo =
- * provider.registerDataStore(params); PrimaryDataStoreLifeCycle lc
- * = primaryDataStoreInfo.getLifeCycle(); ClusterScope scope = new
- * ClusterScope(clusterId, podId, dcId); lc.attachCluster(scope);
- * return primaryDataStoreInfo;
- */
return store;
} catch (Exception e) {
return null;
@@ -376,7 +334,6 @@
TemplateInfo te = createTemplate();
VolumeVO volume = createVolume(te.getId(), primaryStore.getId());
VolumeInfo vol = volumeFactory.getVolume(volume.getId(), primaryStore);
- // ve.createVolumeFromTemplate(primaryStore.getId(), new VHD(), te);
AsyncCallFuture<VolumeApiResult> future = volumeService.createVolumeFromTemplateAsync(vol, primaryStore.getId(), te);
try {
future.get();
diff --git a/engine/storage/object/pom.xml b/engine/storage/object/pom.xml
index a9e3aea..d5f2a79 100644
--- a/engine/storage/object/pom.xml
+++ b/engine/storage/object/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/storage/pom.xml b/engine/storage/pom.xml
index 72e9def..a2044c6 100644
--- a/engine/storage/pom.xml
+++ b/engine/storage/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/storage/snapshot/pom.xml b/engine/storage/snapshot/pom.xml
index 14b0ce9..0966082 100644
--- a/engine/storage/snapshot/pom.xml
+++ b/engine/storage/snapshot/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
@@ -57,8 +57,8 @@
<scope>compile</scope>
</dependency>
<dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
+ <groupId>com.mysql</groupId>
+ <artifactId>mysql-connector-j</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java
index 0e38df5..7174336 100644
--- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java
+++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java
@@ -672,6 +672,12 @@
}
}
+ if (CollectionUtils.isNotEmpty(vmSnapshotDao.findByVmAndByType(volumeVO.getInstanceId(), VMSnapshot.Type.DiskAndMemory))) {
+ logger.debug("DefaultSnapshotStrategy cannot handle snapshot [{}] for volume [{}] as the volume is attached to a VM with disk-and-memory VM snapshots." +
+ "Restoring the volume snapshot will corrupt any newer disk-and-memory VM snapshots.", snapshot);
+ return StrategyPriority.CANT_HANDLE;
+ }
+
return StrategyPriority.DEFAULT;
}
diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java
index 90f517f..b71d6cf 100644
--- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java
+++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java
@@ -26,14 +26,21 @@
import javax.naming.ConfigurationException;
import com.cloud.hypervisor.Hypervisor;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.dao.SnapshotDao;
import com.cloud.vm.snapshot.VMSnapshotDetailsVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDetailsDao;
+import org.apache.cloudstack.backup.BackupManager;
+import org.apache.cloudstack.backup.BackupOfferingVO;
+import org.apache.cloudstack.backup.BackupProvider;
+import org.apache.cloudstack.backup.dao.BackupOfferingDao;
import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotOptions;
import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotStrategy;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import com.cloud.agent.AgentManager;
@@ -104,7 +111,16 @@
PrimaryDataStoreDao primaryDataStoreDao;
@Inject
- VMSnapshotDetailsDao vmSnapshotDetailsDao;
+ private VMSnapshotDetailsDao vmSnapshotDetailsDao;
+
+ @Inject
+ private BackupManager backupManager;
+
+ @Inject
+ private BackupOfferingDao backupOfferingDao;
+
+ @Inject
+ private SnapshotDao snapshotDao;
protected static final String KVM_FILE_BASED_STORAGE_SNAPSHOT = "kvmFileBasedStorageSnapshot";
@@ -480,24 +496,44 @@
@Override
public StrategyPriority canHandle(Long vmId, Long rootPoolId, boolean snapshotMemory) {
UserVmVO vm = userVmDao.findById(vmId);
+ String cantHandleLog = String.format("Default VM snapshot cannot handle VM snapshot for [%s]", vm);
if (State.Running.equals(vm.getState()) && !snapshotMemory) {
- logger.debug("Default VM snapshot strategy cannot handle VM snapshot for [{}] as it is running and its memory will not be affected.", vm);
+ logger.debug("{} as it is running and its memory will not be affected.", cantHandleLog, vm);
return StrategyPriority.CANT_HANDLE;
}
if (vmHasKvmDiskOnlySnapshot(vm)) {
- logger.debug("Default VM snapshot strategy cannot handle VM snapshot for [{}] as it has a disk-only VM snapshot using kvmFileBasedStorageSnapshot strategy." +
- "These two strategies are not compatible, as reverting a disk-only VM snapshot will erase newer disk-and-memory VM snapshots.", vm);
+ logger.debug("{} as it is not compatible with disk-only VM snapshot on KVM. As disk-and-memory snapshots use internal snapshots and disk-only VM snapshots use" +
+ " external snapshots. When restoring external snapshots, any newer internal snapshots are lost.", cantHandleLog);
return StrategyPriority.CANT_HANDLE;
}
List<VolumeVO> volumes = volumeDao.findByInstance(vmId);
for (VolumeVO volume : volumes) {
if (volume.getFormat() != ImageFormat.QCOW2) {
- logger.debug("Default VM snapshot strategy cannot handle VM snapshot for [{}] as it has a volume [{}] that is not in the QCOW2 format.", vm, volume);
+ logger.debug("{} as it has a volume [{}] that is not in the QCOW2 format.", cantHandleLog, vm, volume);
+ return StrategyPriority.CANT_HANDLE;
+ }
+
+ if (CollectionUtils.isNotEmpty(snapshotDao.listByVolumeIdAndTypeNotInAndStateNotRemoved(volume.getId(), Snapshot.Type.GROUP))) {
+ logger.debug("{} as it has a volume [{}] with volume snapshots. As disk-and-memory snapshots use internal snapshots and volume snapshots use external" +
+ " snapshots. When restoring external snapshots, any newer internal snapshots are lost.", cantHandleLog, volume);
return StrategyPriority.CANT_HANDLE;
}
}
+
+
+ BackupOfferingVO backupOfferingVO = backupOfferingDao.findById(vm.getBackupOfferingId());
+ if (backupOfferingVO == null) {
+ return StrategyPriority.DEFAULT;
+ }
+
+ BackupProvider provider = backupManager.getBackupProvider(backupOfferingVO.getProvider());
+ if (!provider.supportsMemoryVmSnapshot()) {
+ logger.debug("{} as the VM has a backup offering for a provider that is not supported.", cantHandleLog);
+ return StrategyPriority.CANT_HANDLE;
+ }
+
return StrategyPriority.DEFAULT;
}
@@ -508,7 +544,7 @@
for (VMSnapshotVO vmSnapshotVO : vmSnapshotDao.findByVmAndByType(vm.getId(), VMSnapshot.Type.Disk)) {
List<VMSnapshotDetailsVO> vmSnapshotDetails = vmSnapshotDetailsDao.listDetails(vmSnapshotVO.getId());
- if (vmSnapshotDetails.stream().anyMatch(vmSnapshotDetailsVO -> vmSnapshotDetailsVO.getName().equals(KVM_FILE_BASED_STORAGE_SNAPSHOT))) {
+ if (vmSnapshotDetails.stream().anyMatch(detailsVO -> KVM_FILE_BASED_STORAGE_SNAPSHOT.equals(detailsVO.getName()) || STORAGE_SNAPSHOT.equals(detailsVO.getName()))) {
return true;
}
}
diff --git a/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyKVMTest.java b/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyKVMTest.java
index 609a122..050c024 100644
--- a/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyKVMTest.java
+++ b/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyKVMTest.java
@@ -29,6 +29,8 @@
import javax.inject.Inject;
+import org.apache.cloudstack.backup.BackupManager;
+import org.apache.cloudstack.backup.dao.BackupOfferingDao;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
@@ -235,7 +237,6 @@
when(vol.getDataStore()).thenReturn(dataStore);
when(snapshotVO.getId()).thenReturn(1L);
when(_snapshotService.revertSnapshot(snapshotVO.getId())).thenReturn(snap);
- // testFindSnapshotByName(name);
vmStrategy.revertDiskSnapshot(vmSnapshot);
}
@@ -431,5 +432,15 @@
public VMSnapshotDetailsDao vmSnapshotDetailsDao () {
return Mockito.mock(VMSnapshotDetailsDao.class);
}
+
+ @Bean
+ public BackupOfferingDao backupOfferingDao() {
+ return Mockito.mock(BackupOfferingDao.class);
+ }
+
+ @Bean
+ public BackupManager backupManager() {
+ return Mockito.mock(BackupManager.class);
+ }
}
}
diff --git a/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyTest.java b/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyTest.java
index 829ca5a..a20b52f 100644
--- a/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyTest.java
+++ b/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyTest.java
@@ -25,7 +25,10 @@
import javax.inject.Inject;
+import com.cloud.storage.dao.SnapshotDao;
import com.cloud.vm.snapshot.dao.VMSnapshotDetailsDao;
+import org.apache.cloudstack.backup.BackupManager;
+import org.apache.cloudstack.backup.dao.BackupOfferingDao;
import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotStrategy;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@@ -318,5 +321,25 @@
public PrimaryDataStoreDao primaryDataStoreDao() {
return Mockito.mock(PrimaryDataStoreDao.class);
}
+
+ @Bean
+ public BackupOfferingDao backupOfferingDao() {
+ return Mockito.mock(BackupOfferingDao.class);
+ }
+
+ @Bean
+ public VMSnapshotDetailsDao VMSnapshotDetailsDao() {
+ return Mockito.mock(VMSnapshotDetailsDao.class);
+ }
+
+ @Bean
+ public SnapshotDao snapshotDao() {
+ return Mockito.mock(SnapshotDao.class);
+ }
+
+ @Bean
+ public BackupManager backupManager() {
+ return Mockito.mock(BackupManager.class);
+ }
}
}
diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java
index e0e244d..cd9ab3a 100644
--- a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java
+++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java
@@ -241,7 +241,7 @@
List<StoragePool> reorderStoragePoolsBasedOnAlgorithm(List<StoragePool> pools, DeploymentPlan plan, Account account) {
String volumeAllocationAlgorithm = VolumeOrchestrationService.VolumeAllocationAlgorithm.value();
logger.debug("Using volume allocation algorithm {} to reorder pools.", volumeAllocationAlgorithm);
- if (volumeAllocationAlgorithm.equals("random") || volumeAllocationAlgorithm.equals("userconcentratedpod_random") || (account == null)) {
+ if (volumeAllocationAlgorithm.equals("random") || (account == null)) {
reorderRandomPools(pools);
} else if (StringUtils.equalsAny(volumeAllocationAlgorithm, "userdispersing", "firstfitleastconsumed")) {
if (logger.isTraceEnabled()) {
diff --git a/engine/storage/volume/pom.xml b/engine/storage/volume/pom.xml
index 42399bc..5422218 100644
--- a/engine/storage/volume/pom.xml
+++ b/engine/storage/volume/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index 5e0eb75..7132d61 100644
--- a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@ -725,7 +725,6 @@
VolumeApiResult res = new VolumeApiResult(volumeInfo);
if (result.isSuccess()) {
- // volumeInfo.processEvent(Event.OperationSucceeded, result.getAnswer());
VolumeVO volume = volDao.findById(volumeInfo.getId());
CopyCmdAnswer answer = (CopyCmdAnswer)result.getAnswer();
diff --git a/engine/userdata/cloud-init/pom.xml b/engine/userdata/cloud-init/pom.xml
index 2b5d559..a49a8ec 100644
--- a/engine/userdata/cloud-init/pom.xml
+++ b/engine/userdata/cloud-init/pom.xml
@@ -23,7 +23,7 @@
<parent>
<artifactId>cloud-engine</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/userdata/pom.xml b/engine/userdata/pom.xml
index 0018258..56c181a 100644
--- a/engine/userdata/pom.xml
+++ b/engine/userdata/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/agent-lb/pom.xml b/framework/agent-lb/pom.xml
index cba750d..b9d728f 100644
--- a/framework/agent-lb/pom.xml
+++ b/framework/agent-lb/pom.xml
@@ -24,7 +24,7 @@
<parent>
<artifactId>cloudstack-framework</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
</project>
diff --git a/framework/ca/pom.xml b/framework/ca/pom.xml
index e7d85c0..b090dbe 100644
--- a/framework/ca/pom.xml
+++ b/framework/ca/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
</project>
diff --git a/framework/cluster/pom.xml b/framework/cluster/pom.xml
index da3de5e..2dd28e8 100644
--- a/framework/cluster/pom.xml
+++ b/framework/cluster/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/config/pom.xml b/framework/config/pom.xml
index 9fbbc4a..dea2f14 100644
--- a/framework/config/pom.xml
+++ b/framework/config/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigKeyScheduledExecutionWrapper.java b/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigKeyScheduledExecutionWrapper.java
index b8d7e78..a02ee8a 100644
--- a/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigKeyScheduledExecutionWrapper.java
+++ b/framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigKeyScheduledExecutionWrapper.java
@@ -66,7 +66,7 @@
this.unit = unit;
}
- protected ConfigKeyScheduledExecutionWrapper(ScheduledExecutorService executorService, Runnable command,
+ public ConfigKeyScheduledExecutionWrapper(ScheduledExecutorService executorService, Runnable command,
ConfigKey<?> configKey, int enableIntervalSeconds, TimeUnit unit) {
validateArgs(executorService, command, configKey);
this.executorService = executorService;
diff --git a/framework/db/pom.xml b/framework/db/pom.xml
index c03fb06..ced0f64 100644
--- a/framework/db/pom.xml
+++ b/framework/db/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -53,8 +53,8 @@
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
+ <groupId>com.mysql</groupId>
+ <artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
diff --git a/framework/db/src/main/java/com/cloud/utils/db/GlobalLock.java b/framework/db/src/main/java/com/cloud/utils/db/GlobalLock.java
index 523f90b..b01ddaf 100644
--- a/framework/db/src/main/java/com/cloud/utils/db/GlobalLock.java
+++ b/framework/db/src/main/java/com/cloud/utils/db/GlobalLock.java
@@ -27,22 +27,23 @@
import com.cloud.utils.Profiler;
-//
-// Wrapper class for global database lock to reduce contention for database connections from within process
-//
-// Example of using dynamic named locks
-//
-// GlobalLock lock = GlobalLock.getInternLock("some table name" + rowId);
-//
-// if(lock.lock()) {
-// try {
-// do something
-// } finally {
-// lock.unlock();
-// }
-// }
-// lock.releaseRef();
-//
+/**
+ * Wrapper class for global database lock to reduce contention for database connections from within process
+ * This class is used to acquire a global lock for a specific operation, identified by a unique name.
+ * Example of using dynamic named locks
+ * <p>
+ * GlobalLock lock = GlobalLock.getInternLock("some table name" + rowId);
+ *
+ * if(lock.lock()) {
+ * try {
+ * do something
+ * } finally {
+ * lock.unlock();
+ * }
+ * }
+ * lock.releaseRef();
+ * </p>
+ */
public class GlobalLock {
protected Logger logger = LogManager.getLogger(getClass());
diff --git a/framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java b/framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java
index 18a9074..42a8b27 100644
--- a/framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java
+++ b/framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java
@@ -29,6 +29,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import javax.sql.DataSource;
@@ -56,14 +57,12 @@
/**
* Transaction abstracts away the Connection object in JDBC. It allows the
* following things that the Connection object does not.
- *
* 1. Transaction can be started at an entry point and whether the DB
* actions should be auto-commit or not determined at that point.
* 2. DB Connection is allocated only when it is needed.
* 3. Code does not need to know if a transaction has been started or not.
* It just starts/ends a transaction and we resolve it correctly with
* the previous actions.
- *
* Note that this class is not synchronous but it doesn't need to be because
* it is stored with TLS and is one per thread. Use appropriately.
*/
@@ -73,7 +72,7 @@
protected Logger lockLogger = LogManager.getLogger(Transaction.class.getName() + "." + "Lock");
protected static Logger CONN_LOGGER = LogManager.getLogger(Transaction.class.getName() + "." + "Connection");
- private static final ThreadLocal<TransactionLegacy> tls = new ThreadLocal<TransactionLegacy>();
+ private static final ThreadLocal<TransactionLegacy> tls = new ThreadLocal<>();
private static final String START_TXN = "start_txn";
private static final String CURRENT_TXN = "current_txn";
private static final String CREATE_TXN = "create_txn";
@@ -103,7 +102,7 @@
private final LinkedList<StackElement> _stack;
private long _id;
- private final LinkedList<Pair<String, Long>> _lockTimes = new LinkedList<Pair<String, Long>>();
+ private final LinkedList<Pair<String, Long>> _lockTimes = new LinkedList<>();
private String _name;
private Connection _conn;
@@ -160,7 +159,7 @@
TransactionLegacy txn = tls.get();
if (txn == null) {
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Creating the transaction: " + name);
+ LOGGER.trace("Creating the transaction: {}", name);
}
txn = new TransactionLegacy(name, false, databaseId);
tls.set(txn);
@@ -206,7 +205,7 @@
public void registerLock(String sql) {
if (_txn && lockLogger.isDebugEnabled()) {
- Pair<String, Long> time = new Pair<String, Long>(sql, System.currentTimeMillis());
+ Pair<String, Long> time = new Pair<>(sql, System.currentTimeMillis());
_lockTimes.add(time);
}
}
@@ -218,7 +217,7 @@
public static Connection getStandaloneConnectionWithException() throws SQLException {
Connection conn = s_ds.getConnection();
if (CONN_LOGGER.isTraceEnabled()) {
- CONN_LOGGER.trace("Retrieving a standalone connection: dbconn" + System.identityHashCode(conn));
+ CONN_LOGGER.trace("Retrieving a standalone connection: dbconn{}", System.identityHashCode(conn));
}
return conn;
}
@@ -236,7 +235,7 @@
try {
Connection conn = s_usageDS.getConnection();
if (CONN_LOGGER.isTraceEnabled()) {
- CONN_LOGGER.trace("Retrieving a standalone connection for usage: dbconn" + System.identityHashCode(conn));
+ CONN_LOGGER.trace("Retrieving a standalone connection for usage: dbconn{}", System.identityHashCode(conn));
}
return conn;
} catch (SQLException e) {
@@ -249,7 +248,7 @@
try {
Connection conn = s_simulatorDS.getConnection();
if (CONN_LOGGER.isTraceEnabled()) {
- CONN_LOGGER.trace("Retrieving a standalone connection for simulator: dbconn" + System.identityHashCode(conn));
+ CONN_LOGGER.trace("Retrieving a standalone connection for simulator: dbconn{}", System.identityHashCode(conn));
}
return conn;
} catch (SQLException e) {
@@ -266,7 +265,7 @@
Iterator<StackElement> it = _stack.descendingIterator();
while (it.hasNext()) {
StackElement element = it.next();
- if (element.type == ATTACHMENT) {
+ if (Objects.equals(element.type, ATTACHMENT)) {
TransactionAttachment att = (TransactionAttachment)element.ref;
if (name.equals(att.getName())) {
it.remove();
@@ -308,7 +307,7 @@
}
// relax stack structure for several places that @DB required injection is not in place
- LOGGER.warn("Non-standard stack context that Transaction context is manaully placed into the calling chain. Stack chain: " + sb);
+ LOGGER.warn("Non-standard stack context that Transaction context is manaully placed into the calling chain. Stack chain: {}", sb);
return true;
}
@@ -344,7 +343,7 @@
private TransactionLegacy(final String name, final boolean forLocking, final short databaseId) {
_name = name;
_conn = null;
- _stack = new LinkedList<StackElement>();
+ _stack = new LinkedList<>();
_txn = false;
_dbId = databaseId;
_id = s_id.incrementAndGet();
@@ -372,7 +371,7 @@
final StringBuilder str = new StringBuilder((_name != null ? _name : ""));
str.append(" : ");
for (final StackElement se : _stack) {
- if (se.type == CURRENT_TXN) {
+ if (Objects.equals(se.type, CURRENT_TXN)) {
str.append(se.ref).append(", ");
}
}
@@ -406,7 +405,7 @@
@Deprecated
public void start() {
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("txn: start requested by: " + buildName());
+ LOGGER.trace("txn: start requested by: {}", buildName());
}
_stack.push(new StackElement(START_TXN, null));
@@ -434,7 +433,7 @@
if (_stmt != null) {
try {
if (stmtLogger.isTraceEnabled()) {
- stmtLogger.trace("Closing: " + _stmt.toString());
+ stmtLogger.trace("Closing: {}", _stmt.toString());
}
try {
ResultSet rs = _stmt.getResultSet();
@@ -446,7 +445,7 @@
}
_stmt.close();
} catch (final SQLException e) {
- stmtLogger.trace("Unable to close statement: " + _stmt.toString());
+ stmtLogger.trace("Unable to close statement: {}", _stmt.toString());
} finally {
_stmt = null;
}
@@ -474,7 +473,7 @@
final Connection conn = getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql);
if (stmtLogger.isTraceEnabled()) {
- stmtLogger.trace("Preparing: " + sql);
+ stmtLogger.trace("Preparing: {}", sql);
}
return pstmt;
}
@@ -494,7 +493,7 @@
final Connection conn = getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql, autoGeneratedKeys);
if (stmtLogger.isTraceEnabled()) {
- stmtLogger.trace("Preparing: " + sql);
+ stmtLogger.trace("Preparing: {}", sql);
}
closePreviousStatement();
_stmt = pstmt;
@@ -516,7 +515,7 @@
final Connection conn = getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql, columnNames);
if (stmtLogger.isTraceEnabled()) {
- stmtLogger.trace("Preparing: " + sql);
+ stmtLogger.trace("Preparing: {}", sql);
}
closePreviousStatement();
_stmt = pstmt;
@@ -537,7 +536,7 @@
final Connection conn = getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
if (stmtLogger.isTraceEnabled()) {
- stmtLogger.trace("Preparing: " + sql);
+ stmtLogger.trace("Preparing: {}", sql);
}
closePreviousStatement();
_stmt = pstmt;
@@ -546,7 +545,6 @@
/**
* Returns the db connection.
- *
* Note: that you can call getConnection() but beaware that
* all prepare statements from the Connection are not garbage
* collected!
@@ -595,8 +593,7 @@
//
_stack.push(new StackElement(CREATE_CONN, null));
if (CONN_LOGGER.isTraceEnabled()) {
- CONN_LOGGER.trace("Creating a DB connection with " + (_txn ? " txn: " : " no txn: ") + " for " + _dbId + ": dbconn" + System.identityHashCode(_conn) +
- ". Stack: " + buildName());
+ CONN_LOGGER.trace("Creating a DB connection with {} for {}: dbconn{}. Stack: {}", _txn ? " txn: " : " no txn: ", _dbId, System.identityHashCode(_conn), buildName());
}
} else {
LOGGER.trace("conn: Using existing DB connection");
@@ -615,33 +612,33 @@
}
protected boolean takeOver(final String name, final boolean create) {
- if (_stack.size() != 0) {
+ if (!_stack.isEmpty()) {
if (!create) {
// If it is not a create transaction, then let's just use the current one.
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Using current transaction: " + toString());
+ LOGGER.trace("Using current transaction: {}", this);
}
mark(name);
return false;
}
final StackElement se = _stack.getFirst();
- if (se.type == CREATE_TXN) {
+ if (Objects.equals(se.type, CREATE_TXN)) {
// This create is called inside of another create. Which is ok?
// We will let that create be responsible for cleaning up.
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Create using current transaction: " + toString());
+ LOGGER.trace("Create using current transaction: {}", this);
}
mark(name);
return false;
}
- LOGGER.warn("Encountered a transaction that has leaked. Cleaning up. " + toString());
+ LOGGER.warn("Encountered a transaction that has leaked. Cleaning up. {}", this);
cleanup();
}
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Took over the transaction: " + name);
+ LOGGER.trace("Took over the transaction: {}", name);
}
_stack.push(new StackElement(create ? CREATE_TXN : CURRENT_TXN, name));
_name = name;
@@ -671,7 +668,7 @@
public void close() {
removeUpTo(CURRENT_TXN, null);
- if (_stack.size() == 0) {
+ if (_stack.isEmpty()) {
LOGGER.trace("Transaction is done");
cleanup();
}
@@ -687,7 +684,7 @@
public boolean close(final String name) {
if (_name == null) { // Already cleaned up.
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Already cleaned up." + buildName());
+ LOGGER.trace("Already cleaned up.{}", buildName());
}
return true;
}
@@ -698,7 +695,7 @@
}
if (LOGGER.isDebugEnabled() && _stack.size() > 2) {
- LOGGER.debug("Transaction is not closed properly: " + toString() + ". Called by " + buildName());
+ LOGGER.debug("Transaction is not closed properly: {}. Called by {}", this, buildName());
}
cleanup();
@@ -714,7 +711,7 @@
protected void clearLockTimes() {
if (lockLogger.isDebugEnabled()) {
for (Pair<String, Long> time : _lockTimes) {
- lockLogger.trace("SQL " + time.first() + " took " + (System.currentTimeMillis() - time.second()));
+ lockLogger.trace("SQL {} took {}", time.first(), System.currentTimeMillis() - time.second());
}
_lockTimes.clear();
}
@@ -722,14 +719,14 @@
public boolean commit() {
if (!_txn) {
- LOGGER.warn("txn: Commit called when it is not a transaction: " + buildName());
+ LOGGER.warn("txn: Commit called when it is not a transaction: {}", buildName());
return false;
}
Iterator<StackElement> it = _stack.iterator();
while (it.hasNext()) {
StackElement st = it.next();
- if (st.type == START_TXN) {
+ if (Objects.equals(st.type, START_TXN)) {
it.remove();
break;
}
@@ -737,7 +734,7 @@
if (hasTxnInStack()) {
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("txn: Not committing because transaction started elsewhere: " + buildName() + " / " + toString());
+ LOGGER.trace("txn: Not committing because transaction started elsewhere: {} / {}", buildName(), this);
}
return false;
}
@@ -746,7 +743,7 @@
try {
if (_conn != null) {
_conn.commit();
- LOGGER.trace("txn: DB Changes committed. Time = " + (System.currentTimeMillis() - _txnTime));
+ LOGGER.trace("txn: DB Changes committed. Time = {}", System.currentTimeMillis() - _txnTime);
clearLockTimes();
closeConnection();
}
@@ -773,7 +770,7 @@
// we should only close db connection when it is not user managed
if (_dbId != CONNECTED_DB) {
if (CONN_LOGGER.isTraceEnabled()) {
- CONN_LOGGER.trace("Closing DB connection: dbconn" + System.identityHashCode(_conn));
+ CONN_LOGGER.trace("Closing DB connection: dbconn{}", System.identityHashCode(_conn));
}
_conn.close();
_conn = null;
@@ -797,13 +794,13 @@
break;
}
- if (item.type == CURRENT_TXN) {
+ if (Objects.equals(item.type, CURRENT_TXN)) {
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Releasing the current txn: " + (item.ref != null ? item.ref : ""));
+ LOGGER.trace("Releasing the current txn: {}", item.ref != null ? item.ref : "");
}
- } else if (item.type == CREATE_CONN) {
+ } else if (Objects.equals(item.type, CREATE_CONN)) {
closeConnection();
- } else if (item.type == START_TXN) {
+ } else if (Objects.equals(item.type, START_TXN)) {
if (item.ref == null) {
rollback = true;
} else {
@@ -814,10 +811,10 @@
LOGGER.warn("Unable to rollback Txn.", e);
}
}
- } else if (item.type == STATEMENT) {
+ } else if (Objects.equals(item.type, STATEMENT)) {
try {
if (stmtLogger.isTraceEnabled()) {
- stmtLogger.trace("Closing: " + ref.toString());
+ stmtLogger.trace("Closing: {}", ref.toString());
}
Statement stmt = (Statement)ref;
try {
@@ -830,17 +827,17 @@
}
stmt.close();
} catch (final SQLException e) {
- stmtLogger.trace("Unable to close statement: " + item);
+ stmtLogger.trace("Unable to close statement: {}", item);
}
- } else if (item.type == ATTACHMENT) {
+ } else if (Objects.equals(item.type, ATTACHMENT)) {
TransactionAttachment att = (TransactionAttachment)item.ref;
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Cleaning up " + att.getName());
+ LOGGER.trace("Cleaning up {}", att.getName());
}
att.cleanup();
}
} catch (Exception e) {
- LOGGER.error("Unable to clean up " + item, e);
+ LOGGER.error("Unable to clean up {}", item, e);
}
}
@@ -853,7 +850,7 @@
closePreviousStatement();
if (!_txn) {
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Rollback called for " + _name + " when there's no transaction: " + buildName());
+ LOGGER.trace("Rollback called for {} when there's no transaction: {}", _name, buildName());
}
return;
}
@@ -862,7 +859,7 @@
try {
if (_conn != null) {
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Rolling back the transaction: Time = " + (System.currentTimeMillis() - _txnTime) + " Name = " + _name + "; called by " + buildName());
+ LOGGER.debug("Rolling back the transaction: Time = {} Name = {}; called by {}", System.currentTimeMillis() - _txnTime, _name, buildName());
}
_conn.rollback();
}
@@ -879,7 +876,7 @@
_conn.rollback(sp);
}
} catch (SQLException e) {
- LOGGER.warn("Unable to rollback to savepoint " + sp);
+ LOGGER.warn("Unable to rollback to savepoint {}", sp);
}
if (!hasTxnInStack()) {
@@ -892,7 +889,7 @@
Iterator<StackElement> it = _stack.iterator();
while (it.hasNext()) {
StackElement st = it.next();
- if (st.type == START_TXN) {
+ if (Objects.equals(st.type, START_TXN)) {
if (st.ref == null) {
it.remove();
} else {
@@ -943,7 +940,7 @@
Iterator<StackElement> it = _stack.iterator();
while (it.hasNext()) {
StackElement se = it.next();
- if (se.type == START_TXN && se.ref == sp) {
+ if (Objects.equals(se.type, START_TXN) && se.ref == sp) {
return true;
}
}
@@ -960,7 +957,7 @@
Iterator<StackElement> it = _stack.iterator();
while (it.hasNext()) {
StackElement se = it.next();
- if (se.type == START_TXN) {
+ if (Objects.equals(se.type, START_TXN)) {
it.remove();
if (se.ref == sp) {
return;
@@ -993,7 +990,7 @@
@Override
protected void finalize() throws Throwable {
- if (!(_conn == null && (_stack == null || _stack.size() == 0))) {
+ if (!(_conn == null && (_stack == null || _stack.isEmpty()))) {
assert (false) : "Oh Alex oh alex...something is wrong with how we're doing this";
LOGGER.error("Something went wrong that a transaction is orphaned before db connection is closed");
cleanup();
@@ -1052,11 +1049,11 @@
@SuppressWarnings({"rawtypes", "unchecked"})
public static void initDataSource(Properties dbProps) {
try {
- if (dbProps.size() == 0)
+ if (dbProps.isEmpty())
return;
- s_dbHAEnabled = Boolean.valueOf(dbProps.getProperty("db.ha.enabled"));
- LOGGER.info("Is Data Base High Availiability enabled? Ans : " + s_dbHAEnabled);
+ s_dbHAEnabled = Boolean.parseBoolean(dbProps.getProperty("db.ha.enabled"));
+ LOGGER.info("Is Data Base High Availiability enabled? Ans : {}", s_dbHAEnabled);
String loadBalanceStrategy = dbProps.getProperty("db.ha.loadBalanceStrategy");
// FIXME: If params are missing...default them????
final Integer cloudMaxActive = parseNumber(dbProps.getProperty("db.cloud.maxActive"), Integer.class);
@@ -1082,7 +1079,7 @@
} else if (cloudIsolationLevel.equalsIgnoreCase("readuncommitted")) {
isolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
} else {
- LOGGER.warn("Unknown isolation level " + cloudIsolationLevel + ". Using read uncommitted");
+ LOGGER.warn("Unknown isolation level {}. Using read uncommitted", cloudIsolationLevel);
}
final boolean cloudTestOnBorrow = Boolean.parseBoolean(dbProps.getProperty("db.cloud.testOnBorrow"));
@@ -1190,16 +1187,16 @@
driver = dbProps.getProperty(String.format("db.%s.driver", schema));
connectionUri = getPropertiesAndBuildConnectionUri(dbProps, loadBalanceStrategy, driver, useSSL, schema);
} else {
- LOGGER.warn(String.format("db.%s.uri was set, ignoring the following properties for schema %s of db.properties: [host, port, name, driver, autoReconnect, url.params,"
+ LOGGER.warn("db.{}.uri was set, ignoring the following properties for schema {} of db.properties: [host, port, name, driver, autoReconnect, url.params,"
+ " replicas, ha.loadBalanceStrategy, ha.enable, failOverReadOnly, reconnectAtTxEnd, autoReconnectForPools, secondsBeforeRetrySource, queriesBeforeRetrySource, "
- + "initialTimeout].", schema, schema));
+ + "initialTimeout].", schema, schema);
String[] splitUri = propertyUri.split(":");
driver = String.format("%s:%s", splitUri[0], splitUri[1]);
connectionUri = propertyUri;
}
- LOGGER.info(String.format("Using the following URI to connect to %s database [%s].", schema, connectionUri));
+ LOGGER.info("Using the following URI to connect to {} database [{}].", schema, connectionUri);
return new Pair<>(connectionUri, driver);
}
@@ -1215,7 +1212,7 @@
if (s_dbHAEnabled) {
dbHaParams = getDBHAParams(schema, dbProps);
replicas = dbProps.getProperty(String.format("db.%s.replicas", schema));
- LOGGER.info(String.format("The replicas configured for %s data base are %s.", schema, replicas));
+ LOGGER.info("The replicas configured for {} data base are {}.", schema, replicas);
}
return buildConnectionUri(loadBalanceStrategy, driver, useSSL, host, replicas, port, dbName, autoReconnect, urlParams, dbHaParams);
@@ -1322,8 +1319,7 @@
config.addDataSourceProperty("elideSetAutoCommits", "true");
config.addDataSourceProperty("maintainTimeStats", "false");
- HikariDataSource dataSource = new HikariDataSource(config);
- return dataSource;
+ return new HikariDataSource(config);
}
private static DataSource createDbcpDataSource(String uri, String username, String password,
@@ -1411,19 +1407,19 @@
private static String getDBHAParams(String dbName, Properties dbProps) {
StringBuilder sb = new StringBuilder();
- sb.append("failOverReadOnly=" + dbProps.getProperty("db." + dbName + ".failOverReadOnly"));
- sb.append("&").append("reconnectAtTxEnd=" + dbProps.getProperty("db." + dbName + ".reconnectAtTxEnd"));
- sb.append("&").append("autoReconnectForPools=" + dbProps.getProperty("db." + dbName + ".autoReconnectForPools"));
- sb.append("&").append("secondsBeforeRetrySource=" + dbProps.getProperty("db." + dbName + ".secondsBeforeRetrySource"));
- sb.append("&").append("queriesBeforeRetrySource=" + dbProps.getProperty("db." + dbName + ".queriesBeforeRetrySource"));
- sb.append("&").append("initialTimeout=" + dbProps.getProperty("db." + dbName + ".initialTimeout"));
+ sb.append("failOverReadOnly=").append(dbProps.getProperty("db." + dbName + ".failOverReadOnly"));
+ sb.append("&").append("reconnectAtTxEnd=").append(dbProps.getProperty("db." + dbName + ".reconnectAtTxEnd"));
+ sb.append("&").append("autoReconnectForPools=").append(dbProps.getProperty("db." + dbName + ".autoReconnectForPools"));
+ sb.append("&").append("secondsBeforeRetrySource=").append(dbProps.getProperty("db." + dbName + ".secondsBeforeRetrySource"));
+ sb.append("&").append("queriesBeforeRetrySource=").append(dbProps.getProperty("db." + dbName + ".queriesBeforeRetrySource"));
+ sb.append("&").append("initialTimeout=").append(dbProps.getProperty("db." + dbName + ".initialTimeout"));
return sb.toString();
}
/**
* Used for unit testing primarily
*
- * @param conn
+ * @param conn connection to use
*/
protected void setConnection(Connection conn) {
_conn = conn;
@@ -1433,7 +1429,7 @@
* Receives a list of {@link PreparedStatement} and quietly closes all of them, which
* triggers also closing their dependent objects, like a {@link ResultSet}
*
- * @param pstmt2Close
+ * @param pstmt2Close list of PreparedStatement to close
*/
public static void closePstmts(List<PreparedStatement> pstmt2Close) {
for (PreparedStatement pstmt : pstmt2Close) {
diff --git a/framework/db/src/test/java/com/cloud/utils/db/TransactionContextBuilderTest.java b/framework/db/src/test/java/com/cloud/utils/db/TransactionContextBuilderTest.java
index a0f7c80..3ec635c 100644
--- a/framework/db/src/test/java/com/cloud/utils/db/TransactionContextBuilderTest.java
+++ b/framework/db/src/test/java/com/cloud/utils/db/TransactionContextBuilderTest.java
@@ -41,9 +41,6 @@
@Test
public void test() {
- // _derived.DbAnnotatedMethod();
- // _base.MethodWithClassDbAnnotated();
-
// test @DB injection on dynamically constructed objects
DbAnnotatedBase base = ComponentContext.inject(new DbAnnotatedBase());
base.MethodWithClassDbAnnotated();
diff --git a/framework/direct-download/pom.xml b/framework/direct-download/pom.xml
index 913bef0..22e8781 100644
--- a/framework/direct-download/pom.xml
+++ b/framework/direct-download/pom.xml
@@ -32,7 +32,7 @@
<parent>
<artifactId>cloudstack-framework</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
</project>
diff --git a/framework/events/pom.xml b/framework/events/pom.xml
index 173b18a..3a0d374 100644
--- a/framework/events/pom.xml
+++ b/framework/events/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/extensions/pom.xml b/framework/extensions/pom.xml
index 7695255..4d42d68 100644
--- a/framework/extensions/pom.xml
+++ b/framework/extensions/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -41,13 +41,13 @@
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-schema</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-components-api</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
diff --git a/framework/ipc/pom.xml b/framework/ipc/pom.xml
index 0d13898..d9fa9d8 100644
--- a/framework/ipc/pom.xml
+++ b/framework/ipc/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/ipc/src/test/java/org/apache/cloudstack/framework/codestyle/AsyncSampleEventDrivenStyleCaller.java b/framework/ipc/src/test/java/org/apache/cloudstack/framework/codestyle/AsyncSampleEventDrivenStyleCaller.java
index 164852a..0d8ddcf 100644
--- a/framework/ipc/src/test/java/org/apache/cloudstack/framework/codestyle/AsyncSampleEventDrivenStyleCaller.java
+++ b/framework/ipc/src/test/java/org/apache/cloudstack/framework/codestyle/AsyncSampleEventDrivenStyleCaller.java
@@ -20,6 +20,8 @@
import java.util.concurrent.ExecutionException;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -36,6 +38,7 @@
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/SampleManagementServerAppContext.xml")
public class AsyncSampleEventDrivenStyleCaller {
+ protected Logger logger = LogManager.getLogger(getClass());
private AsyncSampleCallee _ds;
AsyncCallbackDriver _callbackDriver;
@@ -53,12 +56,8 @@
try {
String result = future.get();
Assert.assertEquals(result, vol);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ExecutionException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ } catch (InterruptedException | ExecutionException e) {
+ logger.info(e);
}
}
@@ -87,10 +86,8 @@
if (!this.finished) {
try {
this.wait();
-
} catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ logger.info(e);
}
}
return this.result;
diff --git a/framework/jobs/pom.xml b/framework/jobs/pom.xml
index f324972..ad342ac 100644
--- a/framework/jobs/pom.xml
+++ b/framework/jobs/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobJoinMapDaoImpl.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobJoinMapDaoImpl.java
index da7ba36..09a8893 100644
--- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobJoinMapDaoImpl.java
+++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobJoinMapDaoImpl.java
@@ -44,8 +44,6 @@
private final SearchBuilder<AsyncJobJoinMapVO> CompleteJoinSearch;
private final SearchBuilder<AsyncJobJoinMapVO> WakeupSearch;
-// private final GenericSearchBuilder<AsyncJobJoinMapVO, Long> JoinJobSearch;
-
protected AsyncJobJoinMapDaoImpl() {
RecordSearch = createSearchBuilder();
RecordSearch.and("jobId", RecordSearch.entity().getJobId(), Op.EQ);
@@ -65,10 +63,6 @@
WakeupSearch.and("expiration", WakeupSearch.entity().getExpiration(), Op.GT);
WakeupSearch.and("joinStatus", WakeupSearch.entity().getJoinStatus(), Op.EQ);
WakeupSearch.done();
-
-// JoinJobSearch = createSearchBuilder(Long.class);
-// JoinJobSearch.and(JoinJobSearch.entity().getJoinJobId(), Op.SC, "joinJobId");
-// JoinJobSearch.done();
}
@Override
@@ -148,64 +142,6 @@
update(ub, sc, null);
}
-// @Override
-// public List<Long> wakeupScan() {
-// List<Long> standaloneList = new ArrayList<Long>();
-//
-// Date cutDate = DateUtil.currentGMTTime();
-//
-// TransactionLegacy txn = TransactionLegacy.currentTxn();
-// PreparedStatement pstmt = null;
-// try {
-// txn.start();
-//
-// //
-// // performance sensitive processing, do it in plain SQL
-// //
-// String sql = "UPDATE async_job SET job_pending_signals=? WHERE id IN " +
-// "(SELECT job_id FROM async_job_join_map WHERE next_wakeup < ? AND expiration > ?)";
-// pstmt = txn.prepareStatement(sql);
-// pstmt.setInt(1, AsyncJob.Constants.SIGNAL_MASK_WAKEUP);
-// pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate));
-// pstmt.setString(3, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate));
-// pstmt.executeUpdate();
-// pstmt.close();
-//
-// sql = "UPDATE sync_queue_item SET queue_proc_msid=NULL, queue_proc_number=NULL WHERE content_id IN " +
-// "(SELECT job_id FROM async_job_join_map WHERE next_wakeup < ? AND expiration > ?)";
-// pstmt = txn.prepareStatement(sql);
-// pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate));
-// pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate));
-// pstmt.executeUpdate();
-// pstmt.close();
-//
-// sql = "SELECT job_id FROM async_job_join_map WHERE next_wakeup < ? AND expiration > ? AND job_id NOT IN (SELECT content_id FROM sync_queue_item)";
-// pstmt = txn.prepareStatement(sql);
-// pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate));
-// pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate));
-// ResultSet rs = pstmt.executeQuery();
-// while(rs.next()) {
-// standaloneList.add(rs.getLong(1));
-// }
-// rs.close();
-// pstmt.close();
-//
-// // update for next wake-up
-// sql = "UPDATE async_job_join_map SET next_wakeup=DATE_ADD(next_wakeup, INTERVAL wakeup_interval SECOND) WHERE next_wakeup < ? AND expiration > ?";
-// pstmt = txn.prepareStatement(sql);
-// pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate));
-// pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutDate));
-// pstmt.executeUpdate();
-// pstmt.close();
-//
-// txn.commit();
-// } catch (SQLException e) {
-// logger.error("Unexpected exception", e);
-// }
-//
-// return standaloneList;
-// }
-
@Override
public List<Long> findJobsToWake(long joinedJobId) {
// TODO: We should fix this. We shouldn't be crossing daos in a dao code.
diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/JobSerializerHelper.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/JobSerializerHelper.java
index fa1d175..66df954 100644
--- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/JobSerializerHelper.java
+++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/JobSerializerHelper.java
@@ -193,7 +193,6 @@
json.add("class", new JsonPrimitive(th.getClass().getName()));
json.add("cause", s_gson.toJsonTree(th.getCause()));
json.add("msg", new JsonPrimitive(th.getMessage()));
-// json.add("stack", s_gson.toJsonTree(th.getStackTrace()));
return json;
}
diff --git a/framework/managed-context/pom.xml b/framework/managed-context/pom.xml
index c095085..70f20ec 100644
--- a/framework/managed-context/pom.xml
+++ b/framework/managed-context/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/pom.xml b/framework/pom.xml
index 02ce0a0..337e5b0 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<build>
<plugins>
diff --git a/framework/quota/pom.xml b/framework/quota/pom.xml
index 52f0d65..70cb3ac 100644
--- a/framework/quota/pom.xml
+++ b/framework/quota/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/rest/pom.xml b/framework/rest/pom.xml
index bb69f90..e2e787a 100644
--- a/framework/rest/pom.xml
+++ b/framework/rest/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>cloud-framework-rest</artifactId>
diff --git a/framework/security/pom.xml b/framework/security/pom.xml
index a36978e..30940b6 100644
--- a/framework/security/pom.xml
+++ b/framework/security/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/spring/lifecycle/pom.xml b/framework/spring/lifecycle/pom.xml
index ff6b595..90a26a7 100644
--- a/framework/spring/lifecycle/pom.xml
+++ b/framework/spring/lifecycle/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/spring/module/pom.xml b/framework/spring/module/pom.xml
index 77a9646..f44cffa 100644
--- a/framework/spring/module/pom.xml
+++ b/framework/spring/module/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/acl/dynamic-role-based/pom.xml b/plugins/acl/dynamic-role-based/pom.xml
index f975afc..0b0b230 100644
--- a/plugins/acl/dynamic-role-based/pom.xml
+++ b/plugins/acl/dynamic-role-based/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/acl/project-role-based/pom.xml b/plugins/acl/project-role-based/pom.xml
index ae00e85..2c351bd 100644
--- a/plugins/acl/project-role-based/pom.xml
+++ b/plugins/acl/project-role-based/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/acl/static-role-based/pom.xml b/plugins/acl/static-role-based/pom.xml
index ee088e3..c6e790b 100644
--- a/plugins/acl/static-role-based/pom.xml
+++ b/plugins/acl/static-role-based/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/affinity-group-processors/explicit-dedication/pom.xml b/plugins/affinity-group-processors/explicit-dedication/pom.xml
index 1d5b530..769773e 100644
--- a/plugins/affinity-group-processors/explicit-dedication/pom.xml
+++ b/plugins/affinity-group-processors/explicit-dedication/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/affinity-group-processors/host-affinity/pom.xml b/plugins/affinity-group-processors/host-affinity/pom.xml
index f0c13e0..925da93 100644
--- a/plugins/affinity-group-processors/host-affinity/pom.xml
+++ b/plugins/affinity-group-processors/host-affinity/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/affinity-group-processors/host-anti-affinity/pom.xml b/plugins/affinity-group-processors/host-anti-affinity/pom.xml
index 0089537..9b83518 100644
--- a/plugins/affinity-group-processors/host-anti-affinity/pom.xml
+++ b/plugins/affinity-group-processors/host-anti-affinity/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/affinity-group-processors/non-strict-host-affinity/pom.xml b/plugins/affinity-group-processors/non-strict-host-affinity/pom.xml
index fc62628..f0bc9e0 100644
--- a/plugins/affinity-group-processors/non-strict-host-affinity/pom.xml
+++ b/plugins/affinity-group-processors/non-strict-host-affinity/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/affinity-group-processors/non-strict-host-anti-affinity/pom.xml b/plugins/affinity-group-processors/non-strict-host-anti-affinity/pom.xml
index b474f76..b12e49f 100644
--- a/plugins/affinity-group-processors/non-strict-host-anti-affinity/pom.xml
+++ b/plugins/affinity-group-processors/non-strict-host-anti-affinity/pom.xml
@@ -32,7 +32,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/alert-handlers/snmp-alerts/pom.xml b/plugins/alert-handlers/snmp-alerts/pom.xml
index 3beb2ce..ea89037 100644
--- a/plugins/alert-handlers/snmp-alerts/pom.xml
+++ b/plugins/alert-handlers/snmp-alerts/pom.xml
@@ -24,7 +24,7 @@
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/alert-handlers/syslog-alerts/pom.xml b/plugins/alert-handlers/syslog-alerts/pom.xml
index 5241ec0..a4ae4f08 100644
--- a/plugins/alert-handlers/syslog-alerts/pom.xml
+++ b/plugins/alert-handlers/syslog-alerts/pom.xml
@@ -24,7 +24,7 @@
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/api/discovery/pom.xml b/plugins/api/discovery/pom.xml
index 525a558..b0f2961 100644
--- a/plugins/api/discovery/pom.xml
+++ b/plugins/api/discovery/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/api/discovery/src/main/java/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java b/plugins/api/discovery/src/main/java/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java
index 4b243f2..90b3b89 100644
--- a/plugins/api/discovery/src/main/java/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java
+++ b/plugins/api/discovery/src/main/java/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java
@@ -59,6 +59,10 @@
@Param(description = "Response field type")
private String type;
+ @SerializedName(ApiConstants.HTTP_REQUEST_TYPE)
+ @Param(description = "Preferred HTTP request type for the API", since = "4.23.0")
+ private String httpRequestType;
+
public ApiDiscoveryResponse() {
params = new HashSet<ApiParameterResponse>();
apiResponse = new HashSet<ApiResponseResponse>();
@@ -74,6 +78,7 @@
this.params = new HashSet<>(another.getParams());
this.apiResponse = new HashSet<>(another.getApiResponse());
this.type = another.getType();
+ this.httpRequestType = another.getHttpRequestType();
this.setObjectName(another.getObjectName());
}
@@ -140,4 +145,12 @@
public String getType() {
return type;
}
+
+ public String getHttpRequestType() {
+ return httpRequestType;
+ }
+
+ public void setHttpRequestType(String httpRequestType) {
+ this.httpRequestType = httpRequestType;
+ }
}
diff --git a/plugins/api/discovery/src/main/java/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java b/plugins/api/discovery/src/main/java/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java
index 452b95c..d6d2351 100644
--- a/plugins/api/discovery/src/main/java/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java
+++ b/plugins/api/discovery/src/main/java/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java
@@ -50,6 +50,7 @@
import org.reflections.ReflectionUtils;
import org.springframework.stereotype.Component;
+import com.cloud.api.ApiServlet;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.serializer.Param;
import com.cloud.user.Account;
@@ -189,7 +190,7 @@
return responseResponse;
}
- private ApiDiscoveryResponse getCmdRequestMap(Class<?> cmdClass, APICommand apiCmdAnnotation) {
+ protected ApiDiscoveryResponse getCmdRequestMap(Class<?> cmdClass, APICommand apiCmdAnnotation) {
String apiName = apiCmdAnnotation.name();
ApiDiscoveryResponse response = new ApiDiscoveryResponse();
response.setName(apiName);
@@ -197,6 +198,12 @@
if (!apiCmdAnnotation.since().isEmpty()) {
response.setSince(apiCmdAnnotation.since());
}
+ String httpRequestType = apiCmdAnnotation.httpMethod();
+ if (StringUtils.isBlank(httpRequestType)) {
+ httpRequestType = ApiServlet.GET_REQUEST_COMMANDS.matcher(apiName.toLowerCase()).matches() ?
+ "GET" : "POST";
+ }
+ response.setHttpRequestType(httpRequestType);
Set<Field> fields = ReflectUtil.getAllFieldsForClass(cmdClass, new Class<?>[] {BaseCmd.class, BaseAsyncCmd.class, BaseAsyncCreateCmd.class});
diff --git a/plugins/api/discovery/src/test/java/org/apache/cloudstack/discovery/ApiDiscoveryServiceImplTest.java b/plugins/api/discovery/src/test/java/org/apache/cloudstack/discovery/ApiDiscoveryServiceImplTest.java
new file mode 100644
index 0000000..e69b952
--- /dev/null
+++ b/plugins/api/discovery/src/test/java/org/apache/cloudstack/discovery/ApiDiscoveryServiceImplTest.java
@@ -0,0 +1,123 @@
+// 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.discovery;
+
+import static org.mockito.ArgumentMatchers.any;
+
+import java.lang.reflect.Field;
+import java.util.Set;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.command.admin.account.CreateAccountCmd;
+import org.apache.cloudstack.api.command.admin.user.GetUserCmd;
+import org.apache.cloudstack.api.command.user.discovery.ListApisCmd;
+import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
+import org.apache.cloudstack.api.response.ApiParameterResponse;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import com.cloud.utils.ReflectUtil;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ApiDiscoveryServiceImplTest {
+
+ @Mock
+ APICommand apiCommandMock;
+
+ @Spy
+ @InjectMocks
+ ApiDiscoveryServiceImpl discoveryServiceSpy;
+
+ @Before
+ public void setUp() {
+ Mockito.when(apiCommandMock.name()).thenReturn("listApis");
+ Mockito.when(apiCommandMock.since()).thenReturn("");
+ }
+
+ @Test
+ public void getCmdRequestMapReturnsResponseWithCorrectApiNameAndDescription() {
+ Mockito.when(apiCommandMock.description()).thenReturn("Lists all APIs");
+ ApiDiscoveryResponse response = discoveryServiceSpy.getCmdRequestMap(ListApisCmd.class, apiCommandMock);
+ Assert.assertEquals("listApis", response.getName());
+ Assert.assertEquals("Lists all APIs", response.getDescription());
+ }
+
+ @Test
+ public void getCmdRequestMapSetsHttpRequestTypeToGetWhenApiNameMatchesGetPattern() {
+ Mockito.when(apiCommandMock.name()).thenReturn("getUser");
+ Mockito.when(apiCommandMock.httpMethod()).thenReturn("");
+ ApiDiscoveryResponse response = discoveryServiceSpy.getCmdRequestMap(GetUserCmd.class, apiCommandMock);
+ Assert.assertEquals("GET", response.getHttpRequestType());
+ }
+
+ @Test
+ public void getCmdRequestMapSetsHttpRequestTypeToPostWhenApiNameDoesNotMatchGetPattern() {
+ Mockito.when(apiCommandMock.name()).thenReturn("createAccount");
+ Mockito.when(apiCommandMock.httpMethod()).thenReturn("");
+ ApiDiscoveryResponse response = discoveryServiceSpy.getCmdRequestMap(CreateAccountCmd.class, apiCommandMock);
+ Assert.assertEquals("POST", response.getHttpRequestType());
+ }
+
+ @Test
+ public void getCmdRequestMapSetsAsyncToTrueForAsyncCommand() {
+ Mockito.when(apiCommandMock.name()).thenReturn("asyncApi");
+ ApiDiscoveryResponse response = discoveryServiceSpy.getCmdRequestMap(BaseAsyncCmd.class, apiCommandMock);
+ Assert.assertTrue(response.getAsync());
+ }
+
+ @Test
+ public void getCmdRequestMapDoesNotAddParamsWithoutParameterAnnotation() {
+ ApiDiscoveryResponse response = discoveryServiceSpy.getCmdRequestMap(BaseCmd.class, apiCommandMock);
+ Assert.assertFalse(response.getParams().isEmpty());
+ Assert.assertEquals(1, response.getParams().size());
+ }
+
+ @Test
+ public void getCmdRequestMapAddsParamsWithExposedAndIncludedInApiDocAnnotations() {
+ Field fieldMock = Mockito.mock(Field.class);
+ Parameter parameterMock = Mockito.mock(Parameter.class);
+ Mockito.when(parameterMock.expose()).thenReturn(true);
+ Mockito.when(parameterMock.includeInApiDoc()).thenReturn(true);
+ Mockito.when(parameterMock.name()).thenReturn("paramName");
+ Mockito.when(parameterMock.since()).thenReturn("");
+ Mockito.when(parameterMock.entityType()).thenReturn(new Class[]{Object.class});
+ Mockito.when(parameterMock.description()).thenReturn("paramDescription");
+ Mockito.when(parameterMock.type()).thenReturn(BaseCmd.CommandType.STRING);
+ Mockito.when(fieldMock.getAnnotation(Parameter.class)).thenReturn(parameterMock);
+ try (MockedStatic<ReflectUtil> reflectUtilMockedStatic = Mockito.mockStatic(ReflectUtil.class)) {
+ reflectUtilMockedStatic.when(() -> ReflectUtil.getAllFieldsForClass(any(Class.class), any(Class[].class)))
+ .thenReturn(Set.of(fieldMock));
+ ApiDiscoveryResponse response = discoveryServiceSpy.getCmdRequestMap(ListApisCmd.class, apiCommandMock);
+ Set<ApiParameterResponse> params = response.getParams();
+ Assert.assertEquals(1, params.size());
+ ApiParameterResponse paramResponse = params.iterator().next();
+ Assert.assertEquals("paramName", ReflectionTestUtils.getField(paramResponse, "name"));
+ }
+ }
+}
diff --git a/plugins/api/rate-limit/pom.xml b/plugins/api/rate-limit/pom.xml
index 4d802ca..294ff18 100644
--- a/plugins/api/rate-limit/pom.xml
+++ b/plugins/api/rate-limit/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<build>
diff --git a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/APITest.java b/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/APITest.java
index efe8c53..eb020c2 100644
--- a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/APITest.java
+++ b/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/APITest.java
@@ -189,7 +189,6 @@
* @return login response string
*/
protected void login(String username, String password) {
- //String md5Psw = createMD5String(password);
// send login request
HashMap<String, String> params = new HashMap<String, String>();
params.put("response", "json");
diff --git a/plugins/api/solidfire-intg-test/pom.xml b/plugins/api/solidfire-intg-test/pom.xml
index ca2a032..0cc9d1a 100644
--- a/plugins/api/solidfire-intg-test/pom.xml
+++ b/plugins/api/solidfire-intg-test/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/api/vmware-sioc/pom.xml b/plugins/api/vmware-sioc/pom.xml
index 10a1853..e523568 100644
--- a/plugins/api/vmware-sioc/pom.xml
+++ b/plugins/api/vmware-sioc/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/backup/dummy/pom.xml b/plugins/backup/dummy/pom.xml
index c15b5dc..63c89cd 100644
--- a/plugins/backup/dummy/pom.xml
+++ b/plugins/backup/dummy/pom.xml
@@ -23,7 +23,7 @@
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/backup/nas/pom.xml b/plugins/backup/nas/pom.xml
index aae1e61..3c7cd8a 100644
--- a/plugins/backup/nas/pom.xml
+++ b/plugins/backup/nas/pom.xml
@@ -25,7 +25,7 @@
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java b/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java
index 3b2c269..a350d80 100644
--- a/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java
+++ b/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java
@@ -56,6 +56,7 @@
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
@@ -195,6 +196,12 @@
throw new CloudRuntimeException("No valid backup repository found for the VM, please check the attached backup offering");
}
+ if (CollectionUtils.isNotEmpty(vmSnapshotDao.findByVmAndByType(vm.getId(), VMSnapshot.Type.DiskAndMemory))) {
+ logger.debug("NAS backup provider cannot take backups of a VM [{}] with disk-and-memory VM snapshots. Restoring the backup will corrupt any newer disk-and-memory " +
+ "VM snapshots.", vm);
+ throw new CloudRuntimeException(String.format("Cannot take backup of VM [%s] as it has disk-and-memory VM snapshots.", vm.getUuid()));
+ }
+
final Date creationDate = new Date();
final String backupPath = String.format("%s/%s", vm.getInstanceName(),
new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(creationDate));
@@ -518,6 +525,11 @@
}
@Override
+ public boolean supportsMemoryVmSnapshot() {
+ return false;
+ }
+
+ @Override
public Pair<Long, Long> getBackupStorageStats(Long zoneId) {
final List<BackupRepository> repositories = backupRepositoryDao.listByZoneAndProvider(zoneId, getName());
Long totalSize = 0L;
diff --git a/plugins/backup/nas/src/test/java/org/apache/cloudstack/backup/NASBackupProviderTest.java b/plugins/backup/nas/src/test/java/org/apache/cloudstack/backup/NASBackupProviderTest.java
index 7540cab..a512292 100644
--- a/plugins/backup/nas/src/test/java/org/apache/cloudstack/backup/NASBackupProviderTest.java
+++ b/plugins/backup/nas/src/test/java/org/apache/cloudstack/backup/NASBackupProviderTest.java
@@ -24,6 +24,7 @@
import java.util.Objects;
import java.util.Optional;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -92,6 +93,9 @@
@Mock
private PrimaryDataStoreDao storagePoolDao;
+ @Mock
+ private VMSnapshotDao vmSnapshotDaoMock;
+
@Test
public void testDeleteBackup() throws OperationTimedoutException, AgentUnavailableException {
Long hostId = 1L;
diff --git a/plugins/backup/networker/pom.xml b/plugins/backup/networker/pom.xml
index 55b827e..cad2b34 100644
--- a/plugins/backup/networker/pom.xml
+++ b/plugins/backup/networker/pom.xml
@@ -25,7 +25,7 @@
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/backup/veeam/pom.xml b/plugins/backup/veeam/pom.xml
index dd145bc..a2dcbd1 100644
--- a/plugins/backup/veeam/pom.xml
+++ b/plugins/backup/veeam/pom.xml
@@ -23,7 +23,7 @@
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
diff --git a/plugins/ca/root-ca/pom.xml b/plugins/ca/root-ca/pom.xml
index 501ba48..2224ae0 100644
--- a/plugins/ca/root-ca/pom.xml
+++ b/plugins/ca/root-ca/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/database/mysql-ha/pom.xml b/plugins/database/mysql-ha/pom.xml
index 518443c..eb1b1d5 100644
--- a/plugins/database/mysql-ha/pom.xml
+++ b/plugins/database/mysql-ha/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/database/quota/pom.xml b/plugins/database/quota/pom.xml
index 5ecbefb..5264538 100644
--- a/plugins/database/quota/pom.xml
+++ b/plugins/database/quota/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaBalanceCmd.java b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaBalanceCmd.java
index cf39f80..0cec0df 100644
--- a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaBalanceCmd.java
+++ b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaBalanceCmd.java
@@ -35,7 +35,8 @@
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.cloudstack.api.response.QuotaStatementItemResponse;
-@APICommand(name = "quotaBalance", responseObject = QuotaStatementItemResponse.class, description = "Create a quota balance statement", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+@APICommand(name = "quotaBalance", responseObject = QuotaStatementItemResponse.class, description = "Create a quota balance statement", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ httpMethod = "GET")
public class QuotaBalanceCmd extends BaseCmd {
diff --git a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaEnabledCmd.java b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaEnabledCmd.java
index 4035a52..af1d146 100644
--- a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaEnabledCmd.java
+++ b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaEnabledCmd.java
@@ -26,7 +26,8 @@
import javax.inject.Inject;
-@APICommand(name = "quotaIsEnabled", responseObject = QuotaEnabledResponse.class, description = "Return true if the plugin is enabled", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+@APICommand(name = "quotaIsEnabled", responseObject = QuotaEnabledResponse.class, description = "Return true if the plugin is enabled", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ httpMethod = "GET")
public class QuotaEnabledCmd extends BaseCmd {
diff --git a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaStatementCmd.java b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaStatementCmd.java
index 18f9bc4..d3bd386 100644
--- a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaStatementCmd.java
+++ b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaStatementCmd.java
@@ -35,7 +35,8 @@
import com.cloud.user.Account;
-@APICommand(name = "quotaStatement", responseObject = QuotaStatementItemResponse.class, description = "Create a quota statement", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+@APICommand(name = "quotaStatement", responseObject = QuotaStatementItemResponse.class, description = "Create a quota statement", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ httpMethod = "GET")
public class QuotaStatementCmd extends BaseCmd {
diff --git a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaSummaryCmd.java b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaSummaryCmd.java
index 42a5980..87322b0 100644
--- a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaSummaryCmd.java
+++ b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaSummaryCmd.java
@@ -33,7 +33,8 @@
import javax.inject.Inject;
-@APICommand(name = "quotaSummary", responseObject = QuotaSummaryResponse.class, description = "Lists balance and quota usage for all Accounts", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+@APICommand(name = "quotaSummary", responseObject = QuotaSummaryResponse.class, description = "Lists balance and quota usage for all Accounts", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ httpMethod = "GET")
public class QuotaSummaryCmd extends BaseListCmd {
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = false, description = "Optional, Account Id for which statement needs to be generated")
diff --git a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffListCmd.java b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffListCmd.java
index d054d54..e0bab07 100644
--- a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffListCmd.java
+++ b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffListCmd.java
@@ -38,7 +38,8 @@
import java.util.Date;
import java.util.List;
-@APICommand(name = "quotaTariffList", responseObject = QuotaTariffResponse.class, description = "Lists all quota tariff plans", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+@APICommand(name = "quotaTariffList", responseObject = QuotaTariffResponse.class, description = "Lists all quota tariff plans", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ httpMethod = "GET")
public class QuotaTariffListCmd extends BaseListCmd {
@Inject
diff --git a/plugins/dedicated-resources/pom.xml b/plugins/dedicated-resources/pom.xml
index 8d4c21e..5576686 100644
--- a/plugins/dedicated-resources/pom.xml
+++ b/plugins/dedicated-resources/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/deployment-planners/implicit-dedication/pom.xml b/plugins/deployment-planners/implicit-dedication/pom.xml
index bfc0e24..c33d6d0 100644
--- a/plugins/deployment-planners/implicit-dedication/pom.xml
+++ b/plugins/deployment-planners/implicit-dedication/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/deployment-planners/user-concentrated-pod/pom.xml b/plugins/deployment-planners/user-concentrated-pod/pom.xml
index ebbd879..20420fb 100644
--- a/plugins/deployment-planners/user-concentrated-pod/pom.xml
+++ b/plugins/deployment-planners/user-concentrated-pod/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/deployment-planners/user-dispersing/pom.xml b/plugins/deployment-planners/user-dispersing/pom.xml
index d811b5e..85c839c 100644
--- a/plugins/deployment-planners/user-dispersing/pom.xml
+++ b/plugins/deployment-planners/user-dispersing/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/drs/cluster/balanced/pom.xml b/plugins/drs/cluster/balanced/pom.xml
index 5267d99..497dfcb 100644
--- a/plugins/drs/cluster/balanced/pom.xml
+++ b/plugins/drs/cluster/balanced/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/drs/cluster/condensed/pom.xml b/plugins/drs/cluster/condensed/pom.xml
index d34f356..6e7c33e 100644
--- a/plugins/drs/cluster/condensed/pom.xml
+++ b/plugins/drs/cluster/condensed/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/event-bus/inmemory/pom.xml b/plugins/event-bus/inmemory/pom.xml
index 7704867..5eadc36 100644
--- a/plugins/event-bus/inmemory/pom.xml
+++ b/plugins/event-bus/inmemory/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/event-bus/kafka/pom.xml b/plugins/event-bus/kafka/pom.xml
index 5231a72..c575725 100644
--- a/plugins/event-bus/kafka/pom.xml
+++ b/plugins/event-bus/kafka/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml
index 738cc7f..3012ac1 100644
--- a/plugins/event-bus/rabbitmq/pom.xml
+++ b/plugins/event-bus/rabbitmq/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/event-bus/webhook/pom.xml b/plugins/event-bus/webhook/pom.xml
index 2bbd5b5..cb19b22 100644
--- a/plugins/event-bus/webhook/pom.xml
+++ b/plugins/event-bus/webhook/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/Webhook.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/Webhook.java
index 1cc73ae..4216f70 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/Webhook.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/Webhook.java
@@ -24,8 +24,8 @@
import org.apache.cloudstack.api.InternalIdentity;
public interface Webhook extends ControlledEntity, Identity, InternalIdentity {
- public static final long ID_DUMMY = 0L;
- public static final String NAME_DUMMY = "Test";
+ long ID_DUMMY = 0L;
+ String NAME_DUMMY = "Test";
enum State {
Enabled, Disabled;
};
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookApiService.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookApiService.java
index edd77e5..de48b8d 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookApiService.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookApiService.java
@@ -18,14 +18,18 @@
package org.apache.cloudstack.mom.webhook;
import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.mom.webhook.api.command.user.AddWebhookFilterCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.CreateWebhookCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookDeliveryCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookFilterCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.ExecuteWebhookDeliveryCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookDeliveriesCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookFiltersCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhooksCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.UpdateWebhookCmd;
import org.apache.cloudstack.mom.webhook.api.response.WebhookDeliveryResponse;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
import com.cloud.utils.component.PluggableService;
@@ -41,4 +45,7 @@
ListResponse<WebhookDeliveryResponse> listWebhookDeliveries(ListWebhookDeliveriesCmd cmd);
int deleteWebhookDelivery(DeleteWebhookDeliveryCmd cmd) throws CloudRuntimeException;
WebhookDeliveryResponse executeWebhookDelivery(ExecuteWebhookDeliveryCmd cmd) throws CloudRuntimeException;
+ ListResponse<WebhookFilterResponse> listWebhookFilters(ListWebhookFiltersCmd cmd) throws CloudRuntimeException;
+ WebhookFilterResponse addWebhookFilter(AddWebhookFilterCmd cmd) throws CloudRuntimeException;
+ int deleteWebhookFilter(DeleteWebhookFilterCmd cmd) throws CloudRuntimeException;
}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookApiServiceImpl.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookApiServiceImpl.java
index 187b140..a484f29 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookApiServiceImpl.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookApiServiceImpl.java
@@ -29,23 +29,30 @@
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.mom.webhook.api.command.user.AddWebhookFilterCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.CreateWebhookCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookDeliveryCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookFilterCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.ExecuteWebhookDeliveryCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookDeliveriesCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookFiltersCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhooksCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.UpdateWebhookCmd;
import org.apache.cloudstack.mom.webhook.api.response.WebhookDeliveryResponse;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
import org.apache.cloudstack.mom.webhook.dao.WebhookDao;
import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryDao;
import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryJoinDao;
+import org.apache.cloudstack.mom.webhook.dao.WebhookFilterDao;
import org.apache.cloudstack.mom.webhook.dao.WebhookJoinDao;
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryJoinVO;
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
+import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
import org.apache.cloudstack.mom.webhook.vo.WebhookJoinVO;
import org.apache.cloudstack.mom.webhook.vo.WebhookVO;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@@ -59,6 +66,7 @@
import com.cloud.projects.Project;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
+import com.cloud.utils.EnumUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.UriUtils;
@@ -84,6 +92,8 @@
@Inject
WebhookDeliveryJoinDao webhookDeliveryJoinDao;
@Inject
+ WebhookFilterDao webhookFilterDao;
+ @Inject
ManagementServerHostDao managementServerHostDao;
@Inject
WebhookService webhookService;
@@ -225,6 +235,25 @@
throw new InvalidParameterValueException(error);
}
+ protected WebhookFilterResponse createWebhookFilterResponse(WebhookFilter webhookFilter, WebhookVO webhookVO) {
+ WebhookFilterResponse response = new WebhookFilterResponse();
+ response.setObjectName("webhookfilter");
+ response.setId(webhookFilter.getUuid());
+ if (webhookVO == null) {
+ webhookVO = webhookDao.findById(webhookFilter.getWebhookId());
+ }
+ if (webhookVO != null) {
+ response.setWebhookId(webhookVO.getUuid());
+ response.setWebhookName(webhookVO.getName());
+ }
+ response.setType(webhookFilter.getType().toString());
+ response.setMode(webhookFilter.getMode().toString());
+ response.setMatchType(webhookFilter.getMatchType().toString());
+ response.setValue(webhookFilter.getValue());
+ response.setCreated(webhookFilter.getCreated());
+ return response;
+ }
+
@Override
public ListResponse<WebhookResponse> listWebhooks(ListWebhooksCmd cmd) {
final CallContext ctx = CallContext.current();
@@ -234,6 +263,25 @@
final String name = cmd.getName();
final String keyword = cmd.getKeyword();
final String scopeStr = cmd.getScope();
+ Webhook.Scope scope = null;
+ if (StringUtils.isNotEmpty(scopeStr)) {
+ scope = EnumUtils.getEnumIgnoreCase(Webhook.Scope.class, scopeStr);
+ if (scope == null) {
+ throw new InvalidParameterValueException("Invalid scope specified");
+ }
+ }
+ if ((Webhook.Scope.Global.equals(scope) && !Account.Type.ADMIN.equals(caller.getType())) ||
+ (Webhook.Scope.Domain.equals(scope) &&
+ !List.of(Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN).contains(caller.getType()))) {
+ throw new InvalidParameterValueException(String.format("Scope %s can not be specified", scope));
+ }
+ Webhook.State state = null;
+ if (StringUtils.isNotEmpty(stateStr)) {
+ state = EnumUtils.getEnumIgnoreCase(Webhook.State.class, stateStr);
+ if (state == null) {
+ throw new InvalidParameterValueException("Invalid state specified");
+ }
+ }
List<WebhookResponse> responsesList = new ArrayList<>();
List<Long> permittedAccounts = new ArrayList<>();
Ternary<Long, Boolean, Project.ListProjectResourcesCriteria> domainIdRecursiveListProject =
@@ -258,27 +306,6 @@
SearchCriteria<WebhookJoinVO> sc = sb.create();
accountManager.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts,
listProjectResourcesCriteria);
- Webhook.Scope scope = null;
- if (StringUtils.isNotEmpty(scopeStr)) {
- try {
- scope = Webhook.Scope.valueOf(scopeStr);
- } catch (IllegalArgumentException iae) {
- throw new InvalidParameterValueException("Invalid scope specified");
- }
- }
- if ((Webhook.Scope.Global.equals(scope) && !Account.Type.ADMIN.equals(caller.getType())) ||
- (Webhook.Scope.Domain.equals(scope) &&
- !List.of(Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN).contains(caller.getType()))) {
- throw new InvalidParameterValueException(String.format("Scope %s can not be specified", scope));
- }
- Webhook.State state = null;
- if (StringUtils.isNotEmpty(stateStr)) {
- try {
- state = Webhook.State.valueOf(stateStr);
- } catch (IllegalArgumentException iae) {
- throw new InvalidParameterValueException("Invalid state specified");
- }
- }
if (scope != null) {
sc.setParameters("scope", scope.name());
}
@@ -316,9 +343,8 @@
final String stateStr = cmd.getState();
Webhook.Scope scope = Webhook.Scope.Local;
if (StringUtils.isNotEmpty(scopeStr)) {
- try {
- scope = Webhook.Scope.valueOf(scopeStr);
- } catch (IllegalArgumentException iae) {
+ scope = EnumUtils.getEnumIgnoreCase(Webhook.Scope.class, scopeStr);
+ if (scope == null) {
throw new InvalidParameterValueException("Invalid scope specified");
}
}
@@ -330,9 +356,8 @@
}
Webhook.State state = Webhook.State.Enabled;
if (StringUtils.isNotEmpty(stateStr)) {
- try {
- state = Webhook.State.valueOf(stateStr);
- } catch (IllegalArgumentException iae) {
+ state = EnumUtils.getEnumIgnoreCase(Webhook.State.class, stateStr);
+ if (state == null) {
throw new InvalidParameterValueException("Invalid state specified");
}
}
@@ -353,6 +378,7 @@
WebhookVO webhook = new WebhookVO(name, description, state, domainId, owner.getId(), payloadUrl, secretKey,
sslVerification, scope);
webhook = webhookDao.persist(webhook);
+ webhookService.invalidateWebhooksCache();
return createWebhookResponse(webhook.getId());
}
@@ -365,7 +391,11 @@
throw new InvalidParameterValueException("Unable to find the webhook with the specified ID");
}
accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhook);
- return webhookDao.remove(id);
+ boolean removed = webhookDao.remove(id);
+ if (removed) {
+ webhookService.invalidateWebhooksCache();
+ }
+ return removed;
}
@Override
@@ -394,29 +424,27 @@
updateNeeded = true;
}
if (StringUtils.isNotEmpty(stateStr)) {
- try {
- Webhook.State state = Webhook.State.valueOf(stateStr);
- webhook.setState(state);
- updateNeeded = true;
- } catch (IllegalArgumentException iae) {
+ Webhook.State state = EnumUtils.getEnumIgnoreCase(Webhook.State.class, stateStr);
+ if (state == null) {
throw new InvalidParameterValueException("Invalid state specified");
}
+ webhook.setState(state);
+ updateNeeded = true;
}
Account owner = accountManager.getAccount(webhook.getAccountId());
if (StringUtils.isNotEmpty(scopeStr)) {
- try {
- Webhook.Scope scope = Webhook.Scope.valueOf(scopeStr);
- if ((Webhook.Scope.Global.equals(scope) && !Account.Type.ADMIN.equals(owner.getType())) ||
- (Webhook.Scope.Domain.equals(scope) &&
- !List.of(Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN).contains(owner.getType()))) {
- throw new InvalidParameterValueException(
- String.format("Scope %s can not be specified for owner %s", scope, owner.getName()));
- }
- webhook.setScope(scope);
- updateNeeded = true;
- } catch (IllegalArgumentException iae) {
+ Webhook.Scope scope = EnumUtils.getEnumIgnoreCase(Webhook.Scope.class, scopeStr);
+ if (scope == null) {
throw new InvalidParameterValueException("Invalid scope specified");
}
+ if ((Webhook.Scope.Global.equals(scope) && !Account.Type.ADMIN.equals(owner.getType())) ||
+ (Webhook.Scope.Domain.equals(scope) &&
+ !List.of(Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN).contains(owner.getType()))) {
+ throw new InvalidParameterValueException(
+ String.format("Scope %s can not be specified for owner %s", scope, owner.getName()));
+ }
+ webhook.setScope(scope);
+ updateNeeded = true;
}
URI uri = URI.create(webhook.getPayloadUrl());
if (StringUtils.isNotEmpty(payloadUrl)) {
@@ -427,7 +455,7 @@
updateNeeded = true;
}
if (sslVerification != null) {
- if (Boolean.TRUE.equals(sslVerification) && !HttpConstants.HTTPS.equalsIgnoreCase(uri.getScheme())) {
+ if (sslVerification && !HttpConstants.HTTPS.equalsIgnoreCase(uri.getScheme())) {
throw new InvalidParameterValueException(
String.format("SSL verification can be specified only for HTTPS URLs, %s", payloadUrl));
}
@@ -444,6 +472,7 @@
if (updateNeeded && !webhookDao.update(id, webhook)) {
return null;
}
+ webhookService.invalidateWebhooksCache();
return createWebhookResponse(webhook.getId());
}
@@ -455,8 +484,7 @@
@Override
public ListResponse<WebhookDeliveryResponse> listWebhookDeliveries(ListWebhookDeliveriesCmd cmd) {
- final CallContext ctx = CallContext.current();
- final Account caller = ctx.getCallingAccount();
+ final Account caller = CallContext.current().getCallingAccount();
final Long id = cmd.getId();
final Long webhookId = cmd.getWebhookId();
final Long managementServerId = cmd.getManagementServerId();
@@ -507,20 +535,23 @@
@Override
public WebhookDeliveryResponse executeWebhookDelivery(ExecuteWebhookDeliveryCmd cmd) throws CloudRuntimeException {
- final CallContext ctx = CallContext.current();
- final Account caller = ctx.getCallingAccount();
+ final Account caller = CallContext.current().getCallingAccount();
final Long deliveryId = cmd.getId();
final Long webhookId = cmd.getWebhookId();
final String payloadUrl = getNormalizedPayloadUrl(cmd.getPayloadUrl());
final String secretKey = cmd.getSecretKey();
final Boolean sslVerification = cmd.isSslVerification();
final String payload = cmd.getPayload();
- final Account owner = accountManager.finalizeOwner(caller, null, null, null);
if (ObjectUtils.allNull(deliveryId, webhookId) && StringUtils.isBlank(payloadUrl)) {
throw new InvalidParameterValueException(String.format("One of the %s, %s or %s must be specified",
ApiConstants.ID, ApiConstants.WEBHOOK_ID, ApiConstants.PAYLOAD_URL));
}
+ if (deliveryId != null && (webhookId != null || StringUtils.isNotBlank(payloadUrl))) {
+ throw new InvalidParameterValueException(
+ String.format("%s cannot be specified with %s or %s", ApiConstants.ID, ApiConstants.WEBHOOK_ID,
+ ApiConstants.PAYLOAD_URL));
+ }
WebhookDeliveryVO existingDelivery = null;
WebhookVO webhook = null;
if (deliveryId != null) {
@@ -545,11 +576,14 @@
webhook.setSecretKey(secretKey);
}
if (sslVerification != null) {
- webhook.setSslVerification(Boolean.TRUE.equals(sslVerification));
+ webhook.setSslVerification(sslVerification);
}
}
+ if (webhook != null) {
+ accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhook);
+ }
if (ObjectUtils.allNull(deliveryId, webhookId)) {
- webhook = new WebhookVO(owner.getDomainId(), owner.getId(), payloadUrl, secretKey,
+ webhook = new WebhookVO(caller.getDomainId(), caller.getId(), payloadUrl, secretKey,
Boolean.TRUE.equals(sslVerification));
}
WebhookDelivery webhookDelivery = webhookService.executeWebhookDelivery(existingDelivery, webhook, payload);
@@ -560,6 +594,87 @@
}
@Override
+ public ListResponse<WebhookFilterResponse> listWebhookFilters(ListWebhookFiltersCmd cmd) throws CloudRuntimeException {
+ Pair<List<WebhookFilterVO>, Integer> filtersAndCount = webhookFilterDao.searchBy(cmd.getId(), cmd.getWebhookId(),
+ cmd.getStartIndex(), cmd.getPageSizeVal());
+ List<WebhookFilterResponse> responsesList = new ArrayList<>();
+ WebhookVO webhookVO = null;
+ if (filtersAndCount.second() > 0) {
+ webhookVO = webhookDao.findById(filtersAndCount.first().get(0).getWebhookId());
+ }
+ for (WebhookFilterVO filter : filtersAndCount.first()) {
+ WebhookFilterResponse response = createWebhookFilterResponse(filter, webhookVO);
+ responsesList.add(response);
+ }
+ ListResponse<WebhookFilterResponse> response = new ListResponse<>();
+ response.setResponses(responsesList, responsesList.size());
+ return response;
+ }
+
+ @Override
+ public WebhookFilterResponse addWebhookFilter(AddWebhookFilterCmd cmd) throws CloudRuntimeException {
+ final Account caller = CallContext.current().getCallingAccount();
+ final long id = cmd.getId();
+ final String typeStr = cmd.getType();
+ final String modeStr = cmd.getMode();
+ final String matchTypeStr = cmd.getMatchType();
+ final String value = cmd.getValue();
+ WebhookVO webhook = webhookDao.findById(id);
+ if (webhook == null) {
+ throw new InvalidParameterValueException("Unable to find the webhook with the specified ID");
+ }
+ accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhook);
+ WebhookFilter.Type type = EnumUtils.getEnumIgnoreCase(WebhookFilter.Type.class, typeStr, WebhookFilter.Type.EventType);
+ WebhookFilter.Mode mode = WebhookFilter.Mode.Include;
+ if (StringUtils.isNotBlank(modeStr)) {
+ mode = EnumUtils.getEnumIgnoreCase(WebhookFilter.Mode.class, modeStr);
+ if (mode == null) {
+ throw new InvalidParameterValueException("Invalid mode specified");
+ }
+ }
+ WebhookFilter.MatchType matchType = WebhookFilter.MatchType.Exact;
+ if (StringUtils.isNotBlank(matchTypeStr)) {
+ matchType = EnumUtils.getEnumIgnoreCase(WebhookFilter.MatchType.class, matchTypeStr);
+ if (matchType == null) {
+ throw new InvalidParameterValueException("Invalid match type specified");
+ }
+ }
+ WebhookFilterVO webhookFilter = new WebhookFilterVO(webhook.getId(), type, mode, matchType, value);
+ List<? extends WebhookFilter> existingFilters = webhookFilterDao.listByWebhook(webhook.getId());
+ if (CollectionUtils.isNotEmpty(existingFilters)) {
+ WebhookFilter conflicting = webhookFilter.getConflicting(existingFilters);
+ if (conflicting != null) {
+ logger.error("Conflict detected when adding WebhookFilter having type: {}, mode: {}, " +
+ "matchtype: {}, value: {} with existing {} for {}", type, mode, matchType, value, conflicting,
+ webhook);
+ throw new InvalidParameterValueException(String.format("Conflicting Webhook filter exists ID: %s",
+ conflicting.getId()));
+ }
+ }
+ webhookFilter = webhookFilterDao.persist(webhookFilter);
+ webhookService.invalidateWebhookFiltersCache(webhook.getId());
+ return createWebhookFilterResponse(webhookFilter, webhook);
+ }
+
+ @Override
+ public int deleteWebhookFilter(DeleteWebhookFilterCmd cmd) throws CloudRuntimeException {
+ final Account caller = CallContext.current().getCallingAccount();
+ final Pair<List<WebhookFilterVO>, Integer> filtersAndCount =
+ webhookFilterDao.searchBy(cmd.getId(), cmd.getWebhookId(), 0L, 1L);
+ if (filtersAndCount.second() == 0) {
+ return 0;
+ }
+ final long webhookId = filtersAndCount.first().get(0).getWebhookId();
+ Webhook webhook = webhookDao.findById(webhookId);
+ accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhook);
+ int result = webhookFilterDao.delete(cmd.getId(), webhookId);
+ if (result > 0) {
+ webhookService.invalidateWebhookFiltersCache(webhookId);
+ }
+ return result;
+ }
+
+ @Override
public List<Class<?>> getCommands() {
List<Class<?>> cmdList = new ArrayList<>();
cmdList.add(CreateWebhookCmd.class);
@@ -569,6 +684,9 @@
cmdList.add(ListWebhookDeliveriesCmd.class);
cmdList.add(DeleteWebhookDeliveryCmd.class);
cmdList.add(ExecuteWebhookDeliveryCmd.class);
+ cmdList.add(ListWebhookFiltersCmd.class);
+ cmdList.add(AddWebhookFilterCmd.class);
+ cmdList.add(DeleteWebhookFilterCmd.class);
return cmdList;
}
}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookFilter.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookFilter.java
new file mode 100644
index 0000000..188c458
--- /dev/null
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookFilter.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.mom.webhook;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+public interface WebhookFilter extends Identity, InternalIdentity {
+
+ enum Type {
+ EventType
+ }
+
+ enum Mode {
+ Include, Exclude
+ }
+
+ enum MatchType {
+ Exact, Prefix, Suffix, Contains
+ }
+
+ long getId();
+ long getWebhookId();
+ Type getType();
+ Mode getMode();
+ MatchType getMatchType();
+ String getValue();
+ Date getCreated();
+
+ static boolean overlaps(WebhookFilter.MatchType oldMatchType, String oldValue, WebhookFilter.MatchType newMatchType, String newValue) {
+ switch (oldMatchType) {
+ case Exact:
+ switch (newMatchType) {
+ case Exact:
+ return oldValue.equals(newValue);
+ }
+ break;
+
+ case Prefix:
+ switch (newMatchType) {
+ case Exact:
+ case Prefix:
+ return newValue.startsWith(oldValue);
+ }
+ break;
+
+ case Suffix:
+ switch (newMatchType) {
+ case Exact:
+ case Suffix:
+ return newValue.endsWith(oldValue);
+ }
+ break;
+
+ case Contains:
+ switch (newMatchType) {
+ case Exact:
+ case Prefix:
+ case Suffix:
+ case Contains:
+ return newValue.contains(oldValue);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+ }
+
+ default WebhookFilter getConflicting(List<? extends WebhookFilter> existing) {
+ for (WebhookFilter f : existing) {
+ if (f.getType() != this.getType()) {
+ continue;
+ }
+
+ // 1. Duplicate entry (same mode, match type, and value)
+ if (f.getMode() == this.getMode()
+ && f.getMatchType() == this.getMatchType()
+ && f.getValue().equalsIgnoreCase(this.getValue())) {
+ return f;
+ }
+
+ // 2. Opposite mode (INCLUDE vs EXCLUDE) — check for overlap
+ if (f.getMode() != this.getMode()) {
+ String oldVal = f.getValue().toUpperCase();
+ String newVal = this.getValue().toUpperCase();
+
+ if (overlaps(f.getMatchType(), oldVal, this.getMatchType(), newVal)) {
+ return f;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookService.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookService.java
index 5a5aced..7d8f9a0 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookService.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookService.java
@@ -60,4 +60,6 @@
void handleEvent(Event event) throws EventBusException;
WebhookDelivery executeWebhookDelivery(WebhookDelivery delivery, Webhook webhook, String payload)
throws CloudRuntimeException;
+ void invalidateWebhooksCache();
+ void invalidateWebhookFiltersCache(long webhookId);
}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookServiceImpl.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookServiceImpl.java
index 97d00c4..624de54 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookServiceImpl.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/WebhookServiceImpl.java
@@ -22,6 +22,7 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -32,7 +33,6 @@
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.ControlledEntity;
-import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.framework.async.AsyncRpcContext;
@@ -42,10 +42,14 @@
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.mom.webhook.dao.WebhookDao;
import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryDao;
+import org.apache.cloudstack.mom.webhook.dao.WebhookFilterDao;
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
+import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
import org.apache.cloudstack.mom.webhook.vo.WebhookVO;
+import org.apache.cloudstack.utils.cache.LazyCache;
import org.apache.cloudstack.utils.identity.ManagementServerNode;
import org.apache.cloudstack.webhook.WebhookHelper;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import com.cloud.api.query.vo.EventJoinVO;
@@ -75,7 +79,9 @@
@Inject
WebhookDao webhookDao;
@Inject
- protected WebhookDeliveryDao webhookDeliveryDao;
+ WebhookDeliveryDao webhookDeliveryDao;
+ @Inject
+ WebhookFilterDao webhookFilterDao;
@Inject
ManagementServerHostDao managementServerHostDao;
@Inject
@@ -83,6 +89,9 @@
@Inject
AccountManager accountManager;
+ protected LazyCache<org.apache.commons.lang3.tuple.Pair<Long, List<Long>>, List<WebhookVO>> webhooksCache;
+ protected LazyCache<Long, List<WebhookFilterVO>> webhookFiltersCache;
+
protected WebhookDeliveryThread getDeliveryJob(Event event, Webhook webhook, Pair<Integer, Integer> configs) {
WebhookDeliveryThread.WebhookDeliveryContext<WebhookDeliveryThread.WebhookDeliveryResult> context =
new WebhookDeliveryThread.WebhookDeliveryContext<>(null, event.getEventId(), webhook.getId());
@@ -97,13 +106,74 @@
return job;
}
+ protected String getEventValueByFilterType(Event event, WebhookFilter.Type filterType) {
+ if (WebhookFilter.Type.EventType.equals(filterType)) {
+ return event.getEventType();
+ }
+ return null;
+ }
+
+ protected boolean isValueMatchingFilter(String eventValue, WebhookFilter.MatchType matchType, String filterValue) {
+ switch (matchType) {
+ case Exact:
+ return eventValue.equals(filterValue);
+ case Prefix:
+ return eventValue.startsWith(filterValue);
+ case Suffix:
+ return eventValue.endsWith(filterValue);
+ case Contains:
+ return eventValue.contains(filterValue);
+ default:
+ return false;
+ }
+ }
+
+ protected boolean isEventMatchingFilters(Event event, List<? extends WebhookFilter> filters) {
+ if (CollectionUtils.isEmpty(filters)) {
+ return true;
+ }
+
+ boolean hasAnyInclude = false;
+ boolean anyIncludeMatched = false;
+
+ // First pass: short-circuit on any Exclude match; track Include presence/match
+ for (WebhookFilter f : filters) {
+ final WebhookFilter.Type type = f.getType();
+ String eventValue = getEventValueByFilterType(event, type);
+
+ if (f.getMode() == WebhookFilter.Mode.Exclude) {
+ if (eventValue != null && isValueMatchingFilter(eventValue, f.getMatchType(), f.getValue())) {
+ logger.trace("{} matched Exclude {}, webhook delivery will be skipped", event, f);
+ return false;
+ }
+ continue;
+ }
+
+ if (f.getMode() == WebhookFilter.Mode.Include) {
+ hasAnyInclude = true;
+ if (!anyIncludeMatched && eventValue != null &&
+ isValueMatchingFilter(eventValue, f.getMatchType(), f.getValue())) {
+ logger.trace("{} matched Include {}", event, f);
+ anyIncludeMatched = true;
+ }
+ }
+ }
+
+ // If there were includes, we must have matched at least one; otherwise allow by default
+ if (hasAnyInclude && !anyIncludeMatched) {
+ return false;
+ }
+
+ return true;
+ }
+
protected List<Runnable> getDeliveryJobs(Event event) throws EventBusException {
List<Runnable> jobs = new ArrayList<>();
if (!EventCategory.ACTION_EVENT.getName().equals(event.getEventCategory())) {
return jobs;
}
if (event.getResourceAccountId() == null) {
- logger.warn("Skipping delivering event {} to any webhook as account ID is missing", event);
+ logger.warn("Skipping delivering {} to any webhook as account ID is missing", event);
throw new EventBusException(String.format("Account missing for the event ID: %s", event.getEventUuid()));
}
List<Long> domainIds = new ArrayList<>();
@@ -112,9 +182,14 @@
domainIds.addAll(domainDao.getDomainParentIds(event.getResourceDomainId()));
}
List<WebhookVO> webhooks =
- webhookDao.listByEnabledForDelivery(event.getResourceAccountId(), domainIds);
+ webhooksCache.get(org.apache.commons.lang3.tuple.Pair.of(event.getResourceAccountId(), domainIds));
Map<Long, Pair<Integer, Integer>> domainConfigs = new HashMap<>();
for (WebhookVO webhook : webhooks) {
+ List<? extends WebhookFilter> filters = webhookFiltersCache.get(webhook.getId());
+ if (!isEventMatchingFilters(event, filters)) {
+ logger.debug("Skipping delivering {} to {} as it doesn't match filters", event, webhook);
+ continue;
+ }
if (!domainConfigs.containsKey(webhook.getDomainId())) {
domainConfigs.put(webhook.getDomainId(),
new Pair<>(WebhookDeliveryTries.valueIn(webhook.getDomainId()),
@@ -128,7 +203,7 @@
}
protected Runnable getManualDeliveryJob(WebhookDelivery existingDelivery, Webhook webhook, String payload,
- AsyncCallFuture<WebhookDeliveryThread.WebhookDeliveryResult> future) {
+ CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future) {
if (StringUtils.isBlank(payload)) {
payload = "{ \"CloudStack\": \"works!\" }";
}
@@ -155,7 +230,7 @@
event.setDescription(description);
event.setResourceAccountUuid(resourceAccountUuid);
ManualDeliveryContext<WebhookDeliveryThread.WebhookDeliveryResult> context =
- new ManualDeliveryContext<>(null, webhook, future);
+ new ManualDeliveryContext<>(null, future);
AsyncCallbackDispatcher<WebhookServiceImpl, WebhookDeliveryThread.WebhookDeliveryResult> caller =
AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().manualDeliveryCompleteCallback(null, null))
@@ -181,7 +256,7 @@
AsyncCallbackDispatcher<WebhookServiceImpl, WebhookDeliveryThread.WebhookDeliveryResult> callback,
ManualDeliveryContext<WebhookDeliveryThread.WebhookDeliveryResult> context) {
WebhookDeliveryThread.WebhookDeliveryResult result = callback.getResult();
- context.future.complete(result);
+ context.getFuture().complete(result);
return null;
}
@@ -205,8 +280,20 @@
return processed;
}
+ protected void initCaches() {
+ webhooksCache = new LazyCache<>(
+ 16, 60,
+ (key) -> webhookDao.listByEnabledForDelivery(key.getLeft(), key.getRight())
+ );
+ webhookFiltersCache = new LazyCache<>(
+ 16, 60,
+ (webhookId) -> webhookFilterDao.listByWebhook(webhookId)
+ );
+ }
+
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+ initCaches();
try {
webhookJobExecutor = Executors.newFixedThreadPool(WebhookDeliveryThreadPoolSize.value(),
new NamedThreadFactory(WEBHOOK_JOB_POOL_THREAD_PREFIX));
@@ -273,7 +360,7 @@
@Override
public WebhookDelivery executeWebhookDelivery(WebhookDelivery delivery, Webhook webhook, String payload)
throws CloudRuntimeException {
- AsyncCallFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = new AsyncCallFuture<>();
+ CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = new CompletableFuture<>();
Runnable job = getManualDeliveryJob(delivery, webhook, payload, future);
webhookJobExecutor.submit(job);
WebhookDeliveryThread.WebhookDeliveryResult result = null;
@@ -298,21 +385,32 @@
}
@Override
+ public void invalidateWebhooksCache() {
+ webhooksCache.clear();
+ }
+
+ @Override
+ public void invalidateWebhookFiltersCache(long webhookId) {
+ webhookFiltersCache.invalidate(webhookId);
+ }
+
+ @Override
public List<Class<?>> getCommands() {
return new ArrayList<>();
}
- static public class ManualDeliveryContext<T> extends AsyncRpcContext<T> {
- final Webhook webhook;
- final AsyncCallFuture<WebhookDeliveryThread.WebhookDeliveryResult> future;
+ protected static class ManualDeliveryContext<T> extends AsyncRpcContext<T> {
+ private final CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future;
- public ManualDeliveryContext(AsyncCompletionCallback<T> callback, Webhook webhook,
- AsyncCallFuture<WebhookDeliveryThread.WebhookDeliveryResult> future) {
- super(callback);
- this.webhook = webhook;
- this.future = future;
+ public CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> getFuture() {
+ return future;
}
+ public ManualDeliveryContext(AsyncCompletionCallback<T> callback,
+ CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future) {
+ super(callback);
+ this.future = future;
+ }
}
public class WebhookDeliveryCleanupWorker extends ManagedContextRunnable {
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/AddWebhookFilterCmd.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/AddWebhookFilterCmd.java
new file mode 100644
index 0000000..ba71cc1
--- /dev/null
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/AddWebhookFilterCmd.java
@@ -0,0 +1,118 @@
+// 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.mom.webhook.api.command.user;
+
+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.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.mom.webhook.WebhookApiService;
+import org.apache.cloudstack.mom.webhook.WebhookFilter;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "addWebhookFilter",
+ description = "Adds a Webhook filter",
+ responseObject = WebhookResponse.class,
+ entityType = {WebhookFilter.class},
+ requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false,
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
+ since = "4.23.0")
+public class AddWebhookFilterCmd extends BaseCmd {
+
+ @Inject
+ WebhookApiService webhookApiService;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.WEBHOOK_ID, type = CommandType.UUID, required = true,
+ entityType = WebhookResponse.class, description = "ID for the Webhook")
+ private Long id;
+
+ @Parameter(name = ApiConstants.MODE, type = BaseCmd.CommandType.STRING,
+ description = "Mode for the Webhook filter - Include or Exclude")
+ private String mode;
+
+ @Parameter(name = ApiConstants.MATCH_TYPE, type = BaseCmd.CommandType.STRING,
+ description = "Match type for the Webhook filter - Exact, Prefix, Suffix or Contains")
+ private String matchType;
+
+ @Parameter(name = ApiConstants.VALUE, type = BaseCmd.CommandType.STRING, required = true,
+ description = "Value for the Webhook which that will be matched")
+ private String value;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccountId();
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getType() {
+ return WebhookFilter.Type.EventType.name();
+ }
+
+ public String getMode() {
+ return mode;
+ }
+
+ public String getMatchType() {
+ return matchType;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public void execute() throws ServerApiException {
+ try {
+ WebhookFilterResponse response = webhookApiService.addWebhookFilter(this);
+ if (response == null) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add webhook filter");
+ }
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ } catch (CloudRuntimeException ex) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
+ }
+ }
+}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/CreateWebhookCmd.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/CreateWebhookCmd.java
index d3d2cf1..12da15b 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/CreateWebhookCmd.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/CreateWebhookCmd.java
@@ -28,13 +28,12 @@
import org.apache.cloudstack.api.ApiErrorCode;
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.DomainResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.mom.webhook.WebhookApiService;
import org.apache.cloudstack.mom.webhook.Webhook;
+import org.apache.cloudstack.mom.webhook.WebhookApiService;
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
import com.cloud.utils.exception.CloudRuntimeException;
@@ -42,10 +41,7 @@
@APICommand(name = "createWebhook",
description = "Creates a Webhook",
responseObject = WebhookResponse.class,
- responseView = ResponseObject.ResponseView.Restricted,
entityType = {Webhook.class},
- requestHasSensitiveInfo = false,
- responseHasSensitiveInfo = true,
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
since = "4.20.0")
public class CreateWebhookCmd extends BaseCmd {
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookFilterCmd.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookFilterCmd.java
new file mode 100644
index 0000000..80812c9
--- /dev/null
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookFilterCmd.java
@@ -0,0 +1,91 @@
+// 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.mom.webhook.api.command.user;
+
+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.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.mom.webhook.WebhookApiService;
+import org.apache.cloudstack.mom.webhook.WebhookFilter;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "deleteWebhookFilter",
+ description = "Deletes Webhook filter",
+ responseObject = SuccessResponse.class,
+ entityType = {WebhookFilter.class},
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
+ since = "4.20.0")
+public class DeleteWebhookFilterCmd extends BaseCmd {
+
+ @Inject
+ WebhookApiService webhookApiService;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+ @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID,
+ entityType = WebhookFilterResponse.class,
+ description = "The ID of the Webhook filter")
+ private Long id;
+
+ @Parameter(name = ApiConstants.WEBHOOK_ID, type = BaseCmd.CommandType.UUID,
+ entityType = WebhookResponse.class,
+ description = "The ID of the Webhook")
+ private Long webhookId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+ public Long getId() {
+ return id;
+ }
+
+ public Long getWebhookId() {
+ return webhookId;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccountId();
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+ @Override
+ public void execute() throws ServerApiException {
+ try {
+ webhookApiService.deleteWebhookFilter(this);
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ setResponseObject(response);
+ } catch (CloudRuntimeException ex) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
+ }
+ }
+}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ExecuteWebhookDeliveryCmd.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ExecuteWebhookDeliveryCmd.java
index f31a548..c3dfe85 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ExecuteWebhookDeliveryCmd.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ExecuteWebhookDeliveryCmd.java
@@ -39,8 +39,6 @@
description = "Executes a Webhook delivery",
responseObject = WebhookDeliveryResponse.class,
entityType = {WebhookDelivery.class},
- requestHasSensitiveInfo = false,
- responseHasSensitiveInfo = false,
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
since = "4.20.0")
public class ExecuteWebhookDeliveryCmd extends BaseCmd {
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookDeliveriesCmd.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookDeliveriesCmd.java
index 466dad0..cf9c046 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookDeliveriesCmd.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookDeliveriesCmd.java
@@ -27,7 +27,6 @@
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
-import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse;
@@ -39,7 +38,6 @@
@APICommand(name = "listWebhookDeliveries",
description = "Lists Webhook deliveries",
responseObject = WebhookResponse.class,
- responseView = ResponseObject.ResponseView.Restricted,
entityType = {WebhookDelivery.class},
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
since = "4.20.0")
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookFiltersCmd.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookFiltersCmd.java
new file mode 100644
index 0000000..1641ea6
--- /dev/null
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookFiltersCmd.java
@@ -0,0 +1,80 @@
+// 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.mom.webhook.api.command.user;
+
+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.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.mom.webhook.WebhookApiService;
+import org.apache.cloudstack.mom.webhook.WebhookFilter;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookDeliveryResponse;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
+
+@APICommand(name = "listWebhookFilters",
+ description = "Lists Webhook filters",
+ responseObject = WebhookFilterResponse.class,
+ entityType = {WebhookFilter.class},
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
+ since = "4.23.0")
+public class ListWebhookFiltersCmd extends BaseListCmd {
+
+ @Inject
+ WebhookApiService webhookApiService;
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+ @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID,
+ entityType = WebhookDeliveryResponse.class,
+ description = "The ID of the Webhook delivery")
+ private Long id;
+
+ @Parameter(name = ApiConstants.WEBHOOK_ID, type = BaseCmd.CommandType.UUID,
+ entityType = WebhookResponse.class,
+ description = "The ID of the Webhook")
+ private Long webhookId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+ public Long getId() {
+ return id;
+ }
+
+ public Long getWebhookId() {
+ return webhookId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+ @Override
+ public void execute() throws ServerApiException {
+ ListResponse<WebhookFilterResponse> response = webhookApiService.listWebhookFilters(this);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhooksCmd.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhooksCmd.java
index 6510c30..2719e0a 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhooksCmd.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhooksCmd.java
@@ -25,17 +25,15 @@
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
import org.apache.cloudstack.api.Parameter;
-import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ListResponse;
-import org.apache.cloudstack.mom.webhook.WebhookApiService;
import org.apache.cloudstack.mom.webhook.Webhook;
+import org.apache.cloudstack.mom.webhook.WebhookApiService;
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
@APICommand(name = "listWebhooks",
description = "Lists Webhooks",
responseObject = WebhookResponse.class,
- responseView = ResponseObject.ResponseView.Restricted,
entityType = {Webhook.class},
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
since = "4.20.0")
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/UpdateWebhookCmd.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/UpdateWebhookCmd.java
index c2be1d3..e27fe1a 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/UpdateWebhookCmd.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/command/user/UpdateWebhookCmd.java
@@ -26,17 +26,16 @@
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.context.CallContext;
-import org.apache.cloudstack.mom.webhook.WebhookApiService;
import org.apache.cloudstack.mom.webhook.Webhook;
+import org.apache.cloudstack.mom.webhook.WebhookApiService;
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = "updateWebhook",
description = "Updates a Webhook",
- responseObject = SuccessResponse.class,
+ responseObject = WebhookResponse.class,
entityType = {Webhook.class},
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
since = "4.20.0")
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/response/WebhookFilterResponse.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/response/WebhookFilterResponse.java
new file mode 100644
index 0000000..f1ed158
--- /dev/null
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/api/response/WebhookFilterResponse.java
@@ -0,0 +1,95 @@
+// 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.mom.webhook.api.response;
+
+import java.util.Date;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+import org.apache.cloudstack.mom.webhook.WebhookFilter;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+@EntityReference(value = {WebhookFilter.class})
+public class WebhookFilterResponse extends BaseResponse {
+ @SerializedName(ApiConstants.ID)
+ @Param(description = "The ID of the Webhook filter")
+ private String id;
+
+ @SerializedName(ApiConstants.WEBHOOK_ID)
+ @Param(description = "The ID of the Webhook")
+ private String webhookId;
+
+ @SerializedName(ApiConstants.WEBHOOK_NAME)
+ @Param(description = "The name of the Webhook")
+ private String webhookName;
+
+ @SerializedName(ApiConstants.TYPE)
+ @Param(description = "The type of the Webhook filter")
+ private String type;
+
+ @SerializedName(ApiConstants.MODE)
+ @Param(description = "The type of the Webhook filter")
+ private String mode;
+
+ @SerializedName(ApiConstants.MATCH_TYPE)
+ @Param(description = "The type of the Webhook filter")
+ private String matchType;
+
+ @SerializedName(ApiConstants.VALUE)
+ @Param(description = "The type of the Webhook filter")
+ private String value;
+
+ @SerializedName(ApiConstants.CREATED)
+ @Param(description = "The type of the Webhook filter")
+ private Date created;
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setWebhookId(String webhookId) {
+ this.webhookId = webhookId;
+ }
+
+ public void setWebhookName(String webhookName) {
+ this.webhookName = webhookName;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+
+ public void setMatchType(String matchType) {
+ this.matchType = matchType;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryDaoImpl.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryDaoImpl.java
index 088ed53..5b8f634 100644
--- a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryDaoImpl.java
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryDaoImpl.java
@@ -21,6 +21,7 @@
import java.util.List;
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
+import org.apache.commons.collections.CollectionUtils;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
@@ -64,6 +65,9 @@
SearchCriteria<WebhookDeliveryVO> sc = sb.create();
sc.setParameters("webhookId", webhookId);
List<WebhookDeliveryVO> keep = listBy(sc, searchFilter);
+ if (CollectionUtils.isEmpty(keep)) {
+ return;
+ }
SearchBuilder<WebhookDeliveryVO> sbDelete = createSearchBuilder();
sbDelete.and("id", sbDelete.entity().getId(), SearchCriteria.Op.NOTIN);
SearchCriteria<WebhookDeliveryVO> scDelete = sbDelete.create();
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookFilterDao.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookFilterDao.java
new file mode 100644
index 0000000..753122d
--- /dev/null
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookFilterDao.java
@@ -0,0 +1,31 @@
+// 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.mom.webhook.dao;
+
+import java.util.List;
+
+import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.GenericDao;
+
+public interface WebhookFilterDao extends GenericDao<WebhookFilterVO, Long> {
+ Pair<List<WebhookFilterVO>, Integer> searchBy(Long id, Long webhookId, Long startIndex, Long pageSize);
+ List<WebhookFilterVO> listByWebhook(Long webhookId);
+ int delete(Long id, Long webhookId);
+}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookFilterDaoImpl.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookFilterDaoImpl.java
new file mode 100644
index 0000000..84446a2
--- /dev/null
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/dao/WebhookFilterDaoImpl.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.mom.webhook.dao;
+
+import java.util.List;
+
+import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
+import org.apache.commons.lang3.ObjectUtils;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+public class WebhookFilterDaoImpl extends GenericDaoBase<WebhookFilterVO, Long> implements WebhookFilterDao {
+
+ SearchBuilder<WebhookFilterVO> IdWebhookIdSearch;
+
+ public WebhookFilterDaoImpl() {
+ IdWebhookIdSearch = createSearchBuilder();
+ IdWebhookIdSearch.and("id", IdWebhookIdSearch.entity().getId(), SearchCriteria.Op.EQ);
+ IdWebhookIdSearch.and("webhookId", IdWebhookIdSearch.entity().getWebhookId(), SearchCriteria.Op.EQ);
+ IdWebhookIdSearch.done();
+ }
+
+ @Override
+ public Pair<List<WebhookFilterVO>, Integer> searchBy(Long id, Long webhookId, Long startIndex, Long pageSize) {
+ Filter searchFilter = new Filter(WebhookFilterVO.class, "id", false, startIndex,
+ pageSize);
+ SearchCriteria<WebhookFilterVO> sc = IdWebhookIdSearch.create();
+ if (id != null) {
+ sc.setParameters("id", id);
+ }
+ if (webhookId != null) {
+ sc.setParameters("webhookId", webhookId);
+ }
+ return searchAndCount(sc, searchFilter);
+ }
+
+ @Override
+ public List<WebhookFilterVO> listByWebhook(Long webhookId) {
+ SearchCriteria<WebhookFilterVO> sc = IdWebhookIdSearch.create();
+ if (webhookId != null) {
+ sc.setParameters("webhookId", webhookId);
+ }
+ return listBy(sc);
+ }
+
+ @Override
+ public int delete(Long id, Long webhookId) {
+ SearchCriteria<WebhookFilterVO> sc = IdWebhookIdSearch.create();
+ if (ObjectUtils.allNull(id, webhookId)) {
+ return 0;
+ }
+ if (id != null) {
+ sc.setParameters("id", id);
+ }
+ if (webhookId != null) {
+ sc.setParameters("webhookId", webhookId);
+ }
+ return remove(sc);
+ }
+}
diff --git a/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/vo/WebhookFilterVO.java b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/vo/WebhookFilterVO.java
new file mode 100644
index 0000000..75e18f1
--- /dev/null
+++ b/plugins/event-bus/webhook/src/main/java/org/apache/cloudstack/mom/webhook/vo/WebhookFilterVO.java
@@ -0,0 +1,155 @@
+// 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.mom.webhook.vo;
+
+import java.util.Date;
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.apache.cloudstack.mom.webhook.WebhookFilter;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+
+import com.cloud.utils.db.GenericDao;
+
+@Entity
+@Table(name = "webhook_filter")
+public class WebhookFilterVO implements WebhookFilter {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id", updatable = false, nullable = false)
+ private Long id;
+
+ @Column(name = "uuid")
+ private String uuid;
+
+ @Column(name = "webhook_id", nullable = false)
+ private Long webhookId;
+
+ @Column(name = "type", length = 20)
+ @Enumerated(value = EnumType.STRING)
+ private Type type;
+
+ @Column(name = "mode", length = 20)
+ @Enumerated(value = EnumType.STRING)
+ private Mode mode;
+
+ @Column(name = "match_type", length = 20)
+ @Enumerated(value = EnumType.STRING)
+ private MatchType matchType;
+
+ @Column(name = "value", nullable = false, length = 128)
+ private String value;
+
+ @Column(name = GenericDao.CREATED_COLUMN)
+ private Date created;
+
+ public WebhookFilterVO() {
+ this.uuid = UUID.randomUUID().toString();
+ }
+
+ public WebhookFilterVO(Long webhookId, Type type, Mode mode, MatchType matchType, String value) {
+ this.uuid = UUID.randomUUID().toString();
+ this.webhookId = webhookId;
+ this.type = type;
+ this.mode = mode;
+ this.matchType = matchType;
+ this.value = value;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ @Override
+ public String getUuid() {
+ return uuid;
+ }
+
+ @Override
+ public long getWebhookId() {
+ return webhookId;
+ }
+
+ public void setWebhookId(Long webhookId) {
+ this.webhookId = webhookId;
+ }
+
+ @Override
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ @Override
+ public Mode getMode() {
+ return mode;
+ }
+
+ public void setMode(Mode mode) {
+ this.mode = mode;
+ }
+
+ @Override
+ public MatchType getMatchType() {
+ return matchType;
+ }
+
+ public void setMatchType(MatchType matchType) {
+ this.matchType = matchType;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("WebhookFilter %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(
+ this, "id", "uuid", "webhook_id", "type", "mode", "match_type", "value"));
+ }
+}
diff --git a/plugins/event-bus/webhook/src/main/resources/META-INF/cloudstack/webhook/spring-event-webhook-context.xml b/plugins/event-bus/webhook/src/main/resources/META-INF/cloudstack/webhook/spring-event-webhook-context.xml
index 22f688c..e006972 100644
--- a/plugins/event-bus/webhook/src/main/resources/META-INF/cloudstack/webhook/spring-event-webhook-context.xml
+++ b/plugins/event-bus/webhook/src/main/resources/META-INF/cloudstack/webhook/spring-event-webhook-context.xml
@@ -31,6 +31,7 @@
<bean id="webhookJoinDao" class="org.apache.cloudstack.mom.webhook.dao.WebhookJoinDaoImpl" />
<bean id="webhookDeliveryDao" class="org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryDaoImpl" />
<bean id="webhookDeliveryJoinDao" class="org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryJoinDaoImpl" />
+ <bean id="webhookFilterDao" class="org.apache.cloudstack.mom.webhook.dao.WebhookFilterDaoImpl" />
<bean id="webhookApiService" class="org.apache.cloudstack.mom.webhook.WebhookApiServiceImpl" />
<bean id="webhookService" class="org.apache.cloudstack.mom.webhook.WebhookServiceImpl" />
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/WebhookApiServiceImplTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/WebhookApiServiceImplTest.java
index dff3580..eb0da8e 100644
--- a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/WebhookApiServiceImplTest.java
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/WebhookApiServiceImplTest.java
@@ -16,34 +16,62 @@
// under the License.
package org.apache.cloudstack.mom.webhook;
+import java.util.Date;
import java.util.List;
import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.mom.webhook.api.command.user.AddWebhookFilterCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.CreateWebhookCmd;
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookDeliveryCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookFilterCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.ExecuteWebhookDeliveryCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookDeliveriesCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookFiltersCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhooksCmd;
+import org.apache.cloudstack.mom.webhook.api.command.user.UpdateWebhookCmd;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookDeliveryResponse;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
import org.apache.cloudstack.mom.webhook.dao.WebhookDao;
+import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryDao;
+import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryJoinDao;
+import org.apache.cloudstack.mom.webhook.dao.WebhookFilterDao;
import org.apache.cloudstack.mom.webhook.dao.WebhookJoinDao;
+import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryJoinVO;
+import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
+import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
import org.apache.cloudstack.mom.webhook.vo.WebhookJoinVO;
import org.apache.cloudstack.mom.webhook.vo.WebhookVO;
import org.apache.commons.collections.CollectionUtils;
+import org.junit.After;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
+import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import com.cloud.api.ApiResponseHelper;
+import com.cloud.cluster.ManagementServerHostVO;
+import com.cloud.cluster.dao.ManagementServerHostDao;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
+import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
@RunWith(MockitoJUnitRunner.class)
public class WebhookApiServiceImplTest {
@@ -53,14 +81,43 @@
@Mock
WebhookJoinDao webhookJoinDao;
@Mock
+ WebhookDeliveryDao webhookDeliveryDao;
+ @Mock
+ WebhookDeliveryJoinDao webhookDeliveryJoinDao;
+ @Mock
+ WebhookFilterDao webhookFilterDao;
+ @Mock
AccountManager accountManager;
-
@Mock
DomainDao domainDao;
+ @Mock
+ WebhookService webhookService;
+ @Mock
+ ManagementServerHostDao managementServerHostDao;
+ @Mock
+ Account caller;
+
+ @Spy
@InjectMocks
WebhookApiServiceImpl webhookApiServiceImpl = new WebhookApiServiceImpl();
+ MockedStatic<CallContext> callContextMocked;
+
+ @Before
+ public void setup() {
+ callContextMocked = Mockito.mockStatic(CallContext.class);
+ CallContext callContextMock = Mockito.mock(CallContext.class);
+ callContextMocked.when(CallContext::current).thenReturn(callContextMock);
+ Mockito.when(callContextMock.getCallingAccount()).thenReturn(caller);
+ }
+
+ @After
+ public void cleanup() {
+ callContextMocked.close();
+ }
+
+
private WebhookJoinVO prepareTestWebhookJoinVO() {
String name = "webhook";
String description = "webhook-description";
@@ -152,48 +209,32 @@
@Test(expected = InvalidParameterValueException.class)
public void testDeleteWebhookInvalidWebhook() {
- try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
- DeleteWebhookCmd cmd = Mockito.mock(DeleteWebhookCmd.class);
- Mockito.when(cmd.getId()).thenReturn(1L);
- CallContext callContextMock = Mockito.mock(CallContext.class);
- callContextMocked.when(CallContext::current).thenReturn(callContextMock);
- webhookApiServiceImpl.deleteWebhook(cmd);
- }
+ DeleteWebhookCmd cmd = Mockito.mock(DeleteWebhookCmd.class);
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ webhookApiServiceImpl.deleteWebhook(cmd);
}
@Test(expected = PermissionDeniedException.class)
public void testDeleteWebhookNoPermission() {
- try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
- DeleteWebhookCmd cmd = Mockito.mock(DeleteWebhookCmd.class);
- Mockito.when(cmd.getId()).thenReturn(1L);
- WebhookVO webhookVO = Mockito.mock(WebhookVO.class);
- Mockito.when(webhookDao.findById(1L)).thenReturn(webhookVO);
- CallContext callContextMock = Mockito.mock(CallContext.class);
- Account account = Mockito.mock(Account.class);
- Mockito.when(callContextMock.getCallingAccount()).thenReturn(account);
- callContextMocked.when(CallContext::current).thenReturn(callContextMock);
- Mockito.doThrow(PermissionDeniedException.class).when(accountManager).checkAccess(account,
- SecurityChecker.AccessType.OperateEntry, false, webhookVO);
- webhookApiServiceImpl.deleteWebhook(cmd);
- }
+ DeleteWebhookCmd cmd = Mockito.mock(DeleteWebhookCmd.class);
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ WebhookVO webhookVO = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhookVO);
+ Mockito.doThrow(PermissionDeniedException.class).when(accountManager).checkAccess(caller,
+ SecurityChecker.AccessType.OperateEntry, false, webhookVO);
+ webhookApiServiceImpl.deleteWebhook(cmd);
}
@Test
public void testDeleteWebhook() {
- try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
- DeleteWebhookCmd cmd = Mockito.mock(DeleteWebhookCmd.class);
- Mockito.when(cmd.getId()).thenReturn(1L);
- WebhookVO webhookVO = Mockito.mock(WebhookVO.class);
- Mockito.when(webhookDao.findById(1L)).thenReturn(webhookVO);
- CallContext callContextMock = Mockito.mock(CallContext.class);
- Account account = Mockito.mock(Account.class);
- Mockito.when(callContextMock.getCallingAccount()).thenReturn(account);
- callContextMocked.when(CallContext::current).thenReturn(callContextMock);
- Mockito.doNothing().when(accountManager).checkAccess(account,
- SecurityChecker.AccessType.OperateEntry, false, webhookVO);
- Mockito.doReturn(true).when(webhookDao).remove(Mockito.anyLong());
- Assert.assertTrue(webhookApiServiceImpl.deleteWebhook(cmd));
- }
+ DeleteWebhookCmd cmd = Mockito.mock(DeleteWebhookCmd.class);
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ WebhookVO webhookVO = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhookVO);
+ Mockito.doNothing().when(accountManager).checkAccess(caller,
+ SecurityChecker.AccessType.OperateEntry, false, webhookVO);
+ Mockito.doReturn(true).when(webhookDao).remove(Mockito.anyLong());
+ Assert.assertTrue(webhookApiServiceImpl.deleteWebhook(cmd));
}
@Test
@@ -250,4 +291,1027 @@
Assert.assertEquals("https://abc.com",
webhookApiServiceImpl.getNormalizedPayloadUrl("https://abc.com"));
}
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void basicWebhookDeliveryApiCheckThrowsExceptionForInvalidDeliveryId() {
+ Mockito.when(webhookDeliveryDao.findById(1L)).thenReturn(null);
+ webhookApiServiceImpl.basicWebhookDeliveryApiCheck(Mockito.mock(Account.class), 1L, null, null, null, null);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void basicWebhookDeliveryApiCheckThrowsExceptionForInvalidWebhookId() {
+ Mockito.when(webhookDao.findById(1L)).thenReturn(null);
+ webhookApiServiceImpl.basicWebhookDeliveryApiCheck(Mockito.mock(Account.class), null, 1L, null, null, null);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void basicWebhookDeliveryApiCheckThrowsExceptionForEndDateBeforeStartDate() {
+ webhookApiServiceImpl.basicWebhookDeliveryApiCheck(Mockito.mock(Account.class), null, null, null, new Date(), new Date(System.currentTimeMillis() - 1000));
+ }
+
+ @Test(expected = PermissionDeniedException.class)
+ public void basicWebhookDeliveryApiCheckThrowsExceptionForNonAdminAccessToManagementServer() {
+ Account caller = Mockito.mock(Account.class);
+ Mockito.when(caller.getType()).thenReturn(Account.Type.NORMAL);
+ webhookApiServiceImpl.basicWebhookDeliveryApiCheck(caller, null, null, 1L, null, null);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void basicWebhookDeliveryApiCheckThrowsExceptionForInvalidManagementServerId() {
+ Account caller = Mockito.mock(Account.class);
+ Mockito.when(caller.getType()).thenReturn(Account.Type.ADMIN);
+ Mockito.when(managementServerHostDao.findById(1L)).thenReturn(null);
+ webhookApiServiceImpl.basicWebhookDeliveryApiCheck(caller, null, null, 1L, null, null);
+ }
+
+ @Test
+ public void basicWebhookDeliveryApiCheckReturnsManagementServerHostVOForValidInput() {
+ Account caller = Mockito.mock(Account.class);
+ Mockito.when(caller.getType()).thenReturn(Account.Type.ADMIN);
+ ManagementServerHostVO managementServerHostVO = Mockito.mock(ManagementServerHostVO.class);
+ Mockito.when(managementServerHostDao.findById(1L)).thenReturn(managementServerHostVO);
+ ManagementServerHostVO result = webhookApiServiceImpl.basicWebhookDeliveryApiCheck(caller, null, null, 1L, null, null);
+ Assert.assertEquals(managementServerHostVO, result);
+ }
+
+ @Test
+ public void basicWebhookDeliveryApiCheckValidatesWebhookDeliveryAccess() {
+ Account caller = Mockito.mock(Account.class);
+ WebhookDeliveryVO webhookDeliveryVO = Mockito.mock(WebhookDeliveryVO.class);
+ WebhookVO webhookVO = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhookDeliveryDao.findById(1L)).thenReturn(webhookDeliveryVO);
+ Mockito.when(webhookDeliveryVO.getWebhookId()).thenReturn(1L);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhookVO);
+ Mockito.doNothing().when(accountManager).checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhookVO);
+ webhookApiServiceImpl.basicWebhookDeliveryApiCheck(caller, 1L, null, null, null, null);
+ Mockito.verify(accountManager).checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhookVO);
+ }
+
+ @Test
+ public void basicWebhookDeliveryApiCheckValidatesWebhookAccess() {
+ Account caller = Mockito.mock(Account.class);
+ WebhookVO webhookVO = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhookVO);
+ Mockito.doNothing().when(accountManager).checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhookVO);
+ webhookApiServiceImpl.basicWebhookDeliveryApiCheck(caller, null, 1L, null, null, null);
+ Mockito.verify(accountManager).checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhookVO);
+ }
+
+ @Test
+ public void createWebhookDeliveryResponsePopulatesAllFieldsCorrectly() {
+ WebhookDeliveryJoinVO webhookDeliveryVO = Mockito.mock(WebhookDeliveryJoinVO.class);
+ Mockito.when(webhookDeliveryVO.getUuid()).thenReturn("uuid");
+ Mockito.when(webhookDeliveryVO.getEventUuid()).thenReturn("eventUuid");
+ Mockito.when(webhookDeliveryVO.getEventType()).thenReturn("eventType");
+ Mockito.when(webhookDeliveryVO.getWebhookUuId()).thenReturn("webhookUuid");
+ Mockito.when(webhookDeliveryVO.getWebhookName()).thenReturn("webhookName");
+ Mockito.when(webhookDeliveryVO.getManagementServerUuId()).thenReturn("managementServerUuid");
+ Mockito.when(webhookDeliveryVO.getManagementServerName()).thenReturn("managementServerName");
+ Mockito.when(webhookDeliveryVO.getHeaders()).thenReturn("headers");
+ Mockito.when(webhookDeliveryVO.getPayload()).thenReturn("payload");
+ Mockito.when(webhookDeliveryVO.isSuccess()).thenReturn(true);
+ Mockito.when(webhookDeliveryVO.getResponse()).thenReturn("response");
+ Mockito.when(webhookDeliveryVO.getStartTime()).thenReturn(new Date(1000));
+ Mockito.when(webhookDeliveryVO.getEndTime()).thenReturn(new Date(2000));
+
+ WebhookDeliveryResponse response = webhookApiServiceImpl.createWebhookDeliveryResponse(webhookDeliveryVO);
+
+ Assert.assertEquals("webhookdelivery", ReflectionTestUtils.getField(response, "objectName"));
+ Assert.assertEquals("uuid", ReflectionTestUtils.getField(response, "id"));
+ Assert.assertEquals("eventUuid", ReflectionTestUtils.getField(response, "eventId"));
+ Assert.assertEquals("eventType", ReflectionTestUtils.getField(response, "eventType"));
+ Assert.assertEquals("webhookUuid", ReflectionTestUtils.getField(response, "webhookId"));
+ Assert.assertEquals("webhookName", ReflectionTestUtils.getField(response, "webhookName"));
+ Assert.assertEquals("managementServerUuid", ReflectionTestUtils.getField(response, "managementServerId"));
+ Assert.assertEquals("managementServerName", ReflectionTestUtils.getField(response, "managementServerName"));
+ Assert.assertEquals("headers", ReflectionTestUtils.getField(response, "headers"));
+ Assert.assertEquals("payload", ReflectionTestUtils.getField(response, "payload"));
+ Assert.assertTrue((Boolean) ReflectionTestUtils.getField(response, "success"));
+ Assert.assertEquals("response", ReflectionTestUtils.getField(response, "response"));
+ Assert.assertEquals(new Date(1000), ReflectionTestUtils.getField(response, "startTime"));
+ Assert.assertEquals(new Date(2000), ReflectionTestUtils.getField(response, "endTime"));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void createWebhookDeliveryResponseThrowsExceptionForNullInput() {
+ webhookApiServiceImpl.createWebhookDeliveryResponse(null);
+ }
+
+ @Test
+ public void createTestWebhookDeliveryResponsePopulatesAllFieldsCorrectly() {
+ WebhookDelivery webhookDelivery = Mockito.mock(WebhookDelivery.class);
+ Mockito.when(webhookDelivery.getUuid()).thenReturn("uuid");
+ Mockito.when(webhookDelivery.getManagementServerId()).thenReturn(1L);
+ Mockito.when(webhookDelivery.getHeaders()).thenReturn("headers");
+ Mockito.when(webhookDelivery.getPayload()).thenReturn("payload");
+ Mockito.when(webhookDelivery.isSuccess()).thenReturn(true);
+ Mockito.when(webhookDelivery.getResponse()).thenReturn("response");
+ Mockito.when(webhookDelivery.getStartTime()).thenReturn(new Date(1000));
+ Mockito.when(webhookDelivery.getEndTime()).thenReturn(new Date(2000));
+
+ Webhook webhook = Mockito.mock(Webhook.class);
+ Mockito.when(webhook.getUuid()).thenReturn("webhookUuid");
+ Mockito.when(webhook.getName()).thenReturn("webhookName");
+
+ ManagementServerHostVO msHost = Mockito.mock(ManagementServerHostVO.class);
+ Mockito.when(msHost.getUuid()).thenReturn("managementServerUuid");
+ Mockito.when(msHost.getName()).thenReturn("managementServerName");
+ Mockito.when(managementServerHostDao.findByMsid(1L)).thenReturn(msHost);
+
+ WebhookDeliveryResponse response = webhookApiServiceImpl.createTestWebhookDeliveryResponse(webhookDelivery, webhook);
+
+ Assert.assertEquals("webhookdelivery", ReflectionTestUtils.getField(response, "objectName"));
+ Assert.assertEquals("uuid", ReflectionTestUtils.getField(response, "id"));
+ Assert.assertEquals(WebhookDelivery.TEST_EVENT_TYPE, ReflectionTestUtils.getField(response, "eventType"));
+ Assert.assertEquals("webhookUuid", ReflectionTestUtils.getField(response, "webhookId"));
+ Assert.assertEquals("webhookName", ReflectionTestUtils.getField(response, "webhookName"));
+ Assert.assertEquals("managementServerUuid", ReflectionTestUtils.getField(response, "managementServerId"));
+ Assert.assertEquals("managementServerName", ReflectionTestUtils.getField(response, "managementServerName"));
+ Assert.assertEquals("headers", ReflectionTestUtils.getField(response, "headers"));
+ Assert.assertEquals("payload", ReflectionTestUtils.getField(response, "payload"));
+ Assert.assertTrue((Boolean) ReflectionTestUtils.getField(response, "success"));
+ Assert.assertEquals("response", ReflectionTestUtils.getField(response, "response"));
+ Assert.assertEquals(new Date(1000), ReflectionTestUtils.getField(response, "startTime"));
+ Assert.assertEquals(new Date(2000), ReflectionTestUtils.getField(response, "endTime"));
+ }
+
+ @Test
+ public void createTestWebhookDeliveryResponseHandlesNullWebhook() {
+ WebhookDelivery webhookDelivery = Mockito.mock(WebhookDelivery.class);
+ Mockito.when(webhookDelivery.getUuid()).thenReturn("uuid");
+ Mockito.when(webhookDelivery.getManagementServerId()).thenReturn(1L);
+ Mockito.when(webhookDelivery.getHeaders()).thenReturn("headers");
+ Mockito.when(webhookDelivery.getPayload()).thenReturn("payload");
+ Mockito.when(webhookDelivery.isSuccess()).thenReturn(true);
+ Mockito.when(webhookDelivery.getResponse()).thenReturn("response");
+ Mockito.when(webhookDelivery.getStartTime()).thenReturn(new Date(1000));
+ Mockito.when(webhookDelivery.getEndTime()).thenReturn(new Date(2000));
+
+ ManagementServerHostVO msHost = Mockito.mock(ManagementServerHostVO.class);
+ Mockito.when(msHost.getUuid()).thenReturn("managementServerUuid");
+ Mockito.when(msHost.getName()).thenReturn("managementServerName");
+ Mockito.when(managementServerHostDao.findByMsid(1L)).thenReturn(msHost);
+
+ WebhookDeliveryResponse response = webhookApiServiceImpl.createTestWebhookDeliveryResponse(webhookDelivery, null);
+
+ Assert.assertEquals("webhookdelivery", ReflectionTestUtils.getField(response, "objectName"));
+ Assert.assertEquals("uuid", ReflectionTestUtils.getField(response, "id"));
+ Assert.assertEquals(WebhookDelivery.TEST_EVENT_TYPE, ReflectionTestUtils.getField(response, "eventType"));
+ Assert.assertNull(ReflectionTestUtils.getField(response, "webhookId"));
+ Assert.assertNull(ReflectionTestUtils.getField(response, "webhookName"));
+ Assert.assertEquals("managementServerUuid", ReflectionTestUtils.getField(response, "managementServerId"));
+ Assert.assertEquals("managementServerName", ReflectionTestUtils.getField(response, "managementServerName"));
+ Assert.assertEquals("headers", ReflectionTestUtils.getField(response, "headers"));
+ Assert.assertEquals("payload", ReflectionTestUtils.getField(response, "payload"));
+ Assert.assertTrue((Boolean) ReflectionTestUtils.getField(response, "success"));
+ Assert.assertEquals("response", ReflectionTestUtils.getField(response, "response"));
+ Assert.assertEquals(new Date(1000), ReflectionTestUtils.getField(response, "startTime"));
+ Assert.assertEquals(new Date(2000), ReflectionTestUtils.getField(response, "endTime"));
+ }
+
+ @Test
+ public void createTestWebhookDeliveryResponseHandlesNullManagementServer() {
+ WebhookDelivery webhookDelivery = Mockito.mock(WebhookDelivery.class);
+ Mockito.when(webhookDelivery.getUuid()).thenReturn("uuid");
+ Mockito.when(webhookDelivery.getManagementServerId()).thenReturn(1L);
+ Mockito.when(webhookDelivery.getHeaders()).thenReturn("headers");
+ Mockito.when(webhookDelivery.getPayload()).thenReturn("payload");
+ Mockito.when(webhookDelivery.isSuccess()).thenReturn(true);
+ Mockito.when(webhookDelivery.getResponse()).thenReturn("response");
+ Mockito.when(webhookDelivery.getStartTime()).thenReturn(new Date(1000));
+ Mockito.when(webhookDelivery.getEndTime()).thenReturn(new Date(2000));
+
+ Webhook webhook = Mockito.mock(Webhook.class);
+ Mockito.when(webhook.getUuid()).thenReturn("webhookUuid");
+ Mockito.when(webhook.getName()).thenReturn("webhookName");
+
+ Mockito.when(managementServerHostDao.findByMsid(1L)).thenReturn(null);
+
+ WebhookDeliveryResponse response = webhookApiServiceImpl.createTestWebhookDeliveryResponse(webhookDelivery, webhook);
+
+ Assert.assertEquals("webhookdelivery", ReflectionTestUtils.getField(response, "objectName"));
+ Assert.assertEquals("uuid", ReflectionTestUtils.getField(response, "id"));
+ Assert.assertEquals(WebhookDelivery.TEST_EVENT_TYPE, ReflectionTestUtils.getField(response, "eventType"));
+ Assert.assertEquals("webhookUuid", ReflectionTestUtils.getField(response, "webhookId"));
+ Assert.assertEquals("webhookName", ReflectionTestUtils.getField(response, "webhookName"));
+ Assert.assertNull(ReflectionTestUtils.getField(response, "managementServerId"));
+ Assert.assertNull(ReflectionTestUtils.getField(response, "managementServerName"));
+ Assert.assertEquals("headers", ReflectionTestUtils.getField(response, "headers"));
+ Assert.assertEquals("payload", ReflectionTestUtils.getField(response, "payload"));
+ Assert.assertTrue((Boolean) ReflectionTestUtils.getField(response, "success"));
+ Assert.assertEquals("response", ReflectionTestUtils.getField(response, "response"));
+ Assert.assertEquals(new Date(1000), ReflectionTestUtils.getField(response, "startTime"));
+ Assert.assertEquals(new Date(2000), ReflectionTestUtils.getField(response, "endTime"));
+ }
+
+ @Test
+ public void getOwnerReturnsFinalizedOwnerForValidInput() {
+ CreateWebhookCmd cmd = Mockito.mock(CreateWebhookCmd.class);
+ Account finalizedOwner = Mockito.mock(Account.class);
+
+ Mockito.when(cmd.getAccountName()).thenReturn("accountName");
+ Mockito.when(cmd.getDomainId()).thenReturn(1L);
+ Mockito.when(cmd.getProjectId()).thenReturn(2L);
+ Mockito.when(accountManager.finalizeOwner(caller, "accountName", 1L, 2L)).thenReturn(finalizedOwner);
+
+ Account result = webhookApiServiceImpl.getOwner(cmd);
+
+ Assert.assertEquals(finalizedOwner, result);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void getOwnerThrowsExceptionForInvalidAccount() {
+ CreateWebhookCmd cmd = Mockito.mock(CreateWebhookCmd.class);
+
+ Mockito.when(cmd.getAccountName()).thenReturn("invalidAccount");
+ Mockito.when(cmd.getDomainId()).thenReturn(1L);
+ Mockito.when(cmd.getProjectId()).thenReturn(null);
+ Mockito.when(accountManager.finalizeOwner(caller, "invalidAccount", 1L, null))
+ .thenThrow(new InvalidParameterValueException("Invalid account"));
+
+ webhookApiServiceImpl.getOwner(cmd);
+ }
+
+ @Test
+ public void createWebhookFilterResponsePopulatesAllFieldsCorrectly() {
+ WebhookFilter webhookFilter = Mockito.mock(WebhookFilter.class);
+ Mockito.when(webhookFilter.getUuid()).thenReturn("filterUuid");
+ Mockito.when(webhookFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(webhookFilter.getMode()).thenReturn(WebhookFilter.Mode.Include);
+ Mockito.when(webhookFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(webhookFilter.getValue()).thenReturn("value");
+ Mockito.when(webhookFilter.getCreated()).thenReturn(new Date(1000));
+
+ WebhookVO webhookVO = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhookVO.getUuid()).thenReturn("webhookUuid");
+ Mockito.when(webhookVO.getName()).thenReturn("webhookName");
+
+ WebhookFilterResponse response = webhookApiServiceImpl.createWebhookFilterResponse(webhookFilter, webhookVO);
+
+ Assert.assertEquals("webhookfilter", ReflectionTestUtils.getField(response, "objectName"));
+ Assert.assertEquals("filterUuid", ReflectionTestUtils.getField(response, "id"));
+ Assert.assertEquals("webhookUuid", ReflectionTestUtils.getField(response, "webhookId"));
+ Assert.assertEquals("webhookName", ReflectionTestUtils.getField(response, "webhookName"));
+ Assert.assertEquals("EventType", ReflectionTestUtils.getField(response, "type"));
+ Assert.assertEquals("Include", ReflectionTestUtils.getField(response, "mode"));
+ Assert.assertEquals("Exact", ReflectionTestUtils.getField(response, "matchType"));
+ Assert.assertEquals("value", ReflectionTestUtils.getField(response, "value"));
+ Assert.assertEquals(new Date(1000), ReflectionTestUtils.getField(response, "created"));
+ }
+
+ @Test
+ public void createWebhookFilterResponseHandlesNullWebhookVO() {
+ WebhookFilter webhookFilter = Mockito.mock(WebhookFilter.class);
+ Mockito.when(webhookFilter.getUuid()).thenReturn("filterUuid");
+ Mockito.when(webhookFilter.getWebhookId()).thenReturn(1L);
+ Mockito.when(webhookFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(webhookFilter.getMode()).thenReturn(WebhookFilter.Mode.Include);
+ Mockito.when(webhookFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(webhookFilter.getValue()).thenReturn("value");
+ Mockito.when(webhookFilter.getCreated()).thenReturn(new Date(1000));
+
+ WebhookVO webhookVO = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhookVO.getUuid()).thenReturn("webhookUuid");
+ Mockito.when(webhookVO.getName()).thenReturn("webhookName");
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhookVO);
+
+ WebhookFilterResponse response = webhookApiServiceImpl.createWebhookFilterResponse(webhookFilter, null);
+
+ Assert.assertEquals("webhookfilter", ReflectionTestUtils.getField(response, "objectName"));
+ Assert.assertEquals("filterUuid", ReflectionTestUtils.getField(response, "id"));
+ Assert.assertEquals("webhookUuid", ReflectionTestUtils.getField(response, "webhookId"));
+ Assert.assertEquals("webhookName", ReflectionTestUtils.getField(response, "webhookName"));
+ Assert.assertEquals("EventType", ReflectionTestUtils.getField(response, "type"));
+ Assert.assertEquals("Include", ReflectionTestUtils.getField(response, "mode"));
+ Assert.assertEquals("Exact", ReflectionTestUtils.getField(response, "matchType"));
+ Assert.assertEquals("value", ReflectionTestUtils.getField(response, "value"));
+ Assert.assertEquals(new Date(1000), ReflectionTestUtils.getField(response, "created"));
+ }
+
+ @Test
+ public void createWebhookFilterResponseHandlesNullWebhookFromDao() {
+ WebhookFilter webhookFilter = Mockito.mock(WebhookFilter.class);
+ Mockito.when(webhookFilter.getUuid()).thenReturn("filterUuid");
+ Mockito.when(webhookFilter.getWebhookId()).thenReturn(1L);
+ Mockito.when(webhookFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(webhookFilter.getMode()).thenReturn(WebhookFilter.Mode.Include);
+ Mockito.when(webhookFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(webhookFilter.getValue()).thenReturn("value");
+ Mockito.when(webhookFilter.getCreated()).thenReturn(new Date(1000));
+
+ Mockito.when(webhookDao.findById(1L)).thenReturn(null);
+
+ WebhookFilterResponse response = webhookApiServiceImpl.createWebhookFilterResponse(webhookFilter, null);
+
+ Assert.assertEquals("webhookfilter", ReflectionTestUtils.getField(response, "objectName"));
+ Assert.assertEquals("filterUuid", ReflectionTestUtils.getField(response, "id"));
+ Assert.assertNull(ReflectionTestUtils.getField(response, "webhookId"));
+ Assert.assertNull(ReflectionTestUtils.getField(response, "webhookName"));
+ Assert.assertEquals("EventType", ReflectionTestUtils.getField(response, "type"));
+ Assert.assertEquals("Include", ReflectionTestUtils.getField(response, "mode"));
+ Assert.assertEquals("Exact", ReflectionTestUtils.getField(response, "matchType"));
+ Assert.assertEquals("value", ReflectionTestUtils.getField(response, "value"));
+ Assert.assertEquals(new Date(1000), ReflectionTestUtils.getField(response, "created"));
+ }
+
+ @Test
+ public void listWebhooksReturnsEmptyResponseForNoWebhooks() {
+ ListWebhooksCmd cmd = Mockito.mock(ListWebhooksCmd.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getState()).thenReturn(null);
+ Mockito.when(cmd.getName()).thenReturn(null);
+ Mockito.when(cmd.getKeyword()).thenReturn(null);
+ Mockito.when(cmd.getScope()).thenReturn(null);
+ Mockito.when(cmd.getStartIndex()).thenReturn(0L);
+ Mockito.when(cmd.getPageSizeVal()).thenReturn(10L);
+ SearchBuilder<WebhookJoinVO> sb = Mockito.mock(SearchBuilder.class);
+ Mockito.when(sb.entity()).thenReturn(Mockito.mock(WebhookJoinVO.class));
+ SearchCriteria<WebhookJoinVO> sc = Mockito.mock(SearchCriteria.class);
+ Mockito.when(sb.create()).thenReturn(sc);
+ Mockito.when(webhookJoinDao.createSearchBuilder()).thenReturn(sb);
+ Mockito.when(webhookJoinDao.searchAndCount(Mockito.any(), Mockito.any())).thenReturn(new Pair<>(List.of(), 0));
+
+ ListResponse<WebhookResponse> response = webhookApiServiceImpl.listWebhooks(cmd);
+
+ Assert.assertTrue(response.getResponses().isEmpty());
+ Assert.assertEquals(0, (int) response.getCount());
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void listWebhooksThrowsExceptionForInvalidScope() {
+ ListWebhooksCmd cmd = Mockito.mock(ListWebhooksCmd.class);
+
+ Mockito.when(cmd.getScope()).thenReturn("InvalidScope");
+
+ webhookApiServiceImpl.listWebhooks(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void listWebhooksThrowsExceptionForInvalidState() {
+ ListWebhooksCmd cmd = Mockito.mock(ListWebhooksCmd.class);
+
+ Mockito.when(cmd.getState()).thenReturn("InvalidState");
+
+ webhookApiServiceImpl.listWebhooks(cmd);
+ }
+
+ @Test
+ public void listWebhooksFiltersByValidScopeAndState() {
+ ListWebhooksCmd cmd = Mockito.mock(ListWebhooksCmd.class);
+ Mockito.when(caller.getType()).thenReturn(Account.Type.DOMAIN_ADMIN);
+ WebhookJoinVO webhook = Mockito.mock(WebhookJoinVO.class);
+ Mockito.when(webhook.getState()).thenReturn(Webhook.State.Enabled);
+ Mockito.when(webhook.getScope()).thenReturn(Webhook.Scope.Domain);
+
+ Mockito.when(cmd.getScope()).thenReturn("Domain");
+ Mockito.when(cmd.getState()).thenReturn("Enabled");
+ Mockito.when(cmd.getStartIndex()).thenReturn(0L);
+ Mockito.when(cmd.getPageSizeVal()).thenReturn(10L);
+ SearchBuilder<WebhookJoinVO> sb = Mockito.mock(SearchBuilder.class);
+ Mockito.when(sb.entity()).thenReturn(Mockito.mock(WebhookJoinVO.class));
+ SearchCriteria<WebhookJoinVO> sc = Mockito.mock(SearchCriteria.class);
+ Mockito.when(sb.create()).thenReturn(sc);
+ Mockito.when(webhookJoinDao.createSearchBuilder()).thenReturn(sb);
+ Mockito.when(webhookJoinDao.searchAndCount(Mockito.any(), Mockito.any())).thenReturn(new Pair<>(List.of(webhook), 1));
+
+ ListResponse<WebhookResponse> response = webhookApiServiceImpl.listWebhooks(cmd);
+
+ Assert.assertEquals(1, (int) response.getCount());
+ Assert.assertEquals(1, response.getResponses().size());
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void listWebhooksThrowsExceptionForUnauthorizedScope() {
+ ListWebhooksCmd cmd = Mockito.mock(ListWebhooksCmd.class);
+
+ Mockito.when(cmd.getScope()).thenReturn("Global");
+ Mockito.when(caller.getType()).thenReturn(Account.Type.NORMAL);
+
+ webhookApiServiceImpl.listWebhooks(cmd);
+ }
+
+ @Test
+ public void createWebhookCreatesWebhookSuccessfully() {
+ CreateWebhookCmd cmd = Mockito.mock(CreateWebhookCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ WebhookJoinVO webhookJoinVO = Mockito.mock(WebhookJoinVO.class);
+ Mockito.when(webhookJoinVO.getState()).thenReturn(Webhook.State.Enabled);
+ Mockito.when(webhookJoinVO.getScope()).thenReturn(Webhook.Scope.Local);
+
+ Mockito.when(cmd.getName()).thenReturn("webhookName");
+ Mockito.when(cmd.getDescription()).thenReturn("webhookDescription");
+ Mockito.when(cmd.getPayloadUrl()).thenReturn("https://example.com");
+ Mockito.when(cmd.getSecretKey()).thenReturn("secretKey");
+ Mockito.when(cmd.isSslVerification()).thenReturn(true);
+ Mockito.when(cmd.getScope()).thenReturn("Local");
+ Mockito.when(cmd.getState()).thenReturn("Enabled");
+ Mockito.when(caller.getType()).thenReturn(Account.Type.ADMIN);
+ Mockito.when(caller.getDomainId()).thenReturn(1L);
+ Mockito.when(webhookDao.persist(Mockito.any(WebhookVO.class))).thenReturn(webhook);
+ Mockito.when(webhook.getId()).thenReturn(1L);
+ Mockito.when(webhookJoinDao.findById(1L)).thenReturn(webhookJoinVO);
+ Mockito.doReturn(caller).when(webhookApiServiceImpl).getOwner(cmd);
+
+ WebhookResponse response = webhookApiServiceImpl.createWebhook(cmd);
+
+ Assert.assertNotNull(response);
+ Assert.assertEquals("webhook", ReflectionTestUtils.getField(response, "objectName"));
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void createWebhookThrowsExceptionForInvalidScope() {
+ CreateWebhookCmd cmd = Mockito.mock(CreateWebhookCmd.class);
+
+ Mockito.when(cmd.getScope()).thenReturn("InvalidScope");
+
+ webhookApiServiceImpl.createWebhook(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void createWebhookThrowsExceptionForInvalidState() {
+ CreateWebhookCmd cmd = Mockito.mock(CreateWebhookCmd.class);
+
+ Mockito.when(cmd.getState()).thenReturn("InvalidState");
+
+ webhookApiServiceImpl.createWebhook(cmd);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void createWebhookThrowsExceptionForInvalidUrl() {
+ CreateWebhookCmd cmd = Mockito.mock(CreateWebhookCmd.class);
+
+ Mockito.when(cmd.getPayloadUrl()).thenReturn("invalid-url");
+ Mockito.doReturn(caller).when(webhookApiServiceImpl).getOwner(cmd);
+
+ webhookApiServiceImpl.createWebhook(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void createWebhookThrowsExceptionForNonHttpsWithSslVerification() {
+ CreateWebhookCmd cmd = Mockito.mock(CreateWebhookCmd.class);
+
+ Mockito.when(cmd.getPayloadUrl()).thenReturn("http://example.com");
+ Mockito.when(cmd.isSslVerification()).thenReturn(true);
+ Mockito.doReturn(caller).when(webhookApiServiceImpl).getOwner(cmd);
+ Mockito.doNothing().when(webhookApiServiceImpl)
+ .validateWebhookOwnerPayloadUrl(caller, "http://example.com", null);
+
+ webhookApiServiceImpl.createWebhook(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void createWebhookThrowsExceptionForDuplicatePayloadUrl() {
+ CreateWebhookCmd cmd = Mockito.mock(CreateWebhookCmd.class);
+ WebhookVO existingWebhook = Mockito.mock(WebhookVO.class);
+
+ Mockito.when(cmd.getPayloadUrl()).thenReturn("https://example.com");
+ Mockito.when(caller.getId()).thenReturn(1L);
+ Mockito.doReturn(caller).when(webhookApiServiceImpl).getOwner(cmd);
+ Mockito.when(webhookDao.findByAccountAndPayloadUrl(1L, "https://example.com")).thenReturn(existingWebhook);
+
+ webhookApiServiceImpl.createWebhook(cmd);
+ }
+
+ @Test
+ public void updateWebhookUpdatesAllFieldsSuccessfully() {
+ UpdateWebhookCmd cmd = Mockito.mock(UpdateWebhookCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhook.getId()).thenReturn(1L);
+ Mockito.when(webhook.getPayloadUrl()).thenReturn("http://abc.xyz");
+ String updatedUrl = "https://cloudstack.apache.org/";
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getName()).thenReturn("Updated Name");
+ Mockito.when(cmd.getDescription()).thenReturn("Updated Description");
+ Mockito.when(cmd.getPayloadUrl()).thenReturn(updatedUrl);
+ Mockito.when(cmd.getSecretKey()).thenReturn("UpdatedSecretKey");
+ Mockito.when(cmd.isSslVerification()).thenReturn(true);
+ Mockito.when(cmd.getScope()).thenReturn("Local");
+ Mockito.when(cmd.getState()).thenReturn("Enabled");
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+ Mockito.when(webhook.getAccountId()).thenReturn(1L);
+ Mockito.when(accountManager.getAccount(1L)).thenReturn(caller);
+ Mockito.when(webhookDao.update(1L, webhook)).thenReturn(true);
+ Mockito.doReturn(Mockito.mock(WebhookResponse.class)).when(webhookApiServiceImpl)
+ .createWebhookResponse(1L);
+
+ WebhookResponse response = webhookApiServiceImpl.updateWebhook(cmd);
+
+
+ Assert.assertNotNull(response);
+ Mockito.verify(webhook).setName("Updated Name");
+ Mockito.verify(webhook).setDescription("Updated Description");
+ Mockito.verify(webhook).setPayloadUrl(updatedUrl);
+ Mockito.verify(webhook).setSecretKey("UpdatedSecretKey");
+ Mockito.verify(webhook).setSslVerification(true);
+ Mockito.verify(webhook).setScope(Webhook.Scope.Local);
+ Mockito.verify(webhook).setState(Webhook.State.Enabled);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void updateWebhookThrowsExceptionForInvalidState() {
+ UpdateWebhookCmd cmd = Mockito.mock(UpdateWebhookCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getState()).thenReturn("InvalidState");
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+
+ webhookApiServiceImpl.updateWebhook(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void updateWebhookThrowsExceptionForInvalidScope() {
+ UpdateWebhookCmd cmd = Mockito.mock(UpdateWebhookCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getScope()).thenReturn("InvalidScope");
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+ Mockito.when(webhook.getAccountId()).thenReturn(1L);
+ Mockito.when(accountManager.getAccount(1L)).thenReturn(caller);
+
+ webhookApiServiceImpl.updateWebhook(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void updateWebhookThrowsExceptionForNonHttpsWithSslVerification() {
+ UpdateWebhookCmd cmd = Mockito.mock(UpdateWebhookCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhook.getPayloadUrl()).thenReturn("http://abc.xyz");
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getPayloadUrl()).thenReturn("http://cloudstack.apache.org/");
+ Mockito.when(cmd.isSslVerification()).thenReturn(true);
+ Mockito.when(webhook.getAccountId()).thenReturn(1L);
+ Mockito.when(accountManager.getAccount(1L)).thenReturn(caller);
+ Mockito.doNothing().when(webhookApiServiceImpl)
+ .validateWebhookOwnerPayloadUrl(caller, "http://cloudstack.apache.org/", webhook);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+
+ webhookApiServiceImpl.updateWebhook(cmd);
+ }
+
+ @Test
+ public void updateWebhookDoesNotUpdateUnchangedFields() {
+ UpdateWebhookCmd cmd = Mockito.mock(UpdateWebhookCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhook.getId()).thenReturn(1L);
+ Mockito.when(webhook.getPayloadUrl()).thenReturn("http://abc.xyz");
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getName()).thenReturn(null);
+ Mockito.when(cmd.getDescription()).thenReturn(null);
+ Mockito.when(cmd.getPayloadUrl()).thenReturn(null);
+ Mockito.when(cmd.getSecretKey()).thenReturn(null);
+ Mockito.when(cmd.isSslVerification()).thenReturn(null);
+ Mockito.when(cmd.getScope()).thenReturn(null);
+ Mockito.when(cmd.getState()).thenReturn(null);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+ Mockito.doReturn(Mockito.mock(WebhookResponse.class)).when(webhookApiServiceImpl)
+ .createWebhookResponse(1L);
+
+ WebhookResponse response = webhookApiServiceImpl.updateWebhook(cmd);
+
+ Assert.assertNotNull(response);
+ Mockito.verify(webhookDao, Mockito.never()).update(Mockito.anyLong(), Mockito.any());
+ }
+
+ @Test
+ public void listWebhookDeliveriesReturnsEmptyResponseForNoDeliveries() {
+ ListWebhookDeliveriesCmd cmd = Mockito.mock(ListWebhookDeliveriesCmd.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(null);
+ Mockito.when(cmd.getManagementServerId()).thenReturn(null);
+ Mockito.when(cmd.getKeyword()).thenReturn(null);
+ Mockito.when(cmd.getStartDate()).thenReturn(null);
+ Mockito.when(cmd.getEndDate()).thenReturn(null);
+ Mockito.when(cmd.getEventType()).thenReturn(null);
+ Mockito.when(cmd.getStartIndex()).thenReturn(0L);
+ Mockito.when(cmd.getPageSizeVal()).thenReturn(10L);
+ Mockito.when(webhookDeliveryJoinDao.searchAndCountByListApiParameters(Mockito.any(), Mockito.anyList(),
+ Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))
+ .thenReturn(new Pair<>(List.of(), 0));
+
+ ListResponse<WebhookDeliveryResponse> response = webhookApiServiceImpl.listWebhookDeliveries(cmd);
+
+ Assert.assertNotNull(response);
+ Assert.assertTrue(response.getResponses().isEmpty());
+ Assert.assertEquals(0, (int) response.getCount());
+ }
+
+ @Test
+ public void listWebhookDeliveriesFiltersByWebhookId() {
+ ListWebhookDeliveriesCmd cmd = Mockito.mock(ListWebhookDeliveriesCmd.class);
+ WebhookDeliveryJoinVO delivery = Mockito.mock(WebhookDeliveryJoinVO.class);
+ WebhookDeliveryResponse deliveryResponse = Mockito.mock(WebhookDeliveryResponse.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(1L);
+ Mockito.when(cmd.getManagementServerId()).thenReturn(null);
+ Mockito.when(cmd.getStartIndex()).thenReturn(0L);
+ Mockito.when(cmd.getPageSizeVal()).thenReturn(10L);
+ Mockito.when(webhookDeliveryJoinDao.searchAndCountByListApiParameters(Mockito.any(), Mockito.anyList(),
+ Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))
+ .thenReturn(new Pair<>(List.of(delivery), 1));
+ Mockito.doReturn(deliveryResponse).when(webhookApiServiceImpl).createWebhookDeliveryResponse(delivery);
+ Mockito.doReturn(null).when(webhookApiServiceImpl)
+ .basicWebhookDeliveryApiCheck(caller, null, 1L, null, null, null);
+
+ ListResponse<WebhookDeliveryResponse> response = webhookApiServiceImpl.listWebhookDeliveries(cmd);
+
+ Assert.assertNotNull(response);
+ Assert.assertEquals(1, response.getResponses().size());
+ Assert.assertEquals(deliveryResponse, response.getResponses().get(0));
+ Assert.assertEquals(1, (int) response.getCount());
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void listWebhookDeliveriesThrowsExceptionForEndDateBeforeStartDate() {
+ ListWebhookDeliveriesCmd cmd = Mockito.mock(ListWebhookDeliveriesCmd.class);
+
+ Mockito.when(cmd.getStartDate()).thenReturn(new Date(System.currentTimeMillis()));
+ Mockito.when(cmd.getEndDate()).thenReturn(new Date(System.currentTimeMillis() - 1000));
+
+ webhookApiServiceImpl.listWebhookDeliveries(cmd);
+ }
+
+ @Test
+ public void listWebhookDeliveriesFiltersByEventType() {
+ ListWebhookDeliveriesCmd cmd = Mockito.mock(ListWebhookDeliveriesCmd.class);
+ WebhookDeliveryJoinVO delivery = Mockito.mock(WebhookDeliveryJoinVO.class);
+ WebhookDeliveryResponse deliveryResponse = Mockito.mock(WebhookDeliveryResponse.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(null);
+ Mockito.when(cmd.getManagementServerId()).thenReturn(null);
+ Mockito.when(cmd.getEventType()).thenReturn("EventType");
+ Mockito.when(cmd.getStartIndex()).thenReturn(0L);
+ Mockito.when(cmd.getPageSizeVal()).thenReturn(10L);
+ Mockito.when(webhookDeliveryJoinDao.searchAndCountByListApiParameters(Mockito.any(), Mockito.anyList(),
+ Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))
+ .thenReturn(new Pair<>(List.of(delivery), 1));
+ Mockito.doReturn(deliveryResponse).when(webhookApiServiceImpl).createWebhookDeliveryResponse(delivery);
+
+ ListResponse<WebhookDeliveryResponse> response = webhookApiServiceImpl.listWebhookDeliveries(cmd);
+
+ Assert.assertNotNull(response);
+ Assert.assertEquals(1, response.getResponses().size());
+ Assert.assertEquals(deliveryResponse, response.getResponses().get(0));
+ Assert.assertEquals(1, (int) response.getCount());
+ }
+
+ @Test
+ public void deleteWebhookDeliveryRemovesDeliveriesSuccessfully() {
+ DeleteWebhookDeliveryCmd cmd = Mockito.mock(DeleteWebhookDeliveryCmd.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(1L);
+ Mockito.when(cmd.getManagementServerId()).thenReturn(null);
+ Mockito.when(cmd.getStartDate()).thenReturn(null);
+ Mockito.when(cmd.getEndDate()).thenReturn(null);
+ Mockito.doReturn(null).when(webhookApiServiceImpl)
+ .basicWebhookDeliveryApiCheck(caller, null, 1L, null, null, null);
+ Mockito.when(webhookDeliveryDao.deleteByDeleteApiParams(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(5);
+
+ int removed = webhookApiServiceImpl.deleteWebhookDelivery(cmd);
+
+ Assert.assertEquals(5, removed);
+ Mockito.verify(webhookDeliveryDao).deleteByDeleteApiParams(null, 1L, null, null, null);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void deleteWebhookDeliveryThrowsExceptionForInvalidDates() {
+ DeleteWebhookDeliveryCmd cmd = Mockito.mock(DeleteWebhookDeliveryCmd.class);
+ Mockito.when(cmd.getStartDate()).thenReturn(new Date(System.currentTimeMillis()));
+ Mockito.when(cmd.getEndDate()).thenReturn(new Date(System.currentTimeMillis() - 1000));
+
+ webhookApiServiceImpl.deleteWebhookDelivery(cmd);
+ }
+
+ @Test
+ public void deleteWebhookDeliveryHandlesNoDeliveriesToRemove() {
+ DeleteWebhookDeliveryCmd cmd = Mockito.mock(DeleteWebhookDeliveryCmd.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(1L);
+ Mockito.when(cmd.getManagementServerId()).thenReturn(null);
+ Mockito.when(cmd.getStartDate()).thenReturn(null);
+ Mockito.when(cmd.getEndDate()).thenReturn(null);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(Mockito.mock(WebhookVO.class));
+ Mockito.when(webhookDeliveryDao.deleteByDeleteApiParams(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(0);
+
+ int removed = webhookApiServiceImpl.deleteWebhookDelivery(cmd);
+
+ Assert.assertEquals(0, removed);
+ Mockito.verify(webhookDeliveryDao).deleteByDeleteApiParams(null, 1L, null, null, null);
+ }
+
+ @Test(expected = PermissionDeniedException.class)
+ public void deleteWebhookDeliveryThrowsExceptionForUnauthorizedAccess() {
+ DeleteWebhookDeliveryCmd cmd = Mockito.mock(DeleteWebhookDeliveryCmd.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(1L);
+ Mockito.when(caller.getType()).thenReturn(Account.Type.NORMAL);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(Mockito.mock(WebhookVO.class));
+
+ webhookApiServiceImpl.deleteWebhookDelivery(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void executeWebhookDeliveryThrowsExceptionWhenNoIdentifiersProvided() {
+ ExecuteWebhookDeliveryCmd cmd = Mockito.mock(ExecuteWebhookDeliveryCmd.class);
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(null);
+ Mockito.when(cmd.getPayloadUrl()).thenReturn(null);
+
+ webhookApiServiceImpl.executeWebhookDelivery(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void executeWebhookDeliveryThrowsExceptionWhenBothDeliveryIdAndWebhookIdProvided() {
+ ExecuteWebhookDeliveryCmd cmd = Mockito.mock(ExecuteWebhookDeliveryCmd.class);
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getWebhookId()).thenReturn(2L);
+
+ webhookApiServiceImpl.executeWebhookDelivery(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void executeWebhookDeliveryThrowsExceptionForInvalidDeliveryId() {
+ ExecuteWebhookDeliveryCmd cmd = Mockito.mock(ExecuteWebhookDeliveryCmd.class);
+ Mockito.when(cmd.getId()).thenReturn(1L);
+
+ webhookApiServiceImpl.executeWebhookDelivery(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void executeWebhookDeliveryThrowsExceptionForInvalidWebhookId() {
+ ExecuteWebhookDeliveryCmd cmd = Mockito.mock(ExecuteWebhookDeliveryCmd.class);
+ Mockito.when(cmd.getWebhookId()).thenReturn(1L);
+
+ webhookApiServiceImpl.executeWebhookDelivery(cmd);
+ }
+
+ @Test
+ public void executeWebhookDeliveryExecutesSuccessfullyForValidDeliveryId() {
+ ExecuteWebhookDeliveryCmd cmd = Mockito.mock(ExecuteWebhookDeliveryCmd.class);
+ WebhookDeliveryVO delivery = Mockito.mock(WebhookDeliveryVO.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ WebhookDelivery webhookDelivery = Mockito.mock(WebhookDelivery.class);
+ WebhookDeliveryResponse response = Mockito.mock(WebhookDeliveryResponse.class);
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getWebhookId()).thenReturn(null);
+ Mockito.when(webhookDeliveryDao.findById(1L)).thenReturn(delivery);
+ Mockito.when(delivery.getWebhookId()).thenReturn(2L);
+ Mockito.when(webhookDao.findById(2L)).thenReturn(webhook);
+ Mockito.when(webhookService.executeWebhookDelivery(delivery, webhook, null)).thenReturn(webhookDelivery);
+ Mockito.when(webhookDelivery.getId()).thenReturn(3L);
+ Mockito.when(webhookDeliveryJoinDao.findById(3L)).thenReturn(Mockito.mock(WebhookDeliveryJoinVO.class));
+ Mockito.doReturn(response).when(webhookApiServiceImpl).createWebhookDeliveryResponse(Mockito.any());
+
+ WebhookDeliveryResponse result = webhookApiServiceImpl.executeWebhookDelivery(cmd);
+
+ Assert.assertNotNull(result);
+ Assert.assertEquals(response, result);
+ }
+
+ @Test
+ public void executeWebhookDeliveryExecutesSuccessfullyForValidWebhookId() {
+ ExecuteWebhookDeliveryCmd cmd = Mockito.mock(ExecuteWebhookDeliveryCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ WebhookDelivery webhookDelivery = Mockito.mock(WebhookDelivery.class);
+ WebhookDeliveryResponse response = Mockito.mock(WebhookDeliveryResponse.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(1L);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+ Mockito.when(webhookService.executeWebhookDelivery(null, webhook, null)).thenReturn(webhookDelivery);
+ Mockito.when(webhookDelivery.getId()).thenReturn(WebhookDelivery.ID_DUMMY);
+ Mockito.doReturn(response).when(webhookApiServiceImpl).createTestWebhookDeliveryResponse(webhookDelivery, webhook);
+
+ WebhookDeliveryResponse result = webhookApiServiceImpl.executeWebhookDelivery(cmd);
+
+ Assert.assertNotNull(result);
+ Assert.assertEquals(response, result);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void executeWebhookDeliveryThrowsExceptionForInvalidPayloadUrl() {
+ ExecuteWebhookDeliveryCmd cmd = Mockito.mock(ExecuteWebhookDeliveryCmd.class);
+ Mockito.when(cmd.getPayloadUrl()).thenReturn("invalid-url");
+
+ webhookApiServiceImpl.executeWebhookDelivery(cmd);
+ }
+
+ @Test
+ public void executeWebhookDeliveryExecutesSuccessfullyForValidPayloadUrl() {
+ ExecuteWebhookDeliveryCmd cmd = Mockito.mock(ExecuteWebhookDeliveryCmd.class);
+ WebhookDelivery webhookDelivery = Mockito.mock(WebhookDelivery.class);
+ WebhookDeliveryResponse response = Mockito.mock(WebhookDeliveryResponse.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(null);
+ Mockito.when(cmd.getPayloadUrl()).thenReturn("https://example.com");
+ Mockito.when(webhookService.executeWebhookDelivery(Mockito.eq(null), Mockito.any(Webhook.class),
+ Mockito.eq(null))).thenReturn(webhookDelivery);
+ Mockito.when(webhookDelivery.getId()).thenReturn(WebhookDelivery.ID_DUMMY);
+ Mockito.doReturn(response).when(webhookApiServiceImpl).createTestWebhookDeliveryResponse(
+ Mockito.eq(webhookDelivery), Mockito.any(Webhook.class));
+
+ WebhookDeliveryResponse result = webhookApiServiceImpl.executeWebhookDelivery(cmd);
+
+ Assert.assertNotNull(result);
+ Assert.assertEquals(response, result);
+ }
+
+ @Test
+ public void listWebhookFiltersReturnsEmptyResponseForNoFilters() {
+ ListWebhookFiltersCmd cmd = Mockito.mock(ListWebhookFiltersCmd.class);
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(null);
+ Mockito.when(cmd.getStartIndex()).thenReturn(0L);
+ Mockito.when(cmd.getPageSizeVal()).thenReturn(10L);
+ Mockito.when(webhookFilterDao.searchBy(Mockito.any(), Mockito.any(), Mockito.anyLong(), Mockito.anyLong()))
+ .thenReturn(new Pair<>(List.of(), 0));
+
+ ListResponse<WebhookFilterResponse> response = webhookApiServiceImpl.listWebhookFilters(cmd);
+
+ Assert.assertNotNull(response);
+ Assert.assertTrue(response.getResponses().isEmpty());
+ }
+
+ @Test
+ public void listWebhookFiltersReturnsFiltersSuccessfully() {
+ ListWebhookFiltersCmd cmd = Mockito.mock(ListWebhookFiltersCmd.class);
+ WebhookFilterVO filter = Mockito.mock(WebhookFilterVO.class);
+ Mockito.when(filter.getWebhookId()).thenReturn(1L);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ WebhookFilterResponse filterResponse = Mockito.mock(WebhookFilterResponse.class);
+
+ Mockito.when(cmd.getId()).thenReturn(null);
+ Mockito.when(cmd.getWebhookId()).thenReturn(1L);
+ Mockito.when(cmd.getStartIndex()).thenReturn(0L);
+ Mockito.when(cmd.getPageSizeVal()).thenReturn(10L);
+ Mockito.when(webhookFilterDao.searchBy(Mockito.any(), Mockito.any(), Mockito.anyLong(), Mockito.anyLong()))
+ .thenReturn(new Pair<>(List.of(filter), 1));
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+ Mockito.doReturn(filterResponse).when(webhookApiServiceImpl).createWebhookFilterResponse(filter, webhook);
+
+ ListResponse<WebhookFilterResponse> response = webhookApiServiceImpl.listWebhookFilters(cmd);
+
+ Assert.assertNotNull(response);
+ Assert.assertEquals(1, response.getResponses().size());
+ Assert.assertEquals(filterResponse, response.getResponses().get(0));
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void addWebhookFilterThrowsExceptionForInvalidWebhookId() {
+ AddWebhookFilterCmd cmd = Mockito.mock(AddWebhookFilterCmd.class);
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(null);
+
+ webhookApiServiceImpl.addWebhookFilter(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void addWebhookFilterThrowsExceptionForInvalidMode() {
+ AddWebhookFilterCmd cmd = Mockito.mock(AddWebhookFilterCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getMode()).thenReturn("InvalidMode");
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+
+ webhookApiServiceImpl.addWebhookFilter(cmd);
+ }
+
+ @Test
+ public void addWebhookFilterAddsFilterSuccessfully() {
+ AddWebhookFilterCmd cmd = Mockito.mock(AddWebhookFilterCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ WebhookFilterVO filter = Mockito.mock(WebhookFilterVO.class);
+ WebhookFilterResponse filterResponse = Mockito.mock(WebhookFilterResponse.class);
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getType()).thenReturn("EventType");
+ Mockito.when(cmd.getMode()).thenReturn("Include");
+ Mockito.when(cmd.getMatchType()).thenReturn("Exact");
+ Mockito.when(cmd.getValue()).thenReturn("value");
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+ Mockito.when(webhookFilterDao.persist(Mockito.any(WebhookFilterVO.class))).thenReturn(filter);
+ Mockito.doReturn(filterResponse).when(webhookApiServiceImpl).createWebhookFilterResponse(filter, webhook);
+
+ WebhookFilterResponse response = webhookApiServiceImpl.addWebhookFilter(cmd);
+
+ Assert.assertNotNull(response);
+ Assert.assertEquals(filterResponse, response);
+ }
+
+ @Test
+ public void addWebhookFilterAddsFilterSuccessfullyEvenWithExisting() {
+ AddWebhookFilterCmd cmd = Mockito.mock(AddWebhookFilterCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ WebhookFilterVO filter = Mockito.mock(WebhookFilterVO.class);
+ WebhookFilterVO newFilter = Mockito.mock(WebhookFilterVO.class);
+ WebhookFilterResponse filterResponse = Mockito.mock(WebhookFilterResponse.class);
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(webhook.getId()).thenReturn(1L);
+ Mockito.when(filter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(filter.getMode()).thenReturn(WebhookFilter.Mode.Exclude);
+ Mockito.when(filter.getMatchType()).thenReturn(WebhookFilter.MatchType.Prefix);
+ Mockito.when(filter.getValue()).thenReturn("value.old");
+ Mockito.when(cmd.getType()).thenReturn("EventType");
+ Mockito.when(cmd.getMode()).thenReturn("Include");
+ Mockito.when(cmd.getMatchType()).thenReturn("Exact");
+ Mockito.when(cmd.getValue()).thenReturn("value");
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+ Mockito.when(webhookFilterDao.listByWebhook(1L)).thenReturn(List.of(filter));
+ Mockito.when(webhookFilterDao.persist(Mockito.any(WebhookFilterVO.class))).thenReturn(newFilter);
+ Mockito.doReturn(filterResponse).when(webhookApiServiceImpl).createWebhookFilterResponse(newFilter, webhook);
+
+ WebhookFilterResponse response = webhookApiServiceImpl.addWebhookFilter(cmd);
+
+ Assert.assertNotNull(response);
+ Assert.assertEquals(filterResponse, response);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void addWebhookFilterConflictsWithExisting() {
+ AddWebhookFilterCmd cmd = Mockito.mock(AddWebhookFilterCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ WebhookFilterVO filter = Mockito.mock(WebhookFilterVO.class);
+
+ Mockito.when(webhook.getId()).thenReturn(1L);
+ Mockito.when(filter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(filter.getMode()).thenReturn(WebhookFilter.Mode.Exclude);
+ Mockito.when(filter.getMatchType()).thenReturn(WebhookFilter.MatchType.Prefix);
+ Mockito.when(filter.getValue()).thenReturn("value");
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getType()).thenReturn("EventType");
+ Mockito.when(cmd.getMode()).thenReturn("Include");
+ Mockito.when(cmd.getMatchType()).thenReturn("Exact");
+ Mockito.when(cmd.getValue()).thenReturn("value.extra");
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+ Mockito.when(webhookFilterDao.listByWebhook(1L)).thenReturn(List.of(filter));
+
+ webhookApiServiceImpl.addWebhookFilter(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void addWebhookFilterSameEventConflictsWithExisting() {
+ AddWebhookFilterCmd cmd = Mockito.mock(AddWebhookFilterCmd.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ WebhookFilterVO filter = Mockito.mock(WebhookFilterVO.class);
+
+ Mockito.when(webhook.getId()).thenReturn(1L);
+ Mockito.when(filter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(filter.getMode()).thenReturn(WebhookFilter.Mode.Include);
+ Mockito.when(filter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(filter.getValue()).thenReturn(EventTypes.EVENT_VM_CREATE);
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(cmd.getType()).thenReturn(WebhookFilter.Type.EventType.name());
+ Mockito.when(cmd.getMode()).thenReturn(WebhookFilter.Mode.Exclude.name());
+ Mockito.when(cmd.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact.name());
+ Mockito.when(cmd.getValue()).thenReturn(EventTypes.EVENT_VM_CREATE);
+ Mockito.when(webhookDao.findById(1L)).thenReturn(webhook);
+ Mockito.when(webhookFilterDao.listByWebhook(1L)).thenReturn(List.of(filter));
+
+ webhookApiServiceImpl.addWebhookFilter(cmd);
+ }
+
+ @Test
+ public void deleteWebhookFilterDeletesFilterSuccessfully() {
+ DeleteWebhookFilterCmd cmd = Mockito.mock(DeleteWebhookFilterCmd.class);
+ WebhookFilterVO filter = Mockito.mock(WebhookFilterVO.class);
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(webhookFilterDao.searchBy(Mockito.any(), Mockito.any(), Mockito.anyLong(), Mockito.anyLong()))
+ .thenReturn(new Pair<>(List.of(filter), 1));
+ Mockito.when(webhookDao.findById(Mockito.anyLong())).thenReturn(webhook);
+ Mockito.when(webhookFilterDao.delete(Mockito.anyLong(), Mockito.anyLong())).thenReturn(1);
+
+ int result = webhookApiServiceImpl.deleteWebhookFilter(cmd);
+
+ Assert.assertEquals(1, result);
+ }
+
+ @Test
+ public void deleteWebhookFilterHandlesNoFiltersToDelete() {
+ DeleteWebhookFilterCmd cmd = Mockito.mock(DeleteWebhookFilterCmd.class);
+
+ Mockito.when(cmd.getId()).thenReturn(1L);
+ Mockito.when(webhookFilterDao.searchBy(Mockito.any(), Mockito.any(), Mockito.anyLong(), Mockito.anyLong()))
+ .thenReturn(new Pair<>(List.of(), 0));
+
+ int result = webhookApiServiceImpl.deleteWebhookFilter(cmd);
+
+ Assert.assertEquals(0, result);
+ }
}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/WebhookServiceImplTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/WebhookServiceImplTest.java
new file mode 100644
index 0000000..90c0c32
--- /dev/null
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/WebhookServiceImplTest.java
@@ -0,0 +1,669 @@
+// 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.mom.webhook;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
+import org.apache.cloudstack.framework.events.Event;
+import org.apache.cloudstack.framework.events.EventBusException;
+import org.apache.cloudstack.mom.webhook.dao.WebhookDao;
+import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryDao;
+import org.apache.cloudstack.mom.webhook.dao.WebhookFilterDao;
+import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
+import org.apache.cloudstack.mom.webhook.vo.WebhookVO;
+import org.apache.cloudstack.utils.cache.LazyCache;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import com.cloud.api.query.vo.EventJoinVO;
+import com.cloud.cluster.dao.ManagementServerHostDao;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.event.EventCategory;
+import com.cloud.event.dao.EventJoinDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WebhookServiceImplTest {
+ @Mock
+ EventJoinDao eventJoinDao;
+ @Mock
+ WebhookDao webhookDao;
+ @Mock
+ WebhookDeliveryDao webhookDeliveryDao;
+ @Mock
+ WebhookFilterDao webhookFilterDao;
+ @Mock
+ ManagementServerHostDao managementServerHostDao;
+ @Mock
+ DomainDao domainDao;
+ @Mock
+ AccountManager accountManager;
+
+ @Spy
+ @InjectMocks
+ private WebhookServiceImpl webhookServiceImpl;
+
+ MockedStatic<ComponentContext> componentContextMockedStatic;
+
+ @Before
+ public void setup() {
+ componentContextMockedStatic = Mockito.mockStatic(ComponentContext.class);
+ componentContextMockedStatic.when(() -> ComponentContext.inject(Mockito.any(WebhookDeliveryThread.class)))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ webhookServiceImpl.initCaches();
+ }
+
+ @After
+ public void tearDown() {
+ componentContextMockedStatic.close();
+ }
+
+ @Test
+ public void getDeliveryJobReturnsProperlyConfiguredJob() {
+ Event event = Mockito.mock(Event.class);
+ Webhook webhook = Mockito.mock(Webhook.class);
+ Pair<Integer, Integer> configs = new Pair<>(4, 5000);
+
+ Mockito.when(event.getEventId()).thenReturn(123L);
+ Mockito.when(webhook.getId()).thenReturn(456L);
+
+ WebhookDeliveryThread job = webhookServiceImpl.getDeliveryJob(event, webhook, configs);
+
+ Assert.assertNotNull(job);
+ Assert.assertEquals(4, ReflectionTestUtils.getField(job, "deliveryTries"));
+ Assert.assertEquals(5000, ReflectionTestUtils.getField(job, "deliveryTimeout"));
+ }
+
+ @Test
+ public void getDeliveryJobInjectsDependencies() {
+ Event event = Mockito.mock(Event.class);
+ Webhook webhook = Mockito.mock(Webhook.class);
+ Pair<Integer, Integer> configs = new Pair<>(1, 1000);
+
+ WebhookDeliveryThread job = webhookServiceImpl.getDeliveryJob(event, webhook, configs);
+
+ Mockito.verify(webhookServiceImpl, Mockito.times(1)).getDeliveryJob(event, webhook, configs);
+ componentContextMockedStatic.verify(() -> ComponentContext.inject(job), Mockito.times(1));
+ }
+
+ @Test
+ public void getEventValueByFilterTypeReturnsEventTypeWhenFilterTypeIsEventType() {
+ Event event = Mockito.mock(Event.class);
+ Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
+
+ String result = webhookServiceImpl.getEventValueByFilterType(event, WebhookFilter.Type.EventType);
+
+ Assert.assertEquals("USER.LOGIN", result);
+ }
+
+ @Test
+ public void getEventValueByFilterTypeReturnsNullWhenFilterTypeIsNotEventType() {
+ Event event = Mockito.mock(Event.class);
+
+ String result = webhookServiceImpl.getEventValueByFilterType(event, null);
+
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void isValueMatchingFilterReturnsTrueForExactMatch() {
+ boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Exact, "USER.LOGIN");
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isValueMatchingFilterReturnsFalseForNonExactMatch() {
+ boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Exact, "USER.LOGOUT");
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isValueMatchingFilterReturnsTrueForPrefixMatch() {
+ boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Prefix, "USER");
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isValueMatchingFilterReturnsFalseForNonPrefixMatch() {
+ boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Prefix, "ADMIN");
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isValueMatchingFilterReturnsTrueForSuffixMatch() {
+ boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Suffix, "LOGIN");
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isValueMatchingFilterReturnsFalseForNonSuffixMatch() {
+ boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Suffix, "LOGOUT");
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isValueMatchingFilterReturnsTrueForContainsMatch() {
+ boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Contains, "USER");
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isValueMatchingFilterReturnsFalseForNonContainsMatch() {
+ boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Contains, "ADMIN");
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isValueMatchingFilterReturnsFalseForNullFilterValue() {
+ boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Exact, null);
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isEventMatchingFiltersReturnsTrueWhenFiltersAreEmpty() {
+ List<WebhookFilter> filters = new ArrayList<>();
+
+ boolean result = webhookServiceImpl.isEventMatchingFilters(Mockito.mock(Event.class), filters);
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isEventMatchingFiltersReturnsFalseWhenEventMatchesExcludeFilter() {
+ Event event = Mockito.mock(Event.class);
+ WebhookFilter excludeFilter = Mockito.mock(WebhookFilter.class);
+
+ Mockito.when(excludeFilter.getMode()).thenReturn(WebhookFilter.Mode.Exclude);
+ Mockito.when(excludeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(excludeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(excludeFilter.getValue()).thenReturn("USER.LOGIN");
+ Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
+
+ List<WebhookFilter> filters = List.of(excludeFilter);
+
+ boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isEventMatchingFiltersReturnsTrueWhenEventMatchesIncludeFilter() {
+ Event event = Mockito.mock(Event.class);
+ WebhookFilter includeFilter = Mockito.mock(WebhookFilter.class);
+
+ Mockito.when(includeFilter.getMode()).thenReturn(WebhookFilter.Mode.Include);
+ Mockito.when(includeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(includeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(includeFilter.getValue()).thenReturn("USER.LOGIN");
+ Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
+
+ List<WebhookFilter> filters = List.of(includeFilter);
+
+ boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isEventMatchingFiltersReturnsFalseWhenEventDoesNotMatchAnyIncludeFilter() {
+ Event event = Mockito.mock(Event.class);
+ WebhookFilter includeFilter = Mockito.mock(WebhookFilter.class);
+
+ Mockito.when(includeFilter.getMode()).thenReturn(WebhookFilter.Mode.Include);
+ Mockito.when(includeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(includeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(includeFilter.getValue()).thenReturn("USER.LOGOUT");
+ Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
+
+ List<WebhookFilter> filters = List.of(includeFilter);
+
+ boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isEventMatchingFiltersReturnsTrueWhenEventMatchesAtLeastOneIncludeFilter() {
+ Event event = Mockito.mock(Event.class);
+ WebhookFilter includeFilter1 = Mockito.mock(WebhookFilter.class);
+ WebhookFilter includeFilter2 = Mockito.mock(WebhookFilter.class);
+
+ Mockito.when(includeFilter1.getMode()).thenReturn(WebhookFilter.Mode.Include);
+ Mockito.when(includeFilter1.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(includeFilter1.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(includeFilter1.getValue()).thenReturn("USER.LOGOUT");
+
+ Mockito.when(includeFilter2.getMode()).thenReturn(WebhookFilter.Mode.Include);
+ Mockito.when(includeFilter2.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(includeFilter2.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(includeFilter2.getValue()).thenReturn("USER.LOGIN");
+
+ Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
+
+ List<WebhookFilter> filters = List.of(includeFilter1, includeFilter2);
+
+ boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isEventMatchingFiltersReturnsFalseWhenEventMatchesExcludeFilterEvenWithIncludeFilters() {
+ Event event = Mockito.mock(Event.class);
+ WebhookFilter excludeFilter = Mockito.mock(WebhookFilter.class);
+ WebhookFilter includeFilter = Mockito.mock(WebhookFilter.class);
+
+ Mockito.when(includeFilter.getMode()).thenReturn(WebhookFilter.Mode.Include);
+ Mockito.when(includeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(includeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Prefix);
+ Mockito.when(includeFilter.getValue()).thenReturn("USER.");
+
+ Mockito.when(excludeFilter.getMode()).thenReturn(WebhookFilter.Mode.Exclude);
+ Mockito.when(excludeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
+ Mockito.when(excludeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
+ Mockito.when(excludeFilter.getValue()).thenReturn("USER.LOGIN");
+
+ Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
+
+ List<WebhookFilter> filters = List.of(includeFilter, excludeFilter);
+
+ boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void getDeliveryJobsReturnsEmptyListWhenEventCategoryIsNotActionEvent() throws EventBusException {
+ Event event = Mockito.mock(Event.class);
+ Mockito.when(event.getEventCategory()).thenReturn("NON_ACTION_EVENT");
+
+ List<Runnable> jobs = webhookServiceImpl.getDeliveryJobs(event);
+
+ Assert.assertTrue(jobs.isEmpty());
+ }
+
+ @Test
+ public void getDeliveryJobsThrowsExceptionWhenEventAccountIdIsNull() {
+ Event event = Mockito.mock(Event.class);
+ Mockito.when(event.getEventCategory()).thenReturn(EventCategory.ACTION_EVENT.getName());
+ Mockito.when(event.getResourceAccountId()).thenReturn(null);
+
+ Assert.assertThrows(EventBusException.class, () -> webhookServiceImpl.getDeliveryJobs(event));
+ }
+
+ @Test
+ public void getDeliveryJobsReturnsEmptyListWhenNoWebhooksMatchFilters() throws EventBusException {
+ Event event = Mockito.mock(Event.class);
+ Mockito.when(event.getEventCategory()).thenReturn(EventCategory.ACTION_EVENT.getName());
+ Mockito.when(event.getResourceAccountId()).thenReturn(1L);
+ Mockito.when(event.getResourceDomainId()).thenReturn(2L);
+ Mockito.when(domainDao.getDomainParentIds(2L)).thenReturn(Set.of(3L));
+
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhook.getId()).thenReturn(1L);
+
+ Mockito.when(webhookDao.listByEnabledForDelivery(Mockito.anyLong(), Mockito.anyList())).thenReturn(List.of(webhook));
+ Mockito.when(webhookFilterDao.listByWebhook(Mockito.anyLong())).thenReturn(List.of());
+ Mockito.doReturn(false).when(webhookServiceImpl).isEventMatchingFilters(Mockito.any(), Mockito.anyList());
+
+ List<Runnable> jobs = webhookServiceImpl.getDeliveryJobs(event);
+
+ Assert.assertTrue(jobs.isEmpty());
+ }
+
+ @Test
+ public void getDeliveryJobsCreatesJobsForMatchingWebhooks() throws EventBusException {
+ Event event = Mockito.mock(Event.class);
+ Mockito.when(event.getEventCategory()).thenReturn(EventCategory.ACTION_EVENT.getName());
+ Mockito.when(event.getResourceAccountId()).thenReturn(1L);
+ Mockito.when(event.getResourceDomainId()).thenReturn(2L);
+ Mockito.when(domainDao.getDomainParentIds(2L)).thenReturn(Set.of(3L));
+
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhook.getId()).thenReturn(1L);
+ Mockito.when(webhook.getDomainId()).thenReturn(2L);
+
+ Mockito.when(webhookDao.listByEnabledForDelivery(Mockito.anyLong(), Mockito.anyList())).thenReturn(List.of(webhook));
+ Mockito.when(webhookFilterDao.listByWebhook(Mockito.anyLong())).thenReturn(List.of());
+ Mockito.doReturn(true).when(webhookServiceImpl).isEventMatchingFilters(Mockito.any(), Mockito.anyList());
+ Mockito.doReturn(Mockito.mock(WebhookDeliveryThread.class)).when(webhookServiceImpl).getDeliveryJob(Mockito.any(), Mockito.any(), Mockito.any());
+
+ List<Runnable> jobs = webhookServiceImpl.getDeliveryJobs(event);
+
+ Assert.assertEquals(1, jobs.size());
+ }
+
+ @Test
+ public void getDeliveryJobsUsesCachedDomainConfigs() throws EventBusException {
+ Event event = Mockito.mock(Event.class);
+ Mockito.when(event.getEventCategory()).thenReturn(EventCategory.ACTION_EVENT.getName());
+ Mockito.when(event.getResourceAccountId()).thenReturn(1L);
+ Mockito.when(event.getResourceDomainId()).thenReturn(2L);
+ Mockito.when(domainDao.getDomainParentIds(2L)).thenReturn(Set.of(3L));
+
+ WebhookVO webhook1 = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhook1.getId()).thenReturn(1L);
+ Mockito.when(webhook1.getDomainId()).thenReturn(2L);
+
+ WebhookVO webhook2 = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhook2.getId()).thenReturn(2L);
+ Mockito.when(webhook2.getDomainId()).thenReturn(2L);
+
+ Mockito.when(webhookDao.listByEnabledForDelivery(Mockito.anyLong(), Mockito.anyList())).thenReturn(List.of(webhook1, webhook2));
+ Mockito.when(webhookFilterDao.listByWebhook(Mockito.anyLong())).thenReturn(List.of());
+ Mockito.doReturn(true).when(webhookServiceImpl).isEventMatchingFilters(Mockito.any(), Mockito.anyList());
+ Mockito.doReturn(Mockito.mock(WebhookDeliveryThread.class)).when(webhookServiceImpl).getDeliveryJob(Mockito.any(), Mockito.any(), Mockito.any());
+
+ List<Runnable> jobs = webhookServiceImpl.getDeliveryJobs(event);
+
+ Assert.assertEquals(2, jobs.size());
+ Mockito.verify(webhookServiceImpl, Mockito.times(1)).getDeliveryJob(Mockito.eq(event), Mockito.eq(webhook1), Mockito.any());
+ Mockito.verify(webhookServiceImpl, Mockito.times(1)).getDeliveryJob(Mockito.eq(event), Mockito.eq(webhook2), Mockito.any());
+ }
+
+ @Test
+ public void getManualDeliveryJobCreatesJobWithDefaultPayloadWhenPayloadIsBlank() {
+ Webhook webhook = Mockito.mock(Webhook.class);
+ CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
+ Account account = Mockito.mock(Account.class);
+
+ Mockito.when(webhook.getAccountId()).thenReturn(2L);
+ Mockito.when(accountManager.getAccount(Mockito.anyLong())).thenReturn(account);
+
+ Runnable job = webhookServiceImpl.getManualDeliveryJob(null, webhook, " ", future);
+
+ Assert.assertNotNull(job);
+ Event event = (Event) ReflectionTestUtils.getField(job, "event");
+ Assert.assertNotNull(event);
+ Assert.assertTrue(StringUtils.isNotBlank(event.getDescription()));
+ }
+
+ @Test
+ public void getManualDeliveryJobCreatesJobWithExistingDeliveryDetails() {
+ WebhookDelivery existingDelivery = Mockito.mock(WebhookDelivery.class);
+ Webhook webhook = Mockito.mock(Webhook.class);
+ EventJoinVO eventJoinVO = Mockito.mock(EventJoinVO.class);
+ CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
+
+ Mockito.when(existingDelivery.getEventId()).thenReturn(123L);
+ Mockito.when(eventJoinDao.findById(123L)).thenReturn(eventJoinVO);
+ Mockito.when(eventJoinVO.getId()).thenReturn(123L);
+ Mockito.when(eventJoinVO.getType()).thenReturn("TEST.EVENT");
+ Mockito.when(eventJoinVO.getUuid()).thenReturn("test-uuid");
+ Mockito.when(existingDelivery.getPayload()).thenReturn("test-payload");
+ Mockito.when(eventJoinVO.getAccountUuid()).thenReturn("account-uuid");
+
+ Runnable job = webhookServiceImpl.getManualDeliveryJob(existingDelivery, webhook, null, future);
+
+ Assert.assertNotNull(job);
+ Mockito.verify(eventJoinDao, Mockito.times(1)).findById(123L);
+ }
+
+ @Test
+ public void getManualDeliveryJobCreatesJobWithWebhookAccountDetailsWhenNoExistingDelivery() {
+ Webhook webhook = Mockito.mock(Webhook.class);
+ Account account = Mockito.mock(Account.class);
+ CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
+
+ Mockito.when(webhook.getAccountId()).thenReturn(1L);
+ Mockito.when(accountManager.getAccount(1L)).thenReturn(account);
+ Mockito.when(account.getUuid()).thenReturn("account-uuid");
+
+ Runnable job = webhookServiceImpl.getManualDeliveryJob(null, webhook, "test-payload", future);
+
+ Assert.assertNotNull(job);
+ Mockito.verify(accountManager, Mockito.times(1)).getAccount(1L);
+ }
+
+ @Test
+ public void getManualDeliveryJobSetsDeliveryTriesAndTimeoutFromWebhookDomain() {
+ Webhook webhook = Mockito.mock(Webhook.class);
+ CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
+ Account account = Mockito.mock(Account.class);
+
+ Mockito.when(webhook.getDomainId()).thenReturn(2L);
+ Mockito.when(webhook.getAccountId()).thenReturn(2L);
+ Mockito.when(accountManager.getAccount(Mockito.anyLong())).thenReturn(account);
+
+ WebhookDeliveryThread job = (WebhookDeliveryThread) webhookServiceImpl.getManualDeliveryJob(null, webhook, "test-payload", future);
+
+ Assert.assertEquals(3, ReflectionTestUtils.getField(job, "deliveryTries"));
+ Assert.assertEquals(10, ReflectionTestUtils.getField(job, "deliveryTimeout"));
+ }
+
+ @Test
+ public void deliveryCompleteCallbackPersistsDeliveryVO() {
+ WebhookDeliveryThread.WebhookDeliveryResult result = Mockito.mock(WebhookDeliveryThread.WebhookDeliveryResult.class);
+ WebhookDeliveryThread.WebhookDeliveryContext<Webhook> context = Mockito.mock(WebhookDeliveryThread.WebhookDeliveryContext.class);
+
+ Mockito.when(context.getEventId()).thenReturn(123L);
+ Mockito.when(context.getRuleId()).thenReturn(456L);
+ Mockito.when(result.getHeaders()).thenReturn("headers");
+ Mockito.when(result.getPayload()).thenReturn("payload");
+ Mockito.when(result.isSuccess()).thenReturn(true);
+ Mockito.when(result.getResult()).thenReturn("result");
+
+ AsyncCallbackDispatcher<WebhookServiceImpl, WebhookDeliveryThread.WebhookDeliveryResult> callback = Mockito.mock(AsyncCallbackDispatcher.class);
+ Mockito.when(callback.getResult()).thenReturn(result);
+
+ webhookServiceImpl.deliveryCompleteCallback(callback, context);
+
+ Mockito.verify(webhookDeliveryDao, Mockito.times(1)).persist(Mockito.any(WebhookDeliveryVO.class));
+ }
+
+ @Test
+ public void manualDeliveryCompleteCallbackCompletesFuture() {
+ WebhookDeliveryThread.WebhookDeliveryResult result = Mockito.mock(WebhookDeliveryThread.WebhookDeliveryResult.class);
+ WebhookServiceImpl.ManualDeliveryContext<WebhookDeliveryThread.WebhookDeliveryResult> context = Mockito.mock(WebhookServiceImpl.ManualDeliveryContext.class);
+ CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
+
+ Mockito.when(context.getFuture()).thenReturn(future);
+ AsyncCallbackDispatcher<WebhookServiceImpl, WebhookDeliveryThread.WebhookDeliveryResult> callback = Mockito.mock(AsyncCallbackDispatcher.class);
+ Mockito.when(callback.getResult()).thenReturn(result);
+
+ webhookServiceImpl.manualDeliveryCompleteCallback(callback, context);
+
+ Mockito.verify(future, Mockito.times(1)).complete(result);
+ }
+
+ @Test
+ public void cleanupOldWebhookDeliveriesProcessesAllWebhooks() {
+ WebhookVO webhook1 = Mockito.mock(WebhookVO.class);
+ WebhookVO webhook2 = Mockito.mock(WebhookVO.class);
+
+ Mockito.when(webhook1.getId()).thenReturn(1L);
+ Mockito.when(webhook2.getId()).thenReturn(2L);
+
+ List<WebhookVO> webhooks = List.of(webhook1, webhook2);
+ Pair<List<WebhookVO>, Integer> webhooksAndCount = new Pair<>(webhooks, 2);
+
+ Mockito.when(webhookDao.searchAndCount(Mockito.any(), Mockito.any())).thenReturn(webhooksAndCount);
+
+ long processed = webhookServiceImpl.cleanupOldWebhookDeliveries(10);
+
+ Assert.assertEquals(2, processed);
+ Mockito.verify(webhookDeliveryDao, Mockito.times(1)).removeOlderDeliveries(1L, 10);
+ Mockito.verify(webhookDeliveryDao, Mockito.times(1)).removeOlderDeliveries(2L, 10);
+ }
+
+ @Test
+ public void listWebhooksByAccountReturnsEmptyListWhenNoWebhooksExist() {
+ Mockito.when(webhookDao.listByAccount(1L)).thenReturn(new ArrayList<>());
+
+ List<? extends ControlledEntity> result = webhookServiceImpl.listWebhooksByAccount(1L);
+
+ Assert.assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void listWebhooksByAccountReturnsWebhooksForValidAccount() {
+ WebhookVO webhook = Mockito.mock(WebhookVO.class);
+ Mockito.when(webhookDao.listByAccount(1L)).thenReturn(List.of(webhook));
+
+ List<? extends ControlledEntity> result = webhookServiceImpl.listWebhooksByAccount(1L);
+
+ Assert.assertEquals(1, result.size());
+ Assert.assertEquals(webhook, result.get(0));
+ }
+
+ @Test
+ public void handleEventSubmitsJobsToExecutor() throws EventBusException {
+ Event event = Mockito.mock(Event.class);
+ Runnable job1 = Mockito.mock(Runnable.class);
+ Runnable job2 = Mockito.mock(Runnable.class);
+ ExecutorService webhookJobExecutor = Mockito.mock(ExecutorService.class);
+ ReflectionTestUtils.setField(webhookServiceImpl, "webhookJobExecutor", webhookJobExecutor);
+
+ Mockito.doReturn(List.of(job1, job2)).when(webhookServiceImpl).getDeliveryJobs(event);
+
+ webhookServiceImpl.handleEvent(event);
+
+ Mockito.verify(webhookJobExecutor, Mockito.times(1)).submit(job1);
+ Mockito.verify(webhookJobExecutor, Mockito.times(1)).submit(job2);
+ }
+
+ @Test
+ public void handleEventDoesNotSubmitJobsWhenNoJobsExist() throws EventBusException {
+ Event event = Mockito.mock(Event.class);
+ ExecutorService webhookJobExecutor = Mockito.mock(ExecutorService.class);
+ ReflectionTestUtils.setField(webhookServiceImpl, "webhookJobExecutor", webhookJobExecutor);
+
+ Mockito.doReturn(new ArrayList<>()).when(webhookServiceImpl).getDeliveryJobs(event);
+
+ webhookServiceImpl.handleEvent(event);
+
+ Mockito.verify(webhookJobExecutor, Mockito.never()).submit(Mockito.any(Runnable.class));
+ }
+
+ @Test
+ public void executeWebhookDeliveryPersistsDeliveryWhenDeliveryExists() {
+ WebhookDelivery delivery = Mockito.mock(WebhookDelivery.class);
+ Webhook webhook = Mockito.mock(Webhook.class);
+ WebhookDeliveryThread.WebhookDeliveryResult result = Mockito.mock(WebhookDeliveryThread.WebhookDeliveryResult.class);
+
+ Mockito.when(delivery.getEventId()).thenReturn(123L);
+ Mockito.when(delivery.getWebhookId()).thenReturn(456L);
+ Mockito.when(result.getHeaders()).thenReturn("headers");
+ Mockito.when(result.getPayload()).thenReturn("payload");
+ Mockito.when(result.isSuccess()).thenReturn(true);
+ Mockito.when(result.getResult()).thenReturn("result");
+ Mockito.when(result.getStarTime()).thenReturn(new Date(System.currentTimeMillis() - (2 * 1000L)));
+ Mockito.when(result.getEndTime()).thenReturn(new Date(System.currentTimeMillis()));
+ Mockito.when(eventJoinDao.findById(123L)).thenReturn(Mockito.mock(EventJoinVO.class));
+ ExecutorService executorService = Mockito.mock(ExecutorService.class);
+ Mockito.when(executorService.submit(Mockito.any(Runnable.class))).thenAnswer(invocation -> {
+ Runnable runnable = invocation.getArgument(0);
+ WebhookDeliveryThread webhookDeliveryThread = (WebhookDeliveryThread) runnable;
+ webhookDeliveryThread.callback.complete(result);
+ return CompletableFuture.completedFuture(null);
+ });
+ ReflectionTestUtils.setField(webhookServiceImpl, "webhookJobExecutor", executorService);
+
+ WebhookDeliveryVO persistedDelivery = Mockito.mock(WebhookDeliveryVO.class);
+ Mockito.when(webhookDeliveryDao.persist(Mockito.any(WebhookDeliveryVO.class))).thenReturn(persistedDelivery);
+
+ WebhookDelivery returnedDelivery = webhookServiceImpl.executeWebhookDelivery(delivery, webhook, "payload");
+
+ Assert.assertEquals(persistedDelivery, returnedDelivery);
+ Mockito.verify(webhookDeliveryDao, Mockito.times(1)).persist(Mockito.any(WebhookDeliveryVO.class));
+ }
+
+ @Test
+ public void executeWebhookDeliveryCreatesAndReturnsNewDeliveryWhenDeliveryIsNull() {
+ Webhook webhook = Mockito.mock(Webhook.class);
+ WebhookDeliveryThread.WebhookDeliveryResult result =
+ Mockito.mock(WebhookDeliveryThread.WebhookDeliveryResult.class);
+ Account account = Mockito.mock(Account.class);
+
+ Mockito.when(webhook.getAccountId()).thenReturn(2L);
+ Mockito.when(accountManager.getAccount(Mockito.anyLong())).thenReturn(account);
+ Mockito.when(result.getHeaders()).thenReturn("headers");
+ Mockito.when(result.getPayload()).thenReturn("payload");
+ Mockito.when(result.isSuccess()).thenReturn(true);
+ Mockito.when(result.getResult()).thenReturn("result");
+ Mockito.when(result.getStarTime()).thenReturn(new Date(System.currentTimeMillis() - (2 * 1000L)));
+ Mockito.when(result.getEndTime()).thenReturn(new Date(System.currentTimeMillis()));
+ ExecutorService executorService = Mockito.mock(ExecutorService.class);
+ Mockito.when(executorService.submit(Mockito.any(Runnable.class))).thenAnswer(invocation -> {
+ System.out.println("Submitting runnable to executor");
+ Runnable runnable = invocation.getArgument(0);
+ WebhookDeliveryThread webhookDeliveryThread = (WebhookDeliveryThread) runnable;
+ webhookDeliveryThread.callback.complete(result);
+ return CompletableFuture.completedFuture(null);
+ });
+ ReflectionTestUtils.setField(webhookServiceImpl, "webhookJobExecutor", executorService);
+
+ WebhookDelivery returnedDelivery = webhookServiceImpl.executeWebhookDelivery(null, webhook, "payload");
+
+ Assert.assertNotNull(returnedDelivery);
+ Assert.assertEquals("headers", returnedDelivery.getHeaders());
+ Assert.assertEquals("payload", returnedDelivery.getPayload());
+ Assert.assertTrue(returnedDelivery.isSuccess());
+ Assert.assertEquals("result", returnedDelivery.getResponse());
+ }
+
+ @Test
+ public void invalidateWebhooksCacheClearsCache() {
+ LazyCache<?, ?> cache = Mockito.mock(LazyCache.class);
+ ReflectionTestUtils.setField(webhookServiceImpl, "webhooksCache", cache);
+
+ webhookServiceImpl.invalidateWebhooksCache();
+
+ Mockito.verify(cache, Mockito.times(1)).clear();
+ }
+
+ @Test
+ public void invalidateWebhookFiltersCacheInvalidatesSpecificCacheEntry() {
+ LazyCache<Long, ?> cache = Mockito.mock(LazyCache.class);
+ ReflectionTestUtils.setField(webhookServiceImpl, "webhookFiltersCache", cache);
+
+ webhookServiceImpl.invalidateWebhookFiltersCache(123L);
+
+ Mockito.verify(cache, Mockito.times(1)).invalidate(123L);
+ }
+}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/AddWebhookFilterCmdTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/AddWebhookFilterCmdTest.java
new file mode 100644
index 0000000..4c1d718
--- /dev/null
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/AddWebhookFilterCmdTest.java
@@ -0,0 +1,110 @@
+// 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.mom.webhook.api.command.user;
+
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.mom.webhook.WebhookApiService;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import com.cloud.user.Account;
+import com.cloud.user.User;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AddWebhookFilterCmdTest {
+ @Mock
+ WebhookApiService webhookApiService;
+
+ @Test
+ public void executeAddsWebhookFilterSuccessfully() {
+ AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
+ cmd.webhookApiService = webhookApiService;
+
+ WebhookFilterResponse response = Mockito.mock(WebhookFilterResponse.class);
+ Mockito.when(webhookApiService.addWebhookFilter(cmd)).thenReturn(response);
+
+ cmd.execute();
+
+ Mockito.verify(webhookApiService, Mockito.times(1)).addWebhookFilter(cmd);
+ Assert.assertNotNull(cmd.getResponseObject());
+ Assert.assertEquals(response, cmd.getResponseObject());
+ }
+
+ @Test(expected = ServerApiException.class)
+ public void executeThrowsExceptionWhenServiceReturnsNull() {
+ AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
+ cmd.webhookApiService = webhookApiService;
+
+ Mockito.when(webhookApiService.addWebhookFilter(cmd)).thenReturn(null);
+
+ cmd.execute();
+ }
+
+ @Test(expected = ServerApiException.class)
+ public void executeThrowsExceptionWhenServiceFails() {
+ AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
+ cmd.webhookApiService = webhookApiService;
+
+ Mockito.doThrow(new CloudRuntimeException("Service failure")).when(webhookApiService).addWebhookFilter(cmd);
+
+ cmd.execute();
+ }
+
+ @Test
+ public void getEntityOwnerIdReturnsCorrectOwnerId() {
+ Account account = Mockito.mock(Account.class);
+ Mockito.when(account.getId()).thenReturn(123L);
+ CallContext.register(Mockito.mock(User.class), account);
+
+ AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
+
+ Assert.assertEquals(123L, cmd.getEntityOwnerId());
+ }
+
+ @Test
+ public void getModeReturnsCorrectValue() {
+ AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
+ ReflectionTestUtils.setField(cmd, "mode", "Include");
+
+ Assert.assertEquals("Include", cmd.getMode());
+ }
+
+ @Test
+ public void getMatchTypeReturnsCorrectValue() {
+ AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
+ ReflectionTestUtils.setField(cmd, "matchType", "Exact");
+
+ Assert.assertEquals("Exact", cmd.getMatchType());
+ }
+
+ @Test
+ public void getValueReturnsCorrectValue() {
+ AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
+ ReflectionTestUtils.setField(cmd, "value", "testValue");
+
+ Assert.assertEquals("testValue", cmd.getValue());
+ }
+}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookDeliveryCmdTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookDeliveryCmdTest.java
index 2a090eb..607dd5f 100644
--- a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookDeliveryCmdTest.java
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookDeliveryCmdTest.java
@@ -19,6 +19,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Date;
import java.util.UUID;
import org.apache.cloudstack.api.ServerApiException;
@@ -105,4 +106,38 @@
cmd.execute();
Assert.assertNotNull(cmd.getResponseObject());
}
+
+ @Test
+ public void getStartDateReturnsCorrectValue() {
+ DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
+ Date date = new Date();
+ ReflectionTestUtils.setField(cmd, "startDate", date);
+
+ Assert.assertEquals(date, cmd.getStartDate());
+ }
+
+ @Test
+ public void getStartDateReturnsNullWhenNotSet() {
+ DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
+ ReflectionTestUtils.setField(cmd, "startDate", null);
+
+ Assert.assertNull(cmd.getStartDate());
+ }
+
+ @Test
+ public void getEndDateReturnsCorrectValue() {
+ DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
+ Date date = new Date();
+ ReflectionTestUtils.setField(cmd, "endDate", date);
+
+ Assert.assertEquals(date, cmd.getEndDate());
+ }
+
+ @Test
+ public void getEndDateReturnsNullWhenNotSet() {
+ DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
+ ReflectionTestUtils.setField(cmd, "endDate", null);
+
+ Assert.assertNull(cmd.getEndDate());
+ }
}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookFilterCmdTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookFilterCmdTest.java
new file mode 100644
index 0000000..ae5a498
--- /dev/null
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/DeleteWebhookFilterCmdTest.java
@@ -0,0 +1,113 @@
+// 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.mom.webhook.api.command.user;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.UUID;
+
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.mom.webhook.WebhookApiService;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import com.cloud.user.Account;
+import com.cloud.user.AccountVO;
+import com.cloud.user.User;
+import com.cloud.user.UserVO;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DeleteWebhookFilterCmdTest {
+ @Mock
+ WebhookApiService webhookApiService;
+
+ private Object getCommandMethodValue(Object obj, String methodName) {
+ Object result = null;
+ try {
+ Method method = obj.getClass().getMethod(methodName);
+ result = method.invoke(obj);
+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+ Assert.fail(String.format("Failed to get method %s value", methodName));
+ }
+ return result;
+ }
+
+ private void runLongMemberTest(String memberName) {
+ String methodName = "get" + memberName.substring(0, 1).toUpperCase() + memberName.substring(1);
+ DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
+ ReflectionTestUtils.setField(cmd, memberName, null);
+ Assert.assertNull(getCommandMethodValue(cmd, methodName));
+ Long value = 100L;
+ ReflectionTestUtils.setField(cmd, memberName, value);
+ Assert.assertEquals(value, getCommandMethodValue(cmd, methodName));
+ }
+
+ @Test
+ public void testGetId() {
+ runLongMemberTest("id");
+ }
+
+ @Test
+ public void testGetWebhookId() {
+ runLongMemberTest("webhookId");
+ }
+
+ @Test
+ public void executeDeletesWebhookFilterSuccessfully() {
+ DeleteWebhookFilterCmd cmd = new DeleteWebhookFilterCmd();
+ cmd.webhookApiService = webhookApiService;
+
+ Mockito.when(webhookApiService.deleteWebhookFilter(cmd)).thenReturn(1);
+
+ cmd.execute();
+
+ Mockito.verify(webhookApiService, Mockito.times(1)).deleteWebhookFilter(cmd);
+ Assert.assertNotNull(cmd.getResponseObject());
+ Assert.assertTrue(cmd.getResponseObject() instanceof SuccessResponse);
+ Assert.assertEquals(cmd.getCommandName(), ((SuccessResponse) cmd.getResponseObject()).getResponseName());
+ }
+
+ @Test(expected = ServerApiException.class)
+ public void executeThrowsExceptionWhenServiceFails() {
+ DeleteWebhookFilterCmd cmd = new DeleteWebhookFilterCmd();
+ cmd.webhookApiService = webhookApiService;
+
+ Mockito.doThrow(new CloudRuntimeException("Service failure")).when(webhookApiService).deleteWebhookFilter(cmd);
+
+ cmd.execute();
+ }
+
+ @Test
+ public void getEntityOwnerIdReturnsCallingAccountId() {
+ Account account = new AccountVO("testaccount", 1L, "networkdomain", Account.Type.NORMAL, "uuid");
+ UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
+ CallContext.register(user, account);
+
+ DeleteWebhookFilterCmd cmd = new DeleteWebhookFilterCmd();
+
+ Assert.assertEquals(account.getId(), cmd.getEntityOwnerId());
+ }
+}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookFiltersCmdTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookFiltersCmdTest.java
new file mode 100644
index 0000000..7e936c2
--- /dev/null
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/api/command/user/ListWebhookFiltersCmdTest.java
@@ -0,0 +1,76 @@
+// 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.mom.webhook.api.command.user;
+
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.mom.webhook.WebhookApiService;
+import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ListWebhookFiltersCmdTest {
+ @Mock
+ WebhookApiService webhookApiService;
+
+ @Test
+ public void executeSetsResponseNameCorrectly() {
+ ListWebhookFiltersCmd cmd = new ListWebhookFiltersCmd();
+ cmd.webhookApiService = webhookApiService;
+
+ ListResponse<WebhookFilterResponse> response = new ListResponse<>();
+ Mockito.when(webhookApiService.listWebhookFilters(cmd)).thenReturn(response);
+
+ cmd.execute();
+
+ Assert.assertNotNull(cmd.getResponseObject());
+ }
+
+ @Test(expected = ServerApiException.class)
+ public void executeThrowsExceptionWhenServiceFails() {
+ ListWebhookFiltersCmd cmd = new ListWebhookFiltersCmd();
+ cmd.webhookApiService = webhookApiService;
+
+ Mockito.doThrow(new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Service failure")).when(webhookApiService).listWebhookFilters(cmd);
+
+ cmd.execute();
+ }
+
+ @Test
+ public void getIdReturnsCorrectValue() {
+ ListWebhookFiltersCmd cmd = new ListWebhookFiltersCmd();
+ ReflectionTestUtils.setField(cmd, "id", 123L);
+
+ Assert.assertEquals(Long.valueOf(123L), cmd.getId());
+ }
+
+ @Test
+ public void getWebhookIdReturnsCorrectValue() {
+ ListWebhookFiltersCmd cmd = new ListWebhookFiltersCmd();
+ ReflectionTestUtils.setField(cmd, "webhookId", 456L);
+
+ Assert.assertEquals(Long.valueOf(456L), cmd.getWebhookId());
+ }
+}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookDaoImplTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookDaoImplTest.java
new file mode 100644
index 0000000..c2f0a8d
--- /dev/null
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookDaoImplTest.java
@@ -0,0 +1,170 @@
+// 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.mom.webhook.dao;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cloudstack.mom.webhook.Webhook;
+import org.apache.cloudstack.mom.webhook.vo.WebhookVO;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+
+@RunWith(MockitoJUnitRunner.class)
+public class WebhookDaoImplTest {
+ @Spy
+ @InjectMocks
+ private WebhookDaoImpl webhookDao;
+
+ @Mock
+ private WebhookVO mockWebhookVO;
+ @Mock
+ private SearchBuilder<WebhookVO> mockSearchBuilder;
+ @Mock
+ private SearchCriteria<WebhookVO> mockSearchCriteria;
+
+ @Before
+ public void setUp() {
+ when(mockSearchBuilder.entity()).thenReturn(mockWebhookVO);
+ when(mockSearchBuilder.and()).thenReturn(mockSearchBuilder);
+ when(mockSearchBuilder.or()).thenReturn(mockSearchBuilder);
+ when(mockSearchBuilder.create()).thenReturn(mockSearchCriteria);
+ doReturn(mockSearchBuilder).when(webhookDao).createSearchBuilder();
+ webhookDao.accountIdSearch = mockSearchBuilder;
+ }
+
+ @Test
+ public void listByEnabledForDeliveryReturnsWebhooksWhenAccountIdAndDomainIdsMatch() {
+ Long accountId = 1L;
+ List<Long> domainIds = List.of(2L, 3L);
+
+ doReturn(List.of(mockWebhookVO)).when(webhookDao).listBy(any(SearchCriteria.class));
+
+ List<WebhookVO> result = webhookDao.listByEnabledForDelivery(accountId, domainIds);
+
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(mockSearchCriteria).setParameters("state", Webhook.State.Enabled.name());
+ verify(mockSearchCriteria).setParameters("scopeGlobal", Webhook.Scope.Global.name());
+ verify(mockSearchCriteria).setParameters("scopeLocal", Webhook.Scope.Local.name());
+ verify(mockSearchCriteria).setParameters("scopeDomain", Webhook.Scope.Domain.name());
+ verify(mockSearchCriteria).setParameters("domainId", 2L, 3L);
+ }
+
+ @Test
+ public void listByEnabledForDeliveryReturnsEmptyWhenNoMatchFound() {
+ Long accountId = 100L;
+ List<Long> domainIds = Collections.emptyList();
+
+ doReturn(Collections.emptyList()).when(webhookDao).listBy(any(SearchCriteria.class));
+
+ List<WebhookVO> result = webhookDao.listByEnabledForDelivery(accountId, domainIds);
+
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ verify(mockSearchCriteria, never()).setParameters("scopeDomain", Webhook.Scope.Domain.name());
+ verify(mockSearchCriteria, never()).setParameters(eq("domainId"), any());
+ }
+
+ @Test
+ public void deleteByAccountRemovesWebhooksForGivenAccountId() {
+ long accountId = 1L;
+
+ doReturn(1).when(webhookDao).remove(any(SearchCriteria.class));
+
+ webhookDao.deleteByAccount(accountId);
+
+ verify(webhookDao, times(1)).remove(any(SearchCriteria.class));
+ verify(mockSearchCriteria).setParameters("accountId", accountId);
+ }
+
+ @Test
+ public void listByAccountReturnsWebhooksForGivenAccountId() {
+ long accountId = 1L;
+
+ doReturn(List.of(mockWebhookVO)).when(webhookDao).listBy(any(SearchCriteria.class));
+
+ List<WebhookVO> result = webhookDao.listByAccount(accountId);
+
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(mockSearchCriteria).setParameters("accountId", accountId);
+ }
+
+ @Test
+ public void listByAccountReturnsEmptyWhenNoWebhooksExistForAccountId() {
+ long accountId = 1L;
+
+ doReturn(Collections.emptyList()).when(webhookDao).listBy(any(SearchCriteria.class));
+
+ List<WebhookVO> result = webhookDao.listByAccount(accountId);
+
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ verify(mockSearchCriteria).setParameters("accountId", accountId);
+ }
+
+ @Test
+ public void findByAccountAndPayloadUrlReturnsWebhookWhenMatchFound() {
+ long accountId = 1L;
+ String payloadUrl = "http://example.com";
+
+ doReturn(mockWebhookVO).when(webhookDao).findOneBy(any());
+
+ WebhookVO result = webhookDao.findByAccountAndPayloadUrl(accountId, payloadUrl);
+
+ assertNotNull(result);
+ verify(mockSearchCriteria).setParameters("accountId", accountId);
+ verify(mockSearchCriteria).setParameters("payloadUrl", payloadUrl);
+ }
+
+ @Test
+ public void findByAccountAndPayloadUrlReturnsNullWhenNoMatchFound() {
+ long accountId = 1L;
+ String payloadUrl = "http://example.com";
+
+ doReturn(null).when(webhookDao).findOneBy(any());
+
+ WebhookVO result = webhookDao.findByAccountAndPayloadUrl(accountId, payloadUrl);
+
+ assertNull(result);
+ verify(mockSearchCriteria).setParameters("accountId", accountId);
+ verify(mockSearchCriteria).setParameters("payloadUrl", payloadUrl);
+ }
+}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryDaoImplTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryDaoImplTest.java
new file mode 100644
index 0000000..ff0f222
--- /dev/null
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryDaoImplTest.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.mom.webhook.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WebhookDeliveryDaoImplTest {
+ @Spy
+ @InjectMocks
+ private WebhookDeliveryDaoImpl webhookDeliveryDao;
+
+ @Mock
+ private WebhookDeliveryVO mockWebhookDeliveryVO;
+ @Mock
+ private SearchBuilder<WebhookDeliveryVO> mockSearchBuilder;
+ @Mock
+ private SearchCriteria<WebhookDeliveryVO> mockSearchCriteria;
+
+ @Before
+ public void setUp() {
+ when(mockSearchBuilder.entity()).thenReturn(mockWebhookDeliveryVO);
+ when(mockSearchBuilder.create()).thenReturn(mockSearchCriteria);
+ doReturn(mockSearchBuilder).when(webhookDeliveryDao).createSearchBuilder();
+ }
+
+ @Test
+ public void deleteByDeleteApiParamsDeletesWhenParametersMatch() {
+ Long webhookId = 2L;
+ Date startDate = new Date(System.currentTimeMillis() - 10000);
+
+ doReturn(1).when(webhookDeliveryDao).remove(any(SearchCriteria.class));
+
+ int result = webhookDeliveryDao.deleteByDeleteApiParams(null, webhookId, null, startDate, null);
+
+ assertEquals(1, result);
+ verify(webhookDeliveryDao).remove(any(SearchCriteria.class));
+ verify(mockSearchBuilder).and(eq("webhookId"), any(), eq(SearchCriteria.Op.EQ));
+ verify(mockSearchCriteria).setParameters("webhookId", webhookId);
+ }
+
+ @Test
+ public void deleteByDeleteApiParamsReturnsZeroWhenNoMatchFound() {
+ Long id = 999L;
+ Long webhookId = 999L;
+ Long managementServerId = 999L;
+ Date startDate = new Date(System.currentTimeMillis() - 10000);
+ Date endDate = new Date();
+
+ doReturn(0).when(webhookDeliveryDao).remove(any(SearchCriteria.class));
+
+ int result = webhookDeliveryDao.deleteByDeleteApiParams(id, webhookId, managementServerId, startDate, endDate);
+
+ assertEquals(0, result);
+ }
+
+ @Test
+ public void removeOlderDeliveriesWhenParametersMatch() {
+ long webhookId = 2L;
+
+ WebhookDeliveryVO d1 = mock(WebhookDeliveryVO.class);
+ when(d1.getId()).thenReturn(1L);
+ WebhookDeliveryVO d2 = mock(WebhookDeliveryVO.class);
+ when(d2.getId()).thenReturn(2L);
+ List<WebhookDeliveryVO> list = List.of(d1, d2);
+ doReturn(list).when(webhookDeliveryDao).listBy(any(SearchCriteria.class), any());
+ doReturn(10).when(webhookDeliveryDao).remove(any(SearchCriteria.class));
+
+ webhookDeliveryDao.removeOlderDeliveries(webhookId, 10);
+ verify(webhookDeliveryDao).remove(any(SearchCriteria.class));
+ verify(mockSearchBuilder).and(eq("webhookId"), any(), eq(SearchCriteria.Op.EQ));
+ verify(mockSearchCriteria).setParameters("webhookId", webhookId);
+ verify(mockSearchBuilder).and(eq("id"), any(), eq(SearchCriteria.Op.NOTIN));
+ verify(mockSearchCriteria).setParameters("id", 1L, 2L);
+ }
+
+ @Test
+ public void removeOlderDeliveriesWhenNoKeepDeliveries() {
+ long webhookId = 2L;
+ doReturn(Collections.emptyList()).when(webhookDeliveryDao).listBy(any(SearchCriteria.class), any());
+
+ webhookDeliveryDao.removeOlderDeliveries(webhookId, 10);
+ verify(webhookDeliveryDao, never()).remove(any(SearchCriteria.class));
+ verify(mockSearchBuilder).and(eq("webhookId"), any(), eq(SearchCriteria.Op.EQ));
+ verify(mockSearchCriteria).setParameters("webhookId", webhookId);
+ verify(mockSearchBuilder, never()).and(eq("id"), any(), eq(SearchCriteria.Op.NOTIN));
+ }
+}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryJoinDaoImplTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryJoinDaoImplTest.java
new file mode 100644
index 0000000..f756153
--- /dev/null
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookDeliveryJoinDaoImplTest.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 org.apache.cloudstack.mom.webhook.dao;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryJoinVO;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WebhookDeliveryJoinDaoImplTest {
+ @Spy
+ @InjectMocks
+ private WebhookDeliveryJoinDaoImpl webhookDeliveryJoinDao;
+
+ @Mock
+ private WebhookDeliveryJoinVO mockWebhookDeliveryJoinVO;
+ @Mock
+ private SearchBuilder<WebhookDeliveryJoinVO> mockSearchBuilder;
+ @Mock
+ private SearchCriteria<WebhookDeliveryJoinVO> mockSearchCriteria;
+
+ @Before
+ public void setUp() {
+ when(mockSearchBuilder.entity()).thenReturn(mockWebhookDeliveryJoinVO);
+ when(mockSearchBuilder.create()).thenReturn(mockSearchCriteria);
+ doReturn(mockSearchBuilder).when(webhookDeliveryJoinDao).createSearchBuilder();
+ }
+
+ @Test
+ public void searchAndCountByListApiParametersId() {
+ long id = 1L;
+
+ doReturn(new Pair(List.of(mockWebhookDeliveryJoinVO), 1)).when(webhookDeliveryJoinDao)
+ .searchAndCount(any(), any());
+
+ Pair<List<WebhookDeliveryJoinVO>, Integer> result =
+ webhookDeliveryJoinDao.searchAndCountByListApiParameters(id, null, null,
+ null, null, null, null,null);
+
+ assertNotNull(result);
+ assertTrue(result.second() > 0);
+ assertFalse(result.first().isEmpty());
+ verify(mockSearchBuilder).and(eq("id"), any(), eq(SearchCriteria.Op.EQ));
+ verify(mockSearchCriteria).setParameters("id", id);
+ }
+
+ @Test
+ public void searchAndCountByListApiParametersWebhookId() {
+ long webhookId = 1L;
+
+ doReturn(new Pair(List.of(mockWebhookDeliveryJoinVO), 1)).when(webhookDeliveryJoinDao)
+ .searchAndCount(any(), any());
+
+ Pair<List<WebhookDeliveryJoinVO>, Integer> result =
+ webhookDeliveryJoinDao.searchAndCountByListApiParameters(null, List.of(webhookId),
+ null, null, null, null, null, null);
+
+ assertNotNull(result);
+ assertTrue(result.second() > 0);
+ assertFalse(result.first().isEmpty());
+ verify(mockSearchBuilder).and(eq("webhookId"), any(), eq(SearchCriteria.Op.IN));
+ verify(mockSearchCriteria).setParameters("webhookId", 1L);
+ }
+
+ @Test
+ public void searchAndCountByListApiParametersMgmtKeywordStartEnd() {
+ long managementServerId = 1L;
+ String keyword = "error";
+ Date start = new Date(System.currentTimeMillis() - 10000);
+ Date end = new Date();
+ Filter searchFilter = new Filter(WebhookDeliveryJoinVO.class, "id", false, 10L, 10L);
+
+ doReturn(new Pair(List.of(mockWebhookDeliveryJoinVO), 1)).when(webhookDeliveryJoinDao)
+ .searchAndCount(any(), eq(searchFilter));
+
+ Pair<List<WebhookDeliveryJoinVO>, Integer> result =
+ webhookDeliveryJoinDao.searchAndCountByListApiParameters(null, null,
+ managementServerId, keyword, start, end, null, searchFilter);
+
+ assertNotNull(result);
+ assertTrue(result.second() > 0);
+ assertFalse(result.first().isEmpty());
+ verify(mockSearchBuilder).and(eq("managementServerId"), any(), eq(SearchCriteria.Op.EQ));
+ verify(mockSearchCriteria).setParameters("managementServerId", managementServerId);
+ verify(mockSearchBuilder).and(eq("keyword"), any(), eq(SearchCriteria.Op.LIKE));
+ verify(mockSearchCriteria).setParameters("keyword", "%" + keyword + "%");
+ verify(mockSearchBuilder).and(eq("startDate"), any(), eq(SearchCriteria.Op.GTEQ));
+ verify(mockSearchCriteria).setParameters("startDate", start);
+ verify(mockSearchBuilder).and(eq("endDate"), any(), eq(SearchCriteria.Op.LTEQ));
+ verify(mockSearchCriteria).setParameters("endDate", end);
+ }
+}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookFilterDaoImplTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookFilterDaoImplTest.java
new file mode 100644
index 0000000..2f5efe2
--- /dev/null
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookFilterDaoImplTest.java
@@ -0,0 +1,130 @@
+// 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.mom.webhook.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WebhookFilterDaoImplTest {
+
+ @Spy
+ @InjectMocks
+ private WebhookFilterDaoImpl webhookFilterDaoImpl;
+
+ @Before
+ public void setUp() {
+ SearchBuilder<WebhookFilterVO> sb = Mockito.mock(SearchBuilder.class);
+ Mockito.when(sb.create()).thenReturn(Mockito.mock(SearchCriteria.class));
+ webhookFilterDaoImpl.IdWebhookIdSearch = sb;
+ }
+
+ @Test
+ public void searchByReturnsResultsWhenIdAndWebhookIdMatch() {
+ Long id = 1L;
+ Long webhookId = 2L;
+ Long startIndex = 0L;
+ Long pageSize = 10L;
+
+ Mockito.doReturn(new Pair(List.of(Mockito.mock(WebhookFilterVO.class)), 1))
+ .when(webhookFilterDaoImpl).searchAndCount(Mockito.any(), Mockito.any());
+
+ Pair<List<WebhookFilterVO>, Integer> result = webhookFilterDaoImpl.searchBy(id, webhookId, startIndex, pageSize);
+
+ assertNotNull(result);
+ assertTrue(result.first().size() >= 0);
+ }
+
+ @Test
+ public void searchByReturnsEmptyWhenNoMatch() {
+ Long id = 999L;
+ Long webhookId = 999L;
+ Long startIndex = 0L;
+ Long pageSize = 10L;
+
+ Mockito.doReturn(new Pair(List.of(), 0))
+ .when(webhookFilterDaoImpl).searchAndCount(Mockito.any(), Mockito.any());
+
+ Pair<List<WebhookFilterVO>, Integer> result = webhookFilterDaoImpl.searchBy(id, webhookId, startIndex, pageSize);
+
+ assertNotNull(result);
+ assertEquals(0, result.first().size());
+ }
+
+ @Test
+ public void listByWebhookReturnsResultsWhenWebhookIdExists() {
+ Long webhookId = 2L;
+
+ Mockito.doReturn(List.of(Mockito.mock(WebhookFilterVO.class)))
+ .when(webhookFilterDaoImpl).listBy(Mockito.any(SearchCriteria.class));
+
+ List<WebhookFilterVO> result = webhookFilterDaoImpl.listByWebhook(webhookId);
+
+ assertNotNull(result);
+ assertTrue(result.size() >= 0);
+ }
+
+ @Test
+ public void listByWebhookReturnsEmptyWhenWebhookIdDoesNotExist() {
+ Long webhookId = 999L;
+
+ Mockito.doReturn(List.of())
+ .when(webhookFilterDaoImpl).listBy(Mockito.any(SearchCriteria.class));
+
+ List<WebhookFilterVO> result = webhookFilterDaoImpl.listByWebhook(webhookId);
+
+ assertNotNull(result);
+ assertEquals(0, result.size());
+ }
+
+ @Test
+ public void deleteReturnsZeroWhenIdAndWebhookIdAreNull() {
+ int result = webhookFilterDaoImpl.delete(null, null);
+
+ assertEquals(0, result);
+ }
+
+ @Test
+ public void deleteReturnsNonZeroWhenIdOrWebhookIdExists() {
+ Long id = 1L;
+ Long webhookId = 2L;
+
+ Mockito.doReturn(1)
+ .when(webhookFilterDaoImpl).remove(Mockito.any(SearchCriteria.class));
+
+ int result = webhookFilterDaoImpl.delete(id, webhookId);
+
+ assertTrue(result >= 0);
+ }
+}
diff --git a/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookJoinDaoImplTest.java b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookJoinDaoImplTest.java
new file mode 100644
index 0000000..a77a2de
--- /dev/null
+++ b/plugins/event-bus/webhook/src/test/java/org/apache/cloudstack/mom/webhook/dao/WebhookJoinDaoImplTest.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.mom.webhook.dao;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cloudstack.mom.webhook.vo.WebhookJoinVO;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WebhookJoinDaoImplTest {
+ @Spy
+ @InjectMocks
+ private WebhookJoinDaoImpl webhookJoinDao;
+
+ @Mock
+ private WebhookJoinVO mockWebhookVO;
+ @Mock
+ private SearchBuilder<WebhookJoinVO> mockSearchBuilder;
+ @Mock
+ private SearchCriteria<WebhookJoinVO> mockSearchCriteria;
+
+ @Before
+ public void setUp() {
+ when(mockSearchBuilder.entity()).thenReturn(mockWebhookVO);
+ when(mockSearchBuilder.and()).thenReturn(mockSearchBuilder);
+ when(mockSearchBuilder.create()).thenReturn(mockSearchCriteria);
+ doReturn(mockSearchBuilder).when(webhookJoinDao).createSearchBuilder();
+ }
+
+ @Test
+ public void listByAccountOrDomainReturnsResultsWhenAccountIdMatches() {
+ long accountId = 1L;
+
+ doReturn(List.of(mockWebhookVO)).when(webhookJoinDao).listBy(any(SearchCriteria.class));
+
+ List<WebhookJoinVO> result = webhookJoinDao.listByAccountOrDomain(accountId, null);
+
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(mockSearchBuilder).op(eq("accountId"), any(), eq(SearchCriteria.Op.EQ));
+ verify(mockSearchCriteria).setParameters("accountId", accountId);
+ verify(mockSearchBuilder, never()).or(eq("domainPath"), any(), eq(SearchCriteria.Op.LIKE));
+ verify(mockSearchCriteria, never()).setParameters(eq("domainPath"), any());
+ }
+
+ @Test
+ public void listByAccountOrDomainReturnsResultsWhenBothAccountIdAndDomainPathMatch() {
+ long accountId = 10L;
+ String domainPath = "domain/path";
+
+ doReturn(List.of(mockWebhookVO)).when(webhookJoinDao).listBy(any(SearchCriteria.class));
+
+ List<WebhookJoinVO> result = webhookJoinDao.listByAccountOrDomain(accountId, domainPath);
+
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(mockSearchBuilder).op(eq("accountId"), any(), eq(SearchCriteria.Op.EQ));
+ verify(mockSearchCriteria).setParameters("accountId", accountId);
+ verify(mockSearchBuilder).or(eq("domainPath"), any(), eq(SearchCriteria.Op.LIKE));
+ verify(mockSearchCriteria).setParameters("domainPath", domainPath);
+ }
+
+ @Test
+ public void listByAccountOrDomainReturnsEmptyWhenNoMatchFound() {
+ long accountId = 999L;
+ String domainPath = "nonexistent/path";
+
+ doReturn(Collections.emptyList()).when(webhookJoinDao).listBy(any(SearchCriteria.class));
+
+ List<WebhookJoinVO> result = webhookJoinDao.listByAccountOrDomain(accountId, domainPath);
+
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ verify(mockSearchBuilder).op(eq("accountId"), any(), eq(SearchCriteria.Op.EQ));
+ verify(mockSearchCriteria).setParameters("accountId", accountId);
+ verify(mockSearchBuilder).or(eq("domainPath"), any(), eq(SearchCriteria.Op.LIKE));
+ verify(mockSearchCriteria).setParameters("domainPath", domainPath);
+ }
+}
diff --git a/plugins/ha-planners/skip-heurestics/pom.xml b/plugins/ha-planners/skip-heurestics/pom.xml
index e010e71..43f3abf 100644
--- a/plugins/ha-planners/skip-heurestics/pom.xml
+++ b/plugins/ha-planners/skip-heurestics/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/host-allocators/random/pom.xml b/plugins/host-allocators/random/pom.xml
index d55436e..061caf1 100644
--- a/plugins/host-allocators/random/pom.xml
+++ b/plugins/host-allocators/random/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/hypervisors/baremetal/pom.xml b/plugins/hypervisors/baremetal/pom.xml
index 384090e..fc4803b 100755
--- a/plugins/hypervisors/baremetal/pom.xml
+++ b/plugins/hypervisors/baremetal/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-hypervisor-baremetal</artifactId>
diff --git a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java
index 99bedbf..9bdc2fb 100644
--- a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java
+++ b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java
@@ -149,7 +149,6 @@
String errMsg =
String.format("Set dhcp entry on external DHCP %1$s failed(ip=%2$s, mac=%3$s, vmname=%4$s)", h.getPrivateIpAddress(), nic.getIPv4Address(),
nic.getMacAddress(), profile.getVirtualMachine().getHostName());
- // prepareBareMetalDhcpEntry(nic, dhcpCommand);
try {
Answer ans = _agentMgr.send(h.getId(), dhcpCommand);
if (ans.getResult()) {
diff --git a/plugins/hypervisors/external/pom.xml b/plugins/hypervisors/external/pom.xml
index 8359b1d..1c581f3 100644
--- a/plugins/hypervisors/external/pom.xml
+++ b/plugins/hypervisors/external/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-hypervisor-external</artifactId>
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
index 2e3de19..5d2e909 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
@@ -26,7 +26,7 @@
// C# versions of certain CloudStack types to simplify JSON serialisation.
// Limit to the number of types, because they are written and maintained manually.
// JsonProperty used to identify property name when serialised, which allows
-// later adoption of C# naming conventions if requried.
+// later adoption of C# naming conventions if required.
namespace HypervResource
{
public class PrimaryDataStoreTO
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_EthernetSwitchPort.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_EthernetSwitchPort.cs
index d1d2870..9626fa6 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_EthernetSwitchPort.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_EthernetSwitchPort.cs
@@ -1267,8 +1267,8 @@
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [Description("The current VMQ offloading usage on this port. The usage is the amount of VMQ res" +
- "ources in use on the port.")]
+ [Description("The current VMQ offloading usage on this port. The usage is the amount of VMQ " +
+ "resources in use on the port.")]
[TypeConverter(typeof(WMIValueTypeConverter))]
public uint VMQOffloadUsage {
get {
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_ExternalEthernetPort.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_ExternalEthernetPort.cs
index acf4923..801aa9e 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_ExternalEthernetPort.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/ROOT.virtualization.v2.Msvm_ExternalEthernetPort.cs
@@ -618,10 +618,9 @@
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [Description("If this property is true, then this Ethernet port can be connected to the switche" +
- "s and thus can provide connectivity to virtual machine. If this property is fals" +
- "e, then this Ethernet is not being used by the virtual machine networking archit" +
- "ecture.")]
+ [Description("If this property is true, then this Ethernet port can be connected to the switches" +
+ " and thus can provide connectivity to virtual machine. If this property is false" +
+ ", then this Ethernet is not being used by the virtual machine networking architecture.")]
[TypeConverter(typeof(WMIValueTypeConverter))]
public bool IsBound {
get {
diff --git a/plugins/hypervisors/hyperv/buildagent.sh b/plugins/hypervisors/hyperv/buildagent.sh
index e5bff6e..536ba43 100755
--- a/plugins/hypervisors/hyperv/buildagent.sh
+++ b/plugins/hypervisors/hyperv/buildagent.sh
@@ -1,20 +1,22 @@
#!/bin/bash
-# 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
+
+# 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
+# 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.
+# 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.
+
export EnableNuGetPackageRestore=true
wget http://nuget.org/nuget.exe
mv nuget.exe ./DotNet/ServerResource/.nuget/NuGet.exe
diff --git a/plugins/hypervisors/hyperv/pom.xml b/plugins/hypervisors/hyperv/pom.xml
index 758cee0..c67943a 100644
--- a/plugins/hypervisors/hyperv/pom.xml
+++ b/plugins/hypervisors/hyperv/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
diff --git a/plugins/hypervisors/kvm/pom.xml b/plugins/hypervisors/kvm/pom.xml
index 7e3bd38..255ada0 100644
--- a/plugins/hypervisors/kvm/pom.xml
+++ b/plugins/hypervisors/kvm/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 6b2eb4d..0a9e0d2 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -69,6 +69,7 @@
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
+import com.cloud.agent.api.to.VirtualMachineMetadataTO;
import org.apache.cloudstack.api.ApiConstants.IoDriverPolicy;
import org.apache.cloudstack.command.CommandInfo;
import org.apache.cloudstack.command.ReconcileCommandService;
@@ -199,6 +200,7 @@
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogAction;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogModel;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.MetadataDef;
import com.cloud.hypervisor.kvm.resource.rolling.maintenance.RollingMaintenanceAgentExecutor;
import com.cloud.hypervisor.kvm.resource.rolling.maintenance.RollingMaintenanceExecutor;
import com.cloud.hypervisor.kvm.resource.rolling.maintenance.RollingMaintenanceServiceExecutor;
@@ -3010,9 +3012,19 @@
vm.addComp(createClockDef(vmTO));
vm.addComp(createDevicesDef(vmTO, guest, vcpus, isUefiEnabled));
+ MetadataDef metaDef;
+ if ((metaDef = createMetadataDef(vmTO)) != null) {
+ vm.addComp(metaDef);
+ }
+
addExtraConfigsToVM(vmTO, vm, extraConfig);
}
+ protected MetadataDef createMetadataDef(VirtualMachineTO vmTO) {
+ VirtualMachineMetadataTO metadata = vmTO.getMetadata();
+ return (metadata != null) ? new MetadataDef(metadata) : null;
+ }
+
/**
* Adds extra configuration to User VM Domain XML before starting.
*/
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index 54b5d28..097a9b8 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -17,21 +17,42 @@
package com.cloud.hypervisor.kvm.resource;
import java.io.File;
+import java.io.StringWriter;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import com.cloud.cpu.CPU;
import org.apache.cloudstack.api.ApiConstants.IoDriverPolicy;
import org.apache.cloudstack.utils.qemu.QemuObject;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
+import com.cloud.agent.api.to.VirtualMachineMetadataTO;
+
import com.cloud.agent.properties.AgentProperties;
import com.cloud.agent.properties.AgentPropertiesFileHandler;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME;
public class LibvirtVMDef {
protected static Logger LOGGER = LogManager.getLogger(LibvirtVMDef.class);
@@ -46,6 +67,157 @@
private final Map<String, Object> components = new HashMap<String, Object>();
private static final int NUMBER_OF_IOTHREADS = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.IOTHREADS);
+ public static class MetadataDef {
+ private VirtualMachineMetadataTO metaTO;
+
+ public MetadataDef(VirtualMachineMetadataTO data) {
+ metaTO = data;
+ }
+
+ public VirtualMachineMetadataTO getMetadata() {
+ return metaTO;
+ }
+
+ @Override
+ public String toString() {
+ DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+ docFactory.setNamespaceAware(true);
+ Document doc = null;
+ try {
+ doc = docFactory.newDocumentBuilder().newDocument();
+ } catch (ParserConfigurationException e) {
+ LOGGER.warn("Could not create a new DOM XML document. The metadata will not be included in the libvirt domain XML: {}", e.getMessage());
+ return "";
+ }
+ Element metadata = doc.createElement("metadata"); // <metadata>
+ Element instance = doc.createElementNS("http://cloudstack.apache.org/instance", "cloudstack:instance"); // <cloudstack:instance>
+
+ Element zone = doc.createElement("cloudstack:zone");
+ zone.setAttribute("uuid", metaTO.getZoneUuid());
+ zone.setTextContent(metaTO.getZoneName());
+ instance.appendChild(zone);
+
+ Element pod = doc.createElement("cloudstack:pod");
+ pod.setAttribute("uuid", metaTO.getPodUuid());
+ pod.setTextContent(metaTO.getPodName());
+ instance.appendChild(pod);
+
+ Element cluster = doc.createElement("cloudstack:cluster");
+ cluster.setAttribute("uuid", metaTO.getClusterUuid());
+ cluster.setTextContent(metaTO.getClusterName());
+ instance.appendChild(cluster);
+
+ Element instanceName = doc.createElement("cloudstack:name");
+ instanceName.setTextContent(metaTO.getName());
+ instance.appendChild(instanceName);
+
+ Element instanceInternalName = doc.createElement("cloudstack:internal_name");
+ instanceInternalName.setTextContent(metaTO.getInternalName());
+ instance.appendChild(instanceInternalName);
+
+ Element instanceDisplayName = doc.createElement("cloudstack:display_name");
+ instanceDisplayName.setTextContent(metaTO.getDisplayName());
+ instance.appendChild(instanceDisplayName);
+
+ Element instanceUuid = doc.createElement("cloudstack:uuid");
+ instanceUuid.setTextContent(metaTO.getInstanceUuid());
+ instance.appendChild(instanceUuid);
+
+ Element serviceOffering = doc.createElement("cloudstack:service_offering"); // <service_offering>
+
+ Element computeOfferingName = doc.createElement("cloudstack:name");
+ computeOfferingName.setTextContent(metaTO.getserviceOfferingName());
+ serviceOffering.appendChild(computeOfferingName);
+
+ Element cpu = doc.createElement("cloudstack:cpu");
+ cpu.setTextContent(metaTO.getCpuCores().toString());
+ serviceOffering.appendChild(cpu);
+
+ Element memory = doc.createElement("cloudstack:memory");
+ memory.setTextContent(metaTO.getMemory().toString());
+ serviceOffering.appendChild(memory);
+
+ Element hostTags = doc.createElement("cloudstack:host_tags");
+ List<String> tags = metaTO.getserviceOfferingHostTags();
+ if (tags != null) {
+ for (String i : metaTO.getserviceOfferingHostTags()) {
+ Element tag = doc.createElement("cloudstack:tag");
+ tag.setTextContent(i);
+ hostTags.appendChild(tag);
+ }
+ }
+ serviceOffering.appendChild(hostTags);
+
+ instance.appendChild(serviceOffering); // </service_offering>
+
+ Element creationTime = doc.createElement("cloudstack:created_at");
+ creationTime.setTextContent(
+ LocalDateTime.ofInstant(Instant.ofEpochSecond(metaTO.getCreated()), ZoneOffset.UTC).format(ISO_LOCAL_DATE_TIME)
+ );
+ instance.appendChild(creationTime);
+
+ Element startedTime = doc.createElement("cloudstack:started_at");
+ startedTime.setTextContent(
+ LocalDateTime.ofInstant(Instant.ofEpochSecond(metaTO.getStarted()), ZoneOffset.UTC).format(ISO_LOCAL_DATE_TIME)
+ );
+ instance.appendChild(startedTime);
+
+ Element owner = doc.createElement("cloudstack:owner"); // <owner>
+
+ Element domain = doc.createElement("cloudstack:domain");
+ domain.setAttribute("uuid", metaTO.getOwnerDomainUuid());
+ domain.setTextContent(metaTO.getOwnerDomainName());
+ owner.appendChild(domain);
+
+ Element account = doc.createElement("cloudstack:account");
+ account.setAttribute("uuid", metaTO.getOwnerAccountUuid());
+ account.setTextContent(metaTO.getOwnerAccountName());
+ owner.appendChild(account);
+
+ Element project = doc.createElement("cloudstack:project");
+ project.setAttribute("uuid", metaTO.getOwnerProjectUuid());
+ project.setTextContent(metaTO.getOwnerProjectName());
+ owner.appendChild(project);
+
+ instance.appendChild(owner); // </owner>
+
+ Element resourceTags = doc.createElement("cloudstack:resource_tags"); // <resource_tags>
+ for (Map.Entry<String, String> entry : metaTO.getResourceTags().entrySet()) {
+ Element tag = doc.createElement("cloudstack:resource_tag"); // <resource_tag>
+ tag.setAttribute("key", entry.getKey());
+ tag.setTextContent(entry.getValue());
+ resourceTags.appendChild(tag); // </resource_tag>
+ }
+ instance.appendChild(resourceTags); // </resource_tags>
+
+ metadata.appendChild(instance); // </cloudstack:instance>
+ doc.appendChild(metadata); // </metadata>
+
+ Transformer transformer = null;
+ try {
+ transformer = TransformerFactory.newInstance().newTransformer();
+ } catch (TransformerConfigurationException e) {
+ LOGGER.warn("Could not create an XML transformer. The metadata will not be included in the libvirt domain XML: {}", e.getMessage());
+ return "";
+ }
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+
+ DOMSource domSource = new DOMSource(doc);
+ StringWriter writer = new StringWriter();
+ StreamResult result = new StreamResult(writer);
+ try {
+ transformer.transform(domSource, result);
+ } catch (TransformerException e) {
+ LOGGER.warn("Could not generate metadata XML. The metadata will not be included in the libvirt domain XML: {}", e.getMessage());
+ return "";
+ }
+
+ return writer.toString();
+ }
+ }
+
public static class GuestDef {
enum GuestType {
KVM, XEN, EXE, LXC
@@ -249,7 +421,9 @@
guestDef.append("<boot dev='" + bo + "'/>\n");
}
}
- guestDef.append("<smbios mode='sysinfo'/>\n");
+ if (!CPU.CPUArch.s390x.getType().equalsIgnoreCase(_arch)) {
+ guestDef.append("<smbios mode='sysinfo'/>\n");
+ }
guestDef.append("</os>\n");
if (iothreads) {
guestDef.append(String.format("<iothreads>%s</iothreads>", NUMBER_OF_IOTHREADS));
@@ -2178,34 +2352,6 @@
}
}
- public class MetadataDef {
- Map<String, Object> customNodes = new HashMap<>();
-
- public <T> T getMetadataNode(Class<T> fieldClass) {
- T field = (T) customNodes.get(fieldClass.getName());
- if (field == null) {
- try {
- field = fieldClass.newInstance();
- customNodes.put(field.getClass().getName(), field);
- } catch (InstantiationException | IllegalAccessException e) {
- LOGGER.debug("No default constructor available in class " + fieldClass.getName() + ", ignoring exception", e);
- }
- }
- return field;
- }
-
- @Override
- public String toString() {
- StringBuilder fsBuilder = new StringBuilder();
- fsBuilder.append("<metadata>\n");
- for (Object field : customNodes.values()) {
- fsBuilder.append(field.toString());
- }
- fsBuilder.append("</metadata>\n");
- return fsBuilder.toString();
- }
- }
-
public static class RngDef {
enum RngModel {
VIRTIO("virtio");
@@ -2508,15 +2654,6 @@
return null;
}
- public MetadataDef getMetaData() {
- MetadataDef o = (MetadataDef) components.get(MetadataDef.class.toString());
- if (o == null) {
- o = new MetadataDef();
- addComp(o);
- }
- return o;
- }
-
@Override
public String toString() {
StringBuilder vmBuilder = new StringBuilder();
@@ -2528,6 +2665,7 @@
if (_desc != null) {
vmBuilder.append("<description>" + _desc + "</description>\n");
}
+
for (Object o : components.values()) {
vmBuilder.append(o.toString());
}
diff --git a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java
index db665c7..e88981f 100644
--- a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java
+++ b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java
@@ -140,7 +140,7 @@
long speed = 0L;
LOGGER.info("Fetching CPU speed from command \"lscpu\".");
try {
- String command = "lscpu | grep -i 'Model name' | head -n 1 | egrep -o '[[:digit:]].[[:digit:]]+GHz' | sed 's/GHz//g'";
+ String command = "lscpu | grep -i 'Model name' | head -n 1 | grep -E -o '[[:digit:]].[[:digit:]]+GHz' | sed 's/GHz//g'";
if(isHostS390x()) {
command = "lscpu | grep 'CPU dynamic MHz' | cut -d ':' -f 2 | tr -d ' ' | awk '{printf \"%.1f\\n\", $1 / 1000}'";
}
diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
index 0fae980..cde87fd 100644
--- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
+++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
@@ -183,6 +183,7 @@
import com.cloud.agent.properties.AgentProperties;
import com.cloud.agent.properties.AgentPropertiesFileHandler;
import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource;
+import com.cloud.cpu.CPU;
import com.cloud.exception.InternalErrorException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.kvm.resource.KVMHABase.HAStoragePool;
@@ -878,7 +879,9 @@
private void verifyFeatures(Document domainDoc) {
assertNodeExists(domainDoc, "/domain/features/pae");
assertNodeExists(domainDoc, "/domain/features/apic");
- assertNodeExists(domainDoc, "/domain/features/acpi");
+ if (!CPU.CPUArch.s390x.getType().equalsIgnoreCase(System.getProperty("os.arch"))) {
+ assertNodeExists(domainDoc, "/domain/features/acpi");
+ }
}
private void verifyHeader(Document domainDoc, String hvsType, String name, String uuid, String os) {
diff --git a/plugins/hypervisors/ovm/pom.xml b/plugins/hypervisors/ovm/pom.xml
index 2149926..d29f9af 100644
--- a/plugins/hypervisors/ovm/pom.xml
+++ b/plugins/hypervisors/ovm/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/hypervisors/ovm/src/main/java/com/cloud/ovm/object/Test.java b/plugins/hypervisors/ovm/src/main/java/com/cloud/ovm/object/Test.java
index cd1b14e..32960a9 100644
--- a/plugins/hypervisors/ovm/src/main/java/com/cloud/ovm/object/Test.java
+++ b/plugins/hypervisors/ovm/src/main/java/com/cloud/ovm/object/Test.java
@@ -23,37 +23,6 @@
public class Test {
public static void main(final String[] args) {
try {
- /*Connection c = new Connection("192.168.105.155", "oracle", "password");
- Utils util = new UtilsImpl(c);
- Storage storage = new StorageImpl(c);
- String[] res = util.listDir("/etc", 1);
- for (String s : res) {
- System.out.println(s);
- }
-
-
- Pool pool = new PoolImpl(c);
-
- //pool.registerServer("192.168.105.155", Pool.ServerType.SITE);
- //pool.registerServer("192.168.105.155", Pool.ServerType.UTILITY);
- //pool.registerServer("192.168.105.155", Pool.ServerType.XEN);
- System.out.println("Is:" + pool.isServerRegistered());
- System.out.println(pool.getServerConfig());
- System.out.println(pool.getServerXmInfo());
- System.out.println(pool.getHostInfo());
- System.out.println(pool.getAgentVersion());
- String[] srs = storage.listSr();
- for (int i=0; i<srs.length; i++) {
- System.out.println(srs[i]);
- }
- String spuuid = storage.createSp(StorageType.OVSSPNFS, "192.168.110.232:/export/frank/nfs");
- System.out.println(spuuid);
- String sruuid = storage.createSr(spuuid, "hi");
- System.out.println(sruuid);
- storage.initSr();
- Pair<Long, Long> spaceInfo = storage.getSrSpaceInfo("192.168.110.232:/export/frank/nfs");
- System.out.println("Total:" + spaceInfo.first());
- System.out.println("Free:" + spaceInfo.second());*/
final OvmVm.Details vm = new OvmVm.Details();
vm.cpuNum = 1;
vm.memory = 512;
@@ -80,23 +49,7 @@
vm.vifs.add(vif);
vm.vifs.add(vif);
vm.vifs.add(vif);
- //System.out.println(vm.toJson());
final Connection c = new Connection("192.168.189.12", "oracle", "password");
- //System.out.println(Coder.toJson(OvmHost.getDetails(c)));
-
- /* This is not being used at the moment.
- * Coverity issue: 1012179
- */
-
- //OvmHost.Details d = new GsonBuilder().create().fromJson(txt, OvmHost.Details.class);
- //OvmHost.Details d = Coder.fromJson(txt, OvmHost.Details.class);
- //OvmHost.Details d = OvmHost.getDetails(c);
- //System.out.println(Coder.toJson(d));
- // OvmStoragePool.Details pool = new OvmStoragePool.Details();
- // pool.path = "192.168.110.232:/export/frank/ovs";
- // pool.type = OvmStoragePool.NFS;
- // pool.uuid = "123";
- // System.out.println(pool.toJson());
String cmd = null;
System.out.println(args.length);
@@ -119,15 +72,10 @@
System.out.println(d.toJson());
if (cmd.equalsIgnoreCase("create")) {
- // String s =
- // "{\"cpuNum\":1,\"memory\":512,\"rootDisk\":{\"type\":\"w\",\"path\":\"/var/ovs/mount/60D0985974CA425AAF5D01A1F161CC8B/running_pool/36_systemvm/System.img\"},\"disks\":[],\"vifs\":[{\"mac\":\"00:16:3E:5C:B1:D1\",\"bridge\":\"xenbr0\",\"type\":\"netfront\"}],\"name\":\"MyTest\",\"uuid\":\"1-2-3-4-5\"}";
OvmVm.create(c, d);
- // c.call("OvmVm.echo", new Object[]{s});
} else if (cmd.equalsIgnoreCase("reboot")) {
final Map<String, String> res = OvmVm.reboot(c, "MyTest");
System.out.println(res.get("vncPort"));
- //OvmVm.stop(c, "MyTest");
- //OvmVm.create(c, d);
} else if (cmd.equalsIgnoreCase("stop")) {
OvmVm.stop(c, "MyTest");
} else if (cmd.equalsIgnoreCase("details")) {
@@ -166,12 +114,6 @@
l.add("4b4d8951-f0b6-36c5-b4f3-a82ff2611c65");
System.out.println(Coder.toJson(l));
- // Map<String, String> res = OvmHost.getPerformanceStats(c, "xenbr0");
- // System.out.println(res.toString());
- // String stxt = "{\"vifs\": [{\"bridge\": \"xenbr0\", \"mac\": \"00:16:3E:5C:B1:D1\", \"type\": \"netfront\"}], \"powerState\": \"RUNNING\", \"disks\": [], \"cpuNum\": 1, \"memory\": 536870912, \"rootDisk\": {\"path\": \"/var/ovs/mount/60D0985974CA425AAF5D01A1F161CC8B/running_pool/MyTest/System.img\", \"type\": \"w\"}}";
- // OvmVm.Details ddd = Coder.fromJson(stxt, OvmVm.Details.class);
- // System.out.println(ddd.vifs.size());
- // System.out.println(ddd.rootDisk.path);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
diff --git a/plugins/hypervisors/ovm3/pom.xml b/plugins/hypervisors/ovm3/pom.xml
index c88284c..4214ee8 100644
--- a/plugins/hypervisors/ovm3/pom.xml
+++ b/plugins/hypervisors/ovm3/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/hypervisors/ovm3/sonar-project.properties b/plugins/hypervisors/ovm3/sonar-project.properties
index d632dfb..7cc3a41 100644
--- a/plugins/hypervisors/ovm3/sonar-project.properties
+++ b/plugins/hypervisors/ovm3/sonar-project.properties
@@ -1,19 +1,19 @@
-#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
+# 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
+# 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.
+# 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.
# Required metadata
sonar.projectKey=cloud-plugin-hypervisor-ovm3
@@ -24,7 +24,7 @@
sonar.sources=src
sonar.binaries=target/classes
-# Exclussions
+# Exclusions
sonar.exclusions=**/*Test.java
# Language
diff --git a/plugins/hypervisors/ovm3/src/test/resources/log4j.properties b/plugins/hypervisors/ovm3/src/test/resources/log4j.properties
index 82ee5c5..0f72e39 100644
--- a/plugins/hypervisors/ovm3/src/test/resources/log4j.properties
+++ b/plugins/hypervisors/ovm3/src/test/resources/log4j.properties
@@ -1,19 +1,19 @@
-#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
+# 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
+# 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.
+# 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.
# Root logger option
log4j.rootLogger=DEBUG, stdout
diff --git a/plugins/hypervisors/ovm3/src/test/resources/scripts/clean_primary.sh b/plugins/hypervisors/ovm3/src/test/resources/scripts/clean_primary.sh
index bbf1cd0..5086a16 100755
--- a/plugins/hypervisors/ovm3/src/test/resources/scripts/clean_primary.sh
+++ b/plugins/hypervisors/ovm3/src/test/resources/scripts/clean_primary.sh
@@ -17,7 +17,7 @@
# specific language governing permissions and limitations
# under the License.
#
-for i in `xm list | awk '{ print $1 }' | egrep -v "Name|Domain-0"`
+for i in `xm list | awk '{ print $1 }' | grep -E -v "Name|Domain-0"`
do
xm destroy $i
done
diff --git a/plugins/hypervisors/ovm3/src/test/resources/scripts/clean_secondary.sh b/plugins/hypervisors/ovm3/src/test/resources/scripts/clean_secondary.sh
index 4275ee8..3d51339 100755
--- a/plugins/hypervisors/ovm3/src/test/resources/scripts/clean_secondary.sh
+++ b/plugins/hypervisors/ovm3/src/test/resources/scripts/clean_secondary.sh
@@ -17,7 +17,7 @@
# specific language governing permissions and limitations
# under the License.
#
-for i in `xm list | awk '{ print $1 }' | egrep -v "Name|Domain-0"`
+for i in `xm list | awk '{ print $1 }' | grep -E -v "Name|Domain-0"`
do
xm destroy $i
done
diff --git a/plugins/hypervisors/ovm3/src/test/resources/scripts/socat.sh b/plugins/hypervisors/ovm3/src/test/resources/scripts/socat.sh
index e37ba47..6072bb6 100755
--- a/plugins/hypervisors/ovm3/src/test/resources/scripts/socat.sh
+++ b/plugins/hypervisors/ovm3/src/test/resources/scripts/socat.sh
@@ -1,19 +1,21 @@
-#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
+#!/bin/bash
+
+# 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
+# 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.
+# 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.
CERT="/etc/ovs-agent/cert"
socat OPENSSL-LISTEN:8899,reuseaddr,fork,verify=0,key=$CERT/key.pem,cert=$CERT/certificate.pem TCP:localhost:8898 &
diff --git a/plugins/hypervisors/ovm3/src/test/resources/scripts/tail.sh b/plugins/hypervisors/ovm3/src/test/resources/scripts/tail.sh
index 2665c44..458f3ec 100755
--- a/plugins/hypervisors/ovm3/src/test/resources/scripts/tail.sh
+++ b/plugins/hypervisors/ovm3/src/test/resources/scripts/tail.sh
@@ -1,19 +1,21 @@
-#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
+#!/bin/bash
+
+# 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
+# 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.
+# 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.
cd /var/log
tail -f ovm-consoled.log devmon.log messages ovs-agent.log ovmwatch.log
diff --git a/plugins/hypervisors/simulator/pom.xml b/plugins/hypervisors/simulator/pom.xml
index f594232..8ef011f 100644
--- a/plugins/hypervisors/simulator/pom.xml
+++ b/plugins/hypervisors/simulator/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-hypervisor-simulator</artifactId>
diff --git a/plugins/hypervisors/ucs/pom.xml b/plugins/hypervisors/ucs/pom.xml
index 521dd74..67bde3b 100644
--- a/plugins/hypervisors/ucs/pom.xml
+++ b/plugins/hypervisors/ucs/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-hypervisor-ucs</artifactId>
diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml
index 355d448..7637cb7 100644
--- a/plugins/hypervisors/vmware/pom.xml
+++ b/plugins/hypervisors/vmware/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareCleanupMaid.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareCleanupMaid.java
index d2c71c4..49f1097 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareCleanupMaid.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareCleanupMaid.java
@@ -65,15 +65,6 @@
_vmName = vmName;
}
-// @Override
-// public int cleanup(CheckPointManager checkPointMgr) {
-//
-// // save a check-point in case we crash at current run so that we won't lose it
-// _checkPoint = checkPointMgr.pushCheckPoint(new VmwareCleanupMaid(_vCenterAddress, _dcMorValue, _vmName));
-// addLeftOverVM(this);
-// return 0;
-// }
-
public String getCleanupProcedure() {
return null;
}
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 831e222..621f008 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -4605,7 +4605,7 @@
vmMo.mountToolsInstaller();
logger.debug(String.format("Successfully re-mounted VMware tools installer for :[%s].", cmd.getVmName()));
} catch (Exception e) {
- logger.error(String.format("Unabled to re-mount VMware tools installer for: [%s].", cmd.getVmName()), e);
+ logger.error("Unable to re-mount VMware tools installer for: [{}].", cmd.getVmName(), e);
}
}
}
@@ -7072,7 +7072,7 @@
if (s_serviceContext.get() != null) {
context = s_serviceContext.get();
String poolKey = VmwareContextPool.composePoolKey(_vCenterAddress, _username);
- // Before re-using the thread local context, ensure it corresponds to the right vCenter API session and that it is valid to make calls.
+ // Before reusing the thread local context, ensure it corresponds to the right vCenter API session and that it is valid to make calls.
if (context.getPoolKey().equals(poolKey)) {
if (context.validate()) {
if (logger.isTraceEnabled()) {
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java
index beac489..73d63f0 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java
@@ -66,9 +66,7 @@
@DB
- //public CiscoNexusVSMDeviceVO addCiscoNexusVSM(long clusterId, String ipaddress, String username, String password, ServerResource resource, String vsmName) {
- public
- CiscoNexusVSMDeviceVO addCiscoNexusVSM(long clusterId, String ipaddress, String username, String password, String vCenterIpaddr, String vCenterDcName) {
+ public CiscoNexusVSMDeviceVO addCiscoNexusVSM(long clusterId, String ipaddress, String username, String password, String vCenterIpaddr, String vCenterDcName) {
// In this function, we associate this VSM with each host
// in the clusterId specified.
@@ -154,28 +152,6 @@
// into each host's resource. Also, we first configure each resource's
// entries in the database to contain this VSM information before the injection.
- //for (HostVO host : hosts) {
- // Create a host details VO object and write it out for this hostid.
- //Long hostid = new Long(vsmId);
- //DetailVO vsmDetail = new DetailVO(host.getId(), "vsmId", hostid.toString());
- //Transaction tx = Transaction.currentTxn();
- //try {
- //tx.start();
- //_hostDetailDao.persist(vsmDetail);
- //tx.commit();
- //} catch (Exception e) {
- //tx.rollback();
- //throw new CloudRuntimeException(e.getMessage());
- //}
- //}
- // Reconfigure the resource.
- //Map hostDetails = new HashMap<String, String>();
- //hostDetails.put(ApiConstants.ID, vsmId);
- //hostDetails.put(ApiConstants.IP_ADDRESS, ipaddress);
- //hostDetails.put(ApiConstants.USERNAME, username);
- //hostDetails.put(ApiConstants.PASSWORD, password);
- //_agentMrg.send(host.getId(), )
-
return VSMObj;
}
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java
index af44d9d..253bbf2 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -998,11 +998,11 @@
long wait, String nfsVersion) throws Exception {
String volumeFolder;
String volumeName;
- String sufix = ".ova";
+ String suffix = ".ova";
int index = srcVolumePath.lastIndexOf(File.separator);
- if (srcVolumePath.endsWith(sufix)) {
+ if (srcVolumePath.endsWith(suffix)) {
volumeFolder = srcVolumePath.substring(0, index);
- volumeName = srcVolumePath.substring(index + 1).replace(sufix, "");
+ volumeName = srcVolumePath.substring(index + 1).replace(suffix, "");
} else {
volumeFolder = srcVolumePath;
volumeName = srcVolumePath.substring(index + 1);
@@ -3790,16 +3790,16 @@
}
DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs);
- boolean isDatastoreStoragePolicyComplaint = primaryDsMo.isDatastoreStoragePolicyComplaint(storagePolicyId);
+ boolean isDatastoreStoragePolicyCompliant = primaryDsMo.isDatastoreStoragePolicyCompliant(storagePolicyId);
- String failedMessage = String.format("DataStore %s is not compliance with storage policy id %s", primaryStorageNameLabel, storagePolicyId);
- if (!isDatastoreStoragePolicyComplaint)
- return new Answer(cmd, isDatastoreStoragePolicyComplaint, failedMessage);
+ String failedMessage = String.format("DataStore %s is not compliant with storage policy id %s", primaryStorageNameLabel, storagePolicyId);
+ if (!isDatastoreStoragePolicyCompliant)
+ return new Answer(cmd, isDatastoreStoragePolicyCompliant, failedMessage);
else
- return new Answer(cmd, isDatastoreStoragePolicyComplaint, null);
+ return new Answer(cmd, isDatastoreStoragePolicyCompliant, null);
} catch (Throwable e) {
hostService.createLogMessageException(e, cmd);
- String details = String.format("Exception while checking if datastore [%s] is storage policy [%s] compliance due to: [%s]", primaryStorageNameLabel, storagePolicyId, VmwareHelper.getExceptionMessage(e));
+ String details = String.format("Exception while checking if datastore [%s] is storage policy [%s] compliant due to: [%s]", primaryStorageNameLabel, storagePolicyId, VmwareHelper.getExceptionMessage(e));
return new Answer(cmd, false, details);
}
}
diff --git a/plugins/hypervisors/xenserver/pom.xml b/plugins/hypervisors/xenserver/pom.xml
index cafa999..4d7ebf6 100644
--- a/plugins/hypervisors/xenserver/pom.xml
+++ b/plugins/hypervisors/xenserver/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
index ca38d4d..cdb4d74 100644
--- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
@@ -51,6 +51,7 @@
import javax.naming.ConfigurationException;
import javax.xml.parsers.ParserConfigurationException;
+import com.xensource.xenapi.VTPM;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageAnswer;
import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageCommand;
@@ -2908,7 +2909,7 @@
* within a XenServer that's under CloudStack control.
*
* - Native Networks: these are networks that are untagged on the XenServer
- * and are used to crate VLAN networks on. These are created by the user and
+ * and are used to create VLAN networks on. These are created by the user and
* is assumed to be one per cluster. - VLAN Networks: these are dynamically
* created by CloudStack and can have problems with duplicated names. -
* LinkLocal Networks: these are dynamically created by CloudStack and can
@@ -3773,7 +3774,7 @@
Host host = pbd.getHost(conn);
if (!isRefNull(host) && StringUtils.equals(host.getUuid(conn), _host.getUuid())) {
if (!pbd.getCurrentlyAttached(conn)) {
- logger.debug(String.format("PBD [%s] of local SR [%s] was unplugged, pluggin it now", pbd.getUuid(conn), srRec.uuid));
+ logger.debug(String.format("PBD [%s] of local SR [%s] was unplugged, plugging it in now", pbd.getUuid(conn), srRec.uuid));
pbd.plug(conn);
}
logger.debug("Scanning local SR: " + srRec.uuid);
@@ -5826,4 +5827,82 @@
public void destroyVm(VM vm, Connection connection) throws XenAPIException, XmlRpcException {
destroyVm(vm, connection, false);
}
+
+ /**
+ * Configure vTPM (Virtual Trusted Platform Module) support for a VM.
+ * vTPM provides a virtual TPM 2.0 device for VMs, enabling features like Secure Boot and disk encryption.
+ *
+ * Requirements:
+ * - XenServer/XCP-ng 8.3 (and above)
+ * - UEFI Secure Boot enabled
+ * - VM in halted state
+ *
+ * @param conn XenServer connection
+ * @param vm The VM to configure
+ * @param vmSpec VM specification containing vTPM settings
+ */
+ public void configureVTPM(Connection conn, VM vm, VirtualMachineTO vmSpec) throws XenAPIException, XmlRpcException {
+ if (vmSpec == null || vmSpec.getDetails() == null) {
+ return;
+ }
+
+ String vtpmEnabled = vmSpec.getDetails().getOrDefault(VmDetailConstants.VIRTUAL_TPM_ENABLED, null);
+
+ final Map<String, String> platform = vm.getPlatform(conn);
+ if (platform != null) {
+ final String guestRequiresVtpm = platform.get("vtpm");
+ if (guestRequiresVtpm != null && Boolean.parseBoolean(guestRequiresVtpm) && !Boolean.parseBoolean(vtpmEnabled)) {
+ logger.warn("Guest OS requires vTPM by default, even if VM details doesn't have the setting: {}", vmSpec.getName());
+ return;
+ }
+ }
+
+ if (!Boolean.parseBoolean(vtpmEnabled)) {
+ return;
+ }
+
+ String bootMode = StringUtils.defaultIfEmpty(vmSpec.getDetails().get(ApiConstants.BootType.UEFI.toString()), null);
+ String bootType = (bootMode == null) ? ApiConstants.BootType.BIOS.toString() : ApiConstants.BootType.UEFI.toString();
+
+ if (!ApiConstants.BootType.UEFI.toString().equals(bootType)) {
+ logger.warn("vTPM requires UEFI boot mode. Skipping vTPM configuration for VM: {}", vmSpec.getName());
+ return;
+ }
+
+ try {
+ Set<VTPM> existingVtpms = vm.getVTPMs(conn);
+ if (!existingVtpms.isEmpty()) {
+ logger.debug("vTPM already exists for VM: {}", vmSpec.getName());
+ return;
+ }
+
+ // Creates vTPM using: xe vtpm-create vm-uuid=<uuid>
+ String vmUuid = vm.getUuid(conn);
+ String result = callHostPlugin(conn, "vmops", "create_vtpm", "vm_uuid", vmUuid);
+
+ if (result == null || result.isEmpty() || result.startsWith("ERROR:") || result.startsWith("EXCEPTION:")) {
+ throw new CloudRuntimeException("Failed to create vTPM, result: " + result);
+ }
+
+ logger.info("Successfully created vTPM {} for VM: {}", result.trim(), vmSpec.getName());
+ } catch (Exception e) {
+ logger.warn("Failed to configure vTPM for VM: {}, continuing without vTPM", vmSpec.getName(), e);
+ }
+ }
+
+ public boolean isVTPMSupported(Connection conn, Host host) {
+ try {
+ Host.Record hostRecord = host.getRecord(conn);
+ String productVersion = hostRecord.softwareVersion.get("product_version");
+ if (productVersion == null) {
+ return false;
+ }
+ ComparableVersion currentVersion = new ComparableVersion(productVersion);
+ ComparableVersion minVersion = new ComparableVersion("8.2.0");
+ return currentVersion.compareTo(minVersion) >= 0;
+ } catch (Exception e) {
+ logger.warn("Failed to check vTPM support on host", e);
+ return false;
+ }
+ }
}
diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
index 3ecbafc..c03b419 100644
--- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
+++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
@@ -220,7 +220,7 @@
srUuid = sr.getUuid(conn);
Set<PBD> pbDs = sr.getPBDs(conn);
for (PBD pbd : pbDs) {
- logger.debug(String.format("Unpluging PBD [%s] of SR [%s] as it is not working properly.", pbd.getUuid(conn), srUuid));
+ logger.debug(String.format("Unplugging PBD [%s] of SR [%s] as it is not working properly.", pbd.getUuid(conn), srUuid));
unplugPbd(conn, pbd);
}
logger.debug(String.format("Forgetting SR [%s] as it is not working properly.", srUuid));
@@ -239,7 +239,7 @@
pbdUuid = pbd.getUuid(conn);
pbd.unplug(conn);
} catch (XenAPIException | XmlRpcException e) {
- throw new CloudRuntimeException(String.format("Exception while unpluging PBD [%s].", pbdUuid));
+ throw new CloudRuntimeException(String.format("Exception while unplugging PBD [%s].", pbdUuid));
}
}
diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixReadyCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixReadyCommandWrapper.java
index c5605e8..4f55ae8 100644
--- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixReadyCommandWrapper.java
+++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixReadyCommandWrapper.java
@@ -60,12 +60,20 @@
final Set<VM> vms = host.getResidentVMs(conn);
citrixResourceBase.destroyPatchVbd(conn, vms);
+ } catch (final Exception e) {
+ logger.warn("Unable to destroy CD-ROM device for system VMs", e);
+ }
+
+ try {
+ final Host host = Host.getByUuid(conn, citrixResourceBase.getHost().getUuid());
final Host.Record hr = host.getRecord(conn);
if (isUefiSupported(CitrixHelper.getProductVersion(hr))) {
hostDetails.put(com.cloud.host.Host.HOST_UEFI_ENABLE, Boolean.TRUE.toString());
}
- } catch (final Exception e) {
+ } catch (Exception e) {
+ logger.warn("Unable to get UEFI support info", e);
}
+
try {
final boolean result = citrixResourceBase.cleanupHaltedVms(conn);
if (!result) {
diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java
index d448638..5c2355a 100644
--- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java
+++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java
@@ -97,6 +97,14 @@
citrixResourceBase.createVGPU(conn, command, vm, gpuDevice);
}
+ try {
+ if (citrixResourceBase.isVTPMSupported(conn, host)) {
+ citrixResourceBase.configureVTPM(conn, vm, vmSpec);
+ }
+ } catch (Exception e) {
+ logger.warn("Failed to configure vTPM for VM " + vmName + ", continuing without vTPM", e);
+ }
+
Host.Record record = host.getRecord(conn);
String xenBrand = record.softwareVersion.get("product_brand");
String xenVersion = record.softwareVersion.get("product_version");
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java
index d464a26..b9504b6 100755
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java
@@ -576,37 +576,6 @@
fail(e.getMessage());
}
- // try {
- // PowerMockito.mockStatic(Host.class);
- // //BDDMockito.given(Host.getByUuid(conn,
- // xsHost.getUuid())).willReturn(host);
- // PowerMockito.when(Host.getByUuid(conn,
- // xsHost.getUuid())).thenReturn(host);
- // PowerMockito.verifyStatic(times(1));
- // } catch (final BadServerResponse e) {
- // fail(e.getMessage());
- // } catch (final XenAPIException e) {
- // fail(e.getMessage());
- // } catch (final XmlRpcException e) {
- // fail(e.getMessage());
- // }
- //
- // PowerMockito.mockStatic(Types.class);
- // PowerMockito.when(Types.toHostRecord(spiedMap)).thenReturn(hr);
- // PowerMockito.verifyStatic(times(1));
- //
- // try {
- // PowerMockito.mockStatic(Host.Record.class);
- // when(host.getRecord(conn)).thenReturn(hr);
- // verify(host, times(1)).getRecord(conn);
- // } catch (final BadServerResponse e) {
- // fail(e.getMessage());
- // } catch (final XenAPIException e) {
- // fail(e.getMessage());
- // } catch (final XmlRpcException e) {
- // fail(e.getMessage());
- // }
-
final Answer answer = wrapper.execute(maintainCommand, citrixResourceBase);
assertFalse(answer.getResult());
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java
index 4b2dd1a..d5e794d 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java
@@ -462,17 +462,6 @@
verify(xenServer610Resource, times(1)).getConnection();
- // try {
- // verify(xenServer610Resource, times(1)).waitForTask(conn, task, 1000, timeout);
- // verify(xenServer610Resource, times(1)).checkForSuccess(conn, task);
- // } catch (final XenAPIException e) {
- // fail(e.getMessage());
- // } catch (final XmlRpcException e) {
- // fail(e.getMessage());
- // } catch (final TimeoutException e) {
- // fail(e.getMessage());
- // }
-
assertFalse(answer.getResult());
}
diff --git a/plugins/integrations/cloudian/pom.xml b/plugins/integrations/cloudian/pom.xml
index 69321f9..1c806ac 100644
--- a/plugins/integrations/cloudian/pom.xml
+++ b/plugins/integrations/cloudian/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/integrations/cloudian/src/main/java/org/apache/cloudstack/cloudian/api/CloudianIsEnabledCmd.java b/plugins/integrations/cloudian/src/main/java/org/apache/cloudstack/cloudian/api/CloudianIsEnabledCmd.java
index 56cb74e..3c334ba 100644
--- a/plugins/integrations/cloudian/src/main/java/org/apache/cloudstack/cloudian/api/CloudianIsEnabledCmd.java
+++ b/plugins/integrations/cloudian/src/main/java/org/apache/cloudstack/cloudian/api/CloudianIsEnabledCmd.java
@@ -31,7 +31,8 @@
responseObject = CloudianEnabledResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.11.0",
- authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
+ httpMethod = "GET")
public class CloudianIsEnabledCmd extends BaseCmd {
@Inject
diff --git a/plugins/integrations/kubernetes-service/pom.xml b/plugins/integrations/kubernetes-service/pom.xml
index 9aad4d6..6b5cec9 100644
--- a/plugins/integrations/kubernetes-service/pom.xml
+++ b/plugins/integrations/kubernetes-service/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/admin/kubernetes/version/AddKubernetesSupportedVersionCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/admin/kubernetes/version/AddKubernetesSupportedVersionCmd.java
index f5c013a..775b6c6 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/admin/kubernetes/version/AddKubernetesSupportedVersionCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/admin/kubernetes/version/AddKubernetesSupportedVersionCmd.java
@@ -89,7 +89,7 @@
private Boolean directDownload;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the Kubernetes ISO. Valid options are: x86_64, aarch64",
+ description = "the CPU arch of the Kubernetes ISO. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
index 9ce6dc3..d309222 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
@@ -388,7 +388,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/version/ListKubernetesSupportedVersionsCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/version/ListKubernetesSupportedVersionsCmd.java
index 9e7d057..b50d2e6 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/version/ListKubernetesSupportedVersionsCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/version/ListKubernetesSupportedVersionsCmd.java
@@ -67,7 +67,7 @@
private Long minimumKubernetesVersionId;
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
- description = "the CPU arch of the binaries ISO. Valid options are: x86_64, aarch64",
+ description = "the CPU arch of the binaries ISO. Valid options are: x86_64, aarch64, s390x",
since = "4.20")
private String arch;
diff --git a/plugins/integrations/prometheus/pom.xml b/plugins/integrations/prometheus/pom.xml
index 378eab5..6f6b342 100644
--- a/plugins/integrations/prometheus/pom.xml
+++ b/plugins/integrations/prometheus/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/integrations/prometheus/src/main/java/org/apache/cloudstack/metrics/PrometheusExporterImpl.java b/plugins/integrations/prometheus/src/main/java/org/apache/cloudstack/metrics/PrometheusExporterImpl.java
index 8908bfa..2ed65ef 100644
--- a/plugins/integrations/prometheus/src/main/java/org/apache/cloudstack/metrics/PrometheusExporterImpl.java
+++ b/plugins/integrations/prometheus/src/main/java/org/apache/cloudstack/metrics/PrometheusExporterImpl.java
@@ -512,20 +512,48 @@
public String getMetrics() {
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("# Cloudstack Prometheus Metrics\n");
- for (final Item item : metricsItems) {
+
+ List<Item> sortedItems = metricsItems.stream()
+ .sorted((item1, item2) -> item1.name.compareTo(item2.name))
+ .collect(Collectors.toList());
+
+ String currentMetricName = null;
+
+ for (Item item : sortedItems) {
+ if (!item.name.equals(currentMetricName)) {
+ currentMetricName = item.name;
+ stringBuilder.append("# HELP ").append(currentMetricName).append(" ")
+ .append(item.getHelp()).append("\n");
+ stringBuilder.append("# TYPE ").append(currentMetricName).append(" ")
+ .append(item.getType()).append("\n");
+ }
+
stringBuilder.append(item.toMetricsString()).append("\n");
}
+
return stringBuilder.toString();
}
private abstract class Item {
String name;
+ String help;
+ String type;
- public Item(final String nm) {
+ public Item(final String nm, final String hlp, final String tp) {
name = nm;
+ help = hlp;
+ type = tp;
}
public abstract String toMetricsString();
+
+ public String getHelp() {
+ return help;
+ }
+
+ public String getType() {
+ return type;
+ }
}
class ItemVM extends Item {
@@ -535,7 +563,9 @@
long total;
public ItemVM(final String zn, final String zu, final String st, long cnt) {
- super("cloudstack_vms_total");
+ super("cloudstack_vms_total",
+ "Total number of virtual machines",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
filter = st;
@@ -556,7 +586,9 @@
String hosttags;
public ItemVMByTag(final String zn, final String zu, final String st, long cnt, final String tags) {
- super("cloudstack_vms_total_by_tag");
+ super("cloudstack_vms_total_by_tag",
+ "Total number of virtual machines grouped by host tags",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
filter = st;
@@ -577,7 +609,9 @@
int total;
public ItemVolume(final String zn, final String zu, final String st, int cnt) {
- super("cloudstack_volumes_total");
+ super("cloudstack_volumes_total",
+ "Total number of volumes",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
filter = st;
@@ -598,7 +632,9 @@
String hosttags;
public ItemHost(final String zn, final String zu, final String st, int cnt, final String tags) {
- super("cloudstack_hosts_total");
+ super("cloudstack_hosts_total",
+ "Total number of hosts",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
state = st;
@@ -610,6 +646,7 @@
public String toMetricsString() {
if (StringUtils.isNotEmpty(hosttags)) {
name = "cloudstack_hosts_total_by_tag";
+ help = "Total number of hosts grouped by tags";
return String.format("%s{zone=\"%s\",filter=\"%s\",tags=\"%s\"} %d", name, zoneName, state, hosttags, total);
}
return String.format("%s{zone=\"%s\",filter=\"%s\"} %d", name, zoneName, state, total);
@@ -628,7 +665,9 @@
String hosttags;
public ItemVMCore(final String zn, final String zu, final String hn, final String hu, final String hip, final String fl, final Long cr, final int dedicated, final String tags) {
- super("cloudstack_host_vms_cores_total");
+ super("cloudstack_host_vms_cores_total",
+ "Total number of VM cores on hosts",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
hostName = hn;
@@ -649,6 +688,7 @@
return String.format("%s{zone=\"%s\",filter=\"%s\"} %d", name, zoneName, filter, core);
} else {
name = "cloudstack_host_vms_cores_total_by_tag";
+ help = "Total number of VM cores grouped by host tags";
return String.format("%s{zone=\"%s\",filter=\"%s\",tags=\"%s\"} %d", name, zoneName, filter, hosttags, core);
}
}
@@ -657,13 +697,14 @@
}
class MissingHostInfo extends Item {
-
String zoneName;
String hostName;
MissingInfoFilter filter;
public MissingHostInfo(String zoneName, String hostname, MissingInfoFilter filter) {
- super("cloudstack_host_missing_info");
+ super("cloudstack_host_missing_info",
+ "Hosts with missing capacity or statistics information",
+ "gauge");
this.zoneName = zoneName;
this.hostName = hostname;
this.filter = filter;
@@ -688,7 +729,9 @@
String hosttags;
public ItemHostCpu(final String zn, final String zu, final String hn, final String hu, final String hip, final String of, final String fl, final double mh, final int dedicated, final String tags) {
- super("cloudstack_host_cpu_usage_mhz_total");
+ super("cloudstack_host_cpu_usage_mhz_total",
+ "Host CPU usage in MHz",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
hostName = hn;
@@ -708,6 +751,7 @@
return String.format("%s{zone=\"%s\",filter=\"%s\"} %.2f", name, zoneName, filter, mhertz);
} else {
name = "cloudstack_host_cpu_usage_mhz_total_by_tag";
+ help = "Host CPU usage in MHz grouped by host tags";
return String.format("%s{zone=\"%s\",filter=\"%s\",tags=\"%s\"} %.2f", name, zoneName, filter, hosttags, mhertz);
}
}
@@ -728,7 +772,9 @@
String hosttags;
public ItemHostMemory(final String zn, final String zu, final String hn, final String hu, final String hip, final String of, final String fl, final double membytes, final int dedicated, final String tags) {
- super("cloudstack_host_memory_usage_mibs_total");
+ super("cloudstack_host_memory_usage_mibs_total",
+ "Host memory usage in MiB",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
hostName = hn;
@@ -748,6 +794,7 @@
return String.format("%s{zone=\"%s\",filter=\"%s\"} %.2f", name, zoneName, filter, miBytes);
} else {
name = "cloudstack_host_memory_usage_mibs_total_by_tag";
+ help = "Host memory usage in MiB grouped by host tags";
return String.format("%s{zone=\"%s\",filter=\"%s\",tags=\"%s\"} %.2f", name, zoneName, filter, hosttags, miBytes);
}
}
@@ -764,7 +811,9 @@
int total;
public ItemHostVM(final String zoneName, final String zoneUuid, final String hostName, final String hostUuid, final String hostIp, final int total) {
- super("cloudstack_host_vms_total");
+ super("cloudstack_host_vms_total",
+ "Total number of VMs per host",
+ "gauge");
this.zoneName = zoneName;
this.zoneUuid = zoneUuid;
this.hostName = hostName;
@@ -790,7 +839,9 @@
double total;
public ItemPool(final String zn, final String zu, final String pn, final String pa, final String typ, final String of, final String fl, double cnt) {
- super("cloudstack_storage_pool_gibs_total");
+ super("cloudstack_storage_pool_gibs_total",
+ "Storage pool capacity in GiB",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
pname = pn;
@@ -817,7 +868,9 @@
int total;
public ItemPrivateIp(final String zn, final String zu, final String fl, int cnt) {
- super("cloudstack_private_ips_total");
+ super("cloudstack_private_ips_total",
+ "Total number of private IP addresses",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
filter = fl;
@@ -837,7 +890,9 @@
int total;
public ItemPublicIp(final String zn, final String zu, final String fl, int cnt) {
- super("cloudstack_public_ips_total");
+ super("cloudstack_public_ips_total",
+ "Total number of public IP addresses",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
filter = fl;
@@ -857,7 +912,9 @@
int total;
public ItemSharedNetworkIp(final String zn, final String zu, final String fl, int cnt) {
- super("cloudstack_shared_network_ips_total");
+ super("cloudstack_shared_network_ips_total",
+ "Total number of shared network IP addresses",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
filter = fl;
@@ -877,7 +934,9 @@
int total;
public ItemVlan(final String zn, final String zu, final String fl, int cnt) {
- super("cloudstack_vlans_total");
+ super("cloudstack_vlans_total",
+ "Total number of VLANs",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
filter = fl;
@@ -894,7 +953,9 @@
long cores;
public ItemDomainLimitCpu(final long c) {
- super("cloudstack_domain_limit_cpu_cores_total");
+ super("cloudstack_domain_limit_cpu_cores_total",
+ "Total CPU core limit across all domains",
+ "gauge");
cores = c;
}
@@ -908,7 +969,9 @@
long miBytes;
public ItemDomainLimitMemory(final long mb) {
- super("cloudstack_domain_limit_memory_mibs_total");
+ super("cloudstack_domain_limit_memory_mibs_total",
+ "Total memory limit in MiB across all domains",
+ "gauge");
miBytes = mb;
}
@@ -927,7 +990,9 @@
int isDedicated;
public ItemHostIsDedicated(final String zoneName, final String zoneUuid, final String hostName, final String hostUuid, final String hostIp, final int isDedicated) {
- super("cloudstack_host_is_dedicated");
+ super("cloudstack_host_is_dedicated",
+ "Whether a host is dedicated (1) or not (0)",
+ "gauge");
this.zoneName = zoneName;
this.zoneUuid = zoneUuid;
this.hostName = hostName;
@@ -949,7 +1014,9 @@
int total;
public ItemActiveDomains(final String zn, final String zu, final int cnt) {
- super("cloudstack_active_domains_total");
+ super("cloudstack_active_domains_total",
+ "Total number of active domains",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
total = cnt;
@@ -970,7 +1037,9 @@
public ItemHostDedicatedToAccount(final String zoneName, final String hostName,
final String accountName, final String domainName, int isDedicated) {
- super("cloudstack_host_dedicated_to_account");
+ super("cloudstack_host_dedicated_to_account",
+ "Host dedication to specific account",
+ "gauge");
this.zoneName = zoneName;
this.hostName = hostName;
this.accountName = accountName;
@@ -991,7 +1060,9 @@
String resourceType;
public ItemPerDomainResourceLimit(final long c, final String domainName, final String resourceType) {
- super("cloudstack_domain_resource_limit");
+ super("cloudstack_domain_resource_limit",
+ "Resource limits per domain",
+ "gauge");
this.cores = c;
this.domainName = domainName;
this.resourceType = resourceType;
@@ -1009,7 +1080,9 @@
String resourceType;
public ItemPerDomainResourceCount(final long mb, final String domainName, final String resourceType) {
- super("cloudstack_domain_resource_count");
+ super("cloudstack_domain_resource_count",
+ "Resource usage count per domain",
+ "gauge");
this.miBytes = mb;
this.domainName = domainName;
this.resourceType = resourceType;
@@ -1027,7 +1100,9 @@
int total;
public ItemActiveAccounts(final String zn, final String zu, final int cnt) {
- super("cloudstack_active_accounts_total");
+ super("cloudstack_active_accounts_total",
+ "Total number of active accounts",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
total = cnt;
@@ -1047,7 +1122,9 @@
int total;
public ItemVMsBySize(final String zn, final String zu, final int c, final int m, int cnt) {
- super("cloudstack_vms_total_by_size");
+ super("cloudstack_vms_total_by_size",
+ "Total number of VMs grouped by CPU and memory size",
+ "gauge");
zoneName = zn;
zoneUuid = zu;
cpu = c;
diff --git a/plugins/maintenance/pom.xml b/plugins/maintenance/pom.xml
index 5290b52..5b12986 100644
--- a/plugins/maintenance/pom.xml
+++ b/plugins/maintenance/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/maintenance/src/main/java/org/apache/cloudstack/api/command/ReadyForShutdownCmd.java b/plugins/maintenance/src/main/java/org/apache/cloudstack/api/command/ReadyForShutdownCmd.java
index 782b23a..36ec4ff 100644
--- a/plugins/maintenance/src/main/java/org/apache/cloudstack/api/command/ReadyForShutdownCmd.java
+++ b/plugins/maintenance/src/main/java/org/apache/cloudstack/api/command/ReadyForShutdownCmd.java
@@ -26,7 +26,8 @@
description = "Returns the status of CloudStack, whether a shutdown has been triggered and if ready to shutdown",
since = "4.19.0",
responseObject = ManagementServerMaintenanceResponse.class,
- requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ httpMethod = "GET")
public class ReadyForShutdownCmd extends BaseMSMaintenanceActionCmd {
public static final String APINAME = "readyForShutdown";
diff --git a/plugins/maintenance/src/test/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImplTest.java b/plugins/maintenance/src/test/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImplTest.java
index 280d1ea..a208893 100644
--- a/plugins/maintenance/src/test/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImplTest.java
+++ b/plugins/maintenance/src/test/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImplTest.java
@@ -321,7 +321,6 @@
spy.prepareForMaintenance("static", false);
});
- Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Maintenance);
Mockito.doNothing().when(jobManagerMock).enableAsyncJobs();
spy.cancelMaintenance();
Mockito.verify(jobManagerMock).enableAsyncJobs();
@@ -339,7 +338,6 @@
spy.prepareForMaintenance("static", false);
});
- Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.PreparingForMaintenance);
Mockito.doNothing().when(jobManagerMock).enableAsyncJobs();
spy.cancelMaintenance();
Mockito.verify(jobManagerMock).enableAsyncJobs();
diff --git a/plugins/metrics/pom.xml b/plugins/metrics/pom.xml
index 6cba7d8..7f8e56d 100644
--- a/plugins/metrics/pom.xml
+++ b/plugins/metrics/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/network-elements/bigswitch/pom.xml b/plugins/network-elements/bigswitch/pom.xml
index b1a163e..cd5ca8b 100644
--- a/plugins/network-elements/bigswitch/pom.xml
+++ b/plugins/network-elements/bigswitch/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/brocade-vcs/pom.xml b/plugins/network-elements/brocade-vcs/pom.xml
index e3d7a6c..1eb716a 100644
--- a/plugins/network-elements/brocade-vcs/pom.xml
+++ b/plugins/network-elements/brocade-vcs/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<build>
diff --git a/plugins/network-elements/cisco-vnmc/pom.xml b/plugins/network-elements/cisco-vnmc/pom.xml
index 56ff642..c183d03 100644
--- a/plugins/network-elements/cisco-vnmc/pom.xml
+++ b/plugins/network-elements/cisco-vnmc/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java b/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java
index 90597d7..e0ab727 100644
--- a/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java
+++ b/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java
@@ -136,7 +136,6 @@
String xml = "";
String line;
while ((line = br.readLine()) != null) {
- //xml += line.replaceAll("\n"," ");
xml += line;
}
diff --git a/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/element/CiscoVnmcElementService.java b/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/element/CiscoVnmcElementService.java
index 8388bb8..8a52893 100644
--- a/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/element/CiscoVnmcElementService.java
+++ b/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/element/CiscoVnmcElementService.java
@@ -28,8 +28,6 @@
public interface CiscoVnmcElementService extends PluggableService {
- //public static final Provider CiscoVnmc = new Provider("CiscoVnmc", true);
-
public CiscoVnmcController addCiscoVnmcResource(AddCiscoVnmcResourceCmd cmd);
public CiscoVnmcResourceResponse createCiscoVnmcResourceResponse(CiscoVnmcController ciscoVnmcResourceVO);
diff --git a/plugins/network-elements/dns-notifier/pom.xml b/plugins/network-elements/dns-notifier/pom.xml
index 7f87c49..b57bfb9 100644
--- a/plugins/network-elements/dns-notifier/pom.xml
+++ b/plugins/network-elements/dns-notifier/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-example-dns-notifier</artifactId>
diff --git a/plugins/network-elements/elastic-loadbalancer/pom.xml b/plugins/network-elements/elastic-loadbalancer/pom.xml
index 21ed6e3..22c61f7 100644
--- a/plugins/network-elements/elastic-loadbalancer/pom.xml
+++ b/plugins/network-elements/elastic-loadbalancer/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/ElasticLbVmMapVO.java b/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/ElasticLbVmMapVO.java
index b9bad7f..96a43df 100644
--- a/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/ElasticLbVmMapVO.java
+++ b/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/ElasticLbVmMapVO.java
@@ -79,10 +79,6 @@
return elbVmId;
}
-// public String getLbName() {
-// return lbName;
-// }
-
public long getIpAddressId() {
return ipAddressId;
}
diff --git a/plugins/network-elements/globodns/pom.xml b/plugins/network-elements/globodns/pom.xml
index a03bb1e..11e84d7 100644
--- a/plugins/network-elements/globodns/pom.xml
+++ b/plugins/network-elements/globodns/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
@@ -33,8 +33,8 @@
<artifactId>globodns-client</artifactId>
</dependency>
<dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
+ <groupId>com.mysql</groupId>
+ <artifactId>mysql-connector-j</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
diff --git a/plugins/network-elements/globodns/src/test/resources/log4j.properties b/plugins/network-elements/globodns/src/test/resources/log4j.properties
index 1bac606..8b1d961 100644
--- a/plugins/network-elements/globodns/src/test/resources/log4j.properties
+++ b/plugins/network-elements/globodns/src/test/resources/log4j.properties
@@ -1,17 +1,19 @@
-# 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
+# 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
+# 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.
+# 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.
# Define the root logger with appender file
#log = /var/log/log4j
diff --git a/plugins/network-elements/internal-loadbalancer/pom.xml b/plugins/network-elements/internal-loadbalancer/pom.xml
index beb5a54..2051a7c 100644
--- a/plugins/network-elements/internal-loadbalancer/pom.xml
+++ b/plugins/network-elements/internal-loadbalancer/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/juniper-contrail/pom.xml b/plugins/network-elements/juniper-contrail/pom.xml
index 0b3f8bf..6d76ced 100644
--- a/plugins/network-elements/juniper-contrail/pom.xml
+++ b/plugins/network-elements/juniper-contrail/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/api/command/CreateServiceInstanceCmd.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/api/command/CreateServiceInstanceCmd.java
index db98448..4c0f29c 100644
--- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/api/command/CreateServiceInstanceCmd.java
+++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/api/command/CreateServiceInstanceCmd.java
@@ -186,7 +186,7 @@
@Override
public long getEntityOwnerId() {
- Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
diff --git a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java
index 15f546d..2107850 100644
--- a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java
+++ b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java
@@ -32,6 +32,9 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
+
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd;
@@ -86,6 +89,7 @@
import com.cloud.vm.dao.UserVmDao;
public class ManagementServerMock {
+ protected Logger logger = LogManager.getLogger(getClass());
@Inject
private AccountManager _accountMgr;
@@ -217,15 +221,7 @@
return null;
}
};
- try {
- Mockito.when(_agentMgr.send(ArgumentMatchers.anyLong(), ArgumentMatchers.any(Commands.class))).thenAnswer(callback);
- } catch (AgentUnavailableException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (OperationTimedoutException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
+ sendCommands(callback);
long id = _userVmDao.getNextInSequence(Long.class, "id");
UserVmVO vm =
new UserVmVO(id, name, name, tmpl.getId(), HypervisorType.XenServer, tmpl.getGuestOSId(), false, false, _zone.getDomainId(), Account.ACCOUNT_ID_SYSTEM,
@@ -239,12 +235,21 @@
try {
_vmMgr.addVmToNetwork(vm, network, profile);
} catch (Exception ex) {
- // TODO Auto-generated catch block
- //ex.printStackTrace();
+ // ignored
}
return vm;
}
+ private void sendCommands(Answer<?> callback) {
+ try {
+ Mockito.when(_agentMgr.send(ArgumentMatchers.anyLong(), ArgumentMatchers.any(Commands.class))).thenAnswer(callback);
+ } catch (AgentUnavailableException e) {
+ logger.warn("no agent running", e);
+ } catch (OperationTimedoutException e) {
+ logger.warn("agent not responding (in time)", e);
+ }
+ }
+
private void deleteHost() {
_hostDao.remove(_hostId);
@@ -265,15 +270,7 @@
return null;
}
};
-
- try {
- Mockito.when(_agentMgr.send(ArgumentMatchers.anyLong(), ArgumentMatchers.any(Commands.class))).thenAnswer(callback);
- } catch (AgentUnavailableException e) {
- e.printStackTrace();
- } catch (OperationTimedoutException e) {
- e.printStackTrace();
- }
-
+ sendCommands(callback);
_userVmDao.remove(vm.getId());
}
diff --git a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java
index 2ff68b4..4dffb40 100644
--- a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java
+++ b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java
@@ -30,6 +30,7 @@
import org.apache.cloudstack.api.command.admin.user.MoveUserCmd;
import org.apache.cloudstack.api.response.UserTwoFactorAuthenticationSetupResponse;
import org.apache.cloudstack.auth.UserTwoFactorAuthenticator;
+import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.acl.ControlledEntity;
@@ -466,7 +467,7 @@
}
@Override
- public Long finalyzeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly) {
+ public Long finalizeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly) {
// TODO Auto-generated method stub
return null;
}
@@ -492,6 +493,11 @@
}
@Override
+ public void checkAccess(Account account, BackupOffering bof) throws PermissionDeniedException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public Pair<Boolean, Map<String, String>> getKeys(GetUserKeysCmd cmd){
return null;
}
diff --git a/plugins/network-elements/netris/pom.xml b/plugins/network-elements/netris/pom.xml
index 1a3fe5d..295fa64 100644
--- a/plugins/network-elements/netris/pom.xml
+++ b/plugins/network-elements/netris/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/network-elements/netscaler/pom.xml b/plugins/network-elements/netscaler/pom.xml
index ab51db5..88a8880 100644
--- a/plugins/network-elements/netscaler/pom.xml
+++ b/plugins/network-elements/netscaler/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/network-elements/nicira-nvp/pom.xml b/plugins/network-elements/nicira-nvp/pom.xml
index 40d4863..10a5843 100644
--- a/plugins/network-elements/nicira-nvp/pom.xml
+++ b/plugins/network-elements/nicira-nvp/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/network-elements/nsx/pom.xml b/plugins/network-elements/nsx/pom.xml
index 7dc31d6..9c0f680 100644
--- a/plugins/network-elements/nsx/pom.xml
+++ b/plugins/network-elements/nsx/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
@@ -59,7 +59,7 @@
<dependency>
<groupId>com.vmware.vapi</groupId>
<artifactId>vapi-runtime</artifactId>
- <version>2.40.0</version>
+ <version>2.61.2</version>
</dependency>
</dependencies>
</project>
diff --git a/plugins/network-elements/opendaylight/pom.xml b/plugins/network-elements/opendaylight/pom.xml
index a71b86d..38934e1 100644
--- a/plugins/network-elements/opendaylight/pom.xml
+++ b/plugins/network-elements/opendaylight/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<profiles>
diff --git a/plugins/network-elements/ovs/pom.xml b/plugins/network-elements/ovs/pom.xml
index 24f6225..ef1326c 100644
--- a/plugins/network-elements/ovs/pom.xml
+++ b/plugins/network-elements/ovs/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/palo-alto/pom.xml b/plugins/network-elements/palo-alto/pom.xml
index 3e821ec..ee16ecc 100644
--- a/plugins/network-elements/palo-alto/pom.xml
+++ b/plugins/network-elements/palo-alto/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/stratosphere-ssp/pom.xml b/plugins/network-elements/stratosphere-ssp/pom.xml
index 1703012..0288c8a 100644
--- a/plugins/network-elements/stratosphere-ssp/pom.xml
+++ b/plugins/network-elements/stratosphere-ssp/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/tungsten/pom.xml b/plugins/network-elements/tungsten/pom.xml
index 793d754..12214af 100644
--- a/plugins/network-elements/tungsten/pom.xml
+++ b/plugins/network-elements/tungsten/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
@@ -41,8 +41,8 @@
<artifactId>reload4j</artifactId>
</dependency>
<dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
+ <groupId>com.mysql</groupId>
+ <artifactId>mysql-connector-j</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java
index 58084d3..b22d1e7 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java
@@ -778,60 +778,6 @@
verify(tungstenService, times(1)).deleteManagementNetwork(anyLong());
}
- //@Test
- //public void processConnectWithoutSecurityGroupTest() throws ConnectionException {
- // Host host = mock(Host.class);
- // StartupCommand startupCommand = mock(StartupCommand.class);
- // TungstenProviderVO tungstenProvider = mock(TungstenProviderVO.class);
- // DataCenterVO dataCenterVO = mock(DataCenterVO.class);
- // VlanVO vlanVO1 = mock(VlanVO.class);
- // VlanVO vlanVO2 = mock(VlanVO.class);
- // List<VlanVO> vlanList = Arrays.asList(vlanVO1, vlanVO2);
- // Network publicNetwork = mock(Network.class);
- // NetworkDetailVO networkDetail = mock(NetworkDetailVO.class);
-//
- // when(host.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
- // when(tungstenProviderDao.findByZoneId(anyLong())).thenReturn(tungstenProvider);
- // when(host.getPublicIpAddress()).thenReturn("192.168.100.100");
- // when(tungstenProvider.getGateway()).thenReturn("192.168.100.100");
- // when(dataCenterDao.findById(anyLong())).thenReturn(dataCenterVO);
- // when(vlanDao.listByZone(anyLong())).thenReturn(vlanList);
- // when(networkModel.getSystemNetworkByZoneAndTrafficType(anyLong(), eq(Networks.TrafficType.Public))).thenReturn(publicNetwork);
- // when(networkDetailsDao.findDetail(anyLong(), anyString())).thenReturn(networkDetail);
- // when(vlanVO1.getVlanGateway()).thenReturn("192.168.100.1");
- // when(vlanVO1.getVlanNetmask()).thenReturn("255.255.255.0");
- // when(vlanVO2.getVlanGateway()).thenReturn("192.168.101.1");
- // when(vlanVO2.getVlanNetmask()).thenReturn("255.255.255.0");
- // when(dataCenterVO.isSecurityGroupEnabled()).thenReturn(false);
-//
- // tungstenElement.processConnect(host, startupCommand, true);
- // verify(agentManager, times(1)).easySend(anyLong(), any(SetupTungstenVRouterCommand.class));
- //}
-
- //@Test
- //public void processConnectWithSecurityGroupTest() throws ConnectionException {
- // Host host = mock(Host.class);
- // StartupCommand startupCommand = mock(StartupCommand.class);
- // TungstenProviderVO tungstenProvider = mock(TungstenProviderVO.class);
- // DataCenterVO dataCenterVO = mock(DataCenterVO.class);
- // NetworkVO network = mock(NetworkVO.class);
- // NetworkDetailVO networkDetail = mock(NetworkDetailVO.class);
- // Network publicNetwork = mock(Network.class);
-//
- // when(host.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
- // when(tungstenProviderDao.findByZoneId(anyLong())).thenReturn(tungstenProvider);
- // when(host.getPublicIpAddress()).thenReturn("192.168.100.100");
- // when(tungstenProvider.getGateway()).thenReturn("192.168.100.100");
- // when(dataCenterDao.findById(anyLong())).thenReturn(dataCenterVO);
- // when(networkDao.listByZoneSecurityGroup(anyLong())).thenReturn(Arrays.asList(network));
- // when(networkDetailsDao.findDetail(anyLong(), anyString())).thenReturn(networkDetail);
- // when(networkModel.getSystemNetworkByZoneAndTrafficType(anyLong(), eq(Networks.TrafficType.Public))).thenReturn(publicNetwork);
- // when(dataCenterVO.isSecurityGroupEnabled()).thenReturn(true);
-//
- // tungstenElement.processConnect(host, startupCommand, true);
- // verify(agentManager, times(1)).easySend(anyLong(), any(SetupTungstenVRouterCommand.class));
- //}
-
@Test
public void processHostAboutToBeRemovedWithSecurityGroupTest() {
HostVO hostVO = mock(HostVO.class);
diff --git a/plugins/network-elements/vxlan/pom.xml b/plugins/network-elements/vxlan/pom.xml
index 1192c98..e350a3c 100644
--- a/plugins/network-elements/vxlan/pom.xml
+++ b/plugins/network-elements/vxlan/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/outofbandmanagement-drivers/ipmitool/pom.xml b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml
index debeb7d..82ee440 100644
--- a/plugins/outofbandmanagement-drivers/ipmitool/pom.xml
+++ b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/outofbandmanagement-drivers/nested-cloudstack/pom.xml b/plugins/outofbandmanagement-drivers/nested-cloudstack/pom.xml
index 9c5e441..aefaf6d 100644
--- a/plugins/outofbandmanagement-drivers/nested-cloudstack/pom.xml
+++ b/plugins/outofbandmanagement-drivers/nested-cloudstack/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/outofbandmanagement-drivers/redfish/pom.xml b/plugins/outofbandmanagement-drivers/redfish/pom.xml
index 0d1b292..eecfe1a 100644
--- a/plugins/outofbandmanagement-drivers/redfish/pom.xml
+++ b/plugins/outofbandmanagement-drivers/redfish/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 16e5ed1..e7d1387 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<build>
<plugins>
diff --git a/plugins/storage-allocators/random/pom.xml b/plugins/storage-allocators/random/pom.xml
index b1a1c26..db55fab 100644
--- a/plugins/storage-allocators/random/pom.xml
+++ b/plugins/storage-allocators/random/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/image/default/pom.xml b/plugins/storage/image/default/pom.xml
index 1bac038..0696ca0 100644
--- a/plugins/storage/image/default/pom.xml
+++ b/plugins/storage/image/default/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/image/s3/pom.xml b/plugins/storage/image/s3/pom.xml
index 9c3ea94..607830b 100644
--- a/plugins/storage/image/s3/pom.xml
+++ b/plugins/storage/image/s3/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/image/sample/pom.xml b/plugins/storage/image/sample/pom.xml
index 586eb10..e704486 100644
--- a/plugins/storage/image/sample/pom.xml
+++ b/plugins/storage/image/sample/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/image/swift/pom.xml b/plugins/storage/image/swift/pom.xml
index 407106c..1caffda 100644
--- a/plugins/storage/image/swift/pom.xml
+++ b/plugins/storage/image/swift/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/object/ceph/pom.xml b/plugins/storage/object/ceph/pom.xml
index f6138ad..1f5a4bc 100644
--- a/plugins/storage/object/ceph/pom.xml
+++ b/plugins/storage/object/ceph/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/object/cloudian/pom.xml b/plugins/storage/object/cloudian/pom.xml
index 81c78a8..8184692 100644
--- a/plugins/storage/object/cloudian/pom.xml
+++ b/plugins/storage/object/cloudian/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/object/minio/pom.xml b/plugins/storage/object/minio/pom.xml
index 61b9838..d69c2a7 100644
--- a/plugins/storage/object/minio/pom.xml
+++ b/plugins/storage/object/minio/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/object/simulator/pom.xml b/plugins/storage/object/simulator/pom.xml
index 6efbd1c..dc4ab01 100644
--- a/plugins/storage/object/simulator/pom.xml
+++ b/plugins/storage/object/simulator/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/sharedfs/storagevm/pom.xml b/plugins/storage/sharedfs/storagevm/pom.xml
index 3459489..2a4ea74 100644
--- a/plugins/storage/sharedfs/storagevm/pom.xml
+++ b/plugins/storage/sharedfs/storagevm/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/storage/volume/adaptive/pom.xml b/plugins/storage/volume/adaptive/pom.xml
index e625cd6..337544b 100644
--- a/plugins/storage/volume/adaptive/pom.xml
+++ b/plugins/storage/volume/adaptive/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/cloudbyte/pom.xml b/plugins/storage/volume/cloudbyte/pom.xml
index 77dadb4..453a03e 100644
--- a/plugins/storage/volume/cloudbyte/pom.xml
+++ b/plugins/storage/volume/cloudbyte/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java b/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java
index 9f7a695..9dc0229 100644
--- a/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java
+++ b/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java
@@ -175,9 +175,6 @@
_volumeDao.update(volume.getId(), volume);
- // create new volume details for the volume
- //updateVolumeDetails(volume, esvolume);
-
long capacityBytes = storagePool.getCapacityBytes();
long usedBytes = storagePool.getUsedBytes();
diff --git a/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/util/ElastistorUtil.java b/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/util/ElastistorUtil.java
index 6650dad..603908e 100644
--- a/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/util/ElastistorUtil.java
+++ b/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/util/ElastistorUtil.java
@@ -341,7 +341,6 @@
String qosgroupid;
String VolumeName = volumeName;
String totaliops = String.valueOf(capacityIops);
- //String totalthroughput = String.valueOf(capacityIops * 4);
String totalthroughput = "0";
String quotasize = convertCapacityBytes(capacityBytes);
@@ -679,14 +678,6 @@
}
LOGGER.info("tsm id is null");
return false;
-
- /*
- * else { LOGGER.error("no volume is present in the tsm"); } } else {
- * LOGGER.error(
- * "List tsm failed, no tsm present in the eastistor for the given IP "
- * ); return false; } return false;
- */
-
}
public static boolean deleteElastistorVolume(String esvolumeid) throws Throwable {
diff --git a/plugins/storage/volume/datera/pom.xml b/plugins/storage/volume/datera/pom.xml
index 84a5e4c..6c4b580 100644
--- a/plugins/storage/volume/datera/pom.xml
+++ b/plugins/storage/volume/datera/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/default/pom.xml b/plugins/storage/volume/default/pom.xml
index 02e2fb8..03d26fb 100644
--- a/plugins/storage/volume/default/pom.xml
+++ b/plugins/storage/volume/default/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/flasharray/pom.xml b/plugins/storage/volume/flasharray/pom.xml
index a6da4cf..5adad7a 100644
--- a/plugins/storage/volume/flasharray/pom.xml
+++ b/plugins/storage/volume/flasharray/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/linstor/pom.xml b/plugins/storage/volume/linstor/pom.xml
index ee72aab..0b78f0e 100644
--- a/plugins/storage/volume/linstor/pom.xml
+++ b/plugins/storage/volume/linstor/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/linstor/src/test/java/org/apache/cloudstack/storage/datastore/util/LinstorUtilTest.java b/plugins/storage/volume/linstor/src/test/java/org/apache/cloudstack/storage/datastore/util/LinstorUtilTest.java
index 55f0c6e..39d9a25 100644
--- a/plugins/storage/volume/linstor/src/test/java/org/apache/cloudstack/storage/datastore/util/LinstorUtilTest.java
+++ b/plugins/storage/volume/linstor/src/test/java/org/apache/cloudstack/storage/datastore/util/LinstorUtilTest.java
@@ -82,7 +82,6 @@
mockStoragePool("thinpool", "nodeC", ProviderKind.LVM_THIN)
));
-// when(LinstorUtil.getLinstorAPI(LINSTOR_URL_TEST)).thenReturn(api);
}
@Test
diff --git a/plugins/storage/volume/nexenta/pom.xml b/plugins/storage/volume/nexenta/pom.xml
index d9ed6fd..d1de59b 100644
--- a/plugins/storage/volume/nexenta/pom.xml
+++ b/plugins/storage/volume/nexenta/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/nexenta/src/main/java/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java b/plugins/storage/volume/nexenta/src/main/java/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java
index 60f3bd2..dad4819 100644
--- a/plugins/storage/volume/nexenta/src/main/java/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java
+++ b/plugins/storage/volume/nexenta/src/main/java/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java
@@ -187,9 +187,6 @@
NexentaStorAppliance appliance = getNexentaStorAppliance(storagePoolId);
StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
-
-
-// _storagePoolDao.update(stoagePoolId);
} else {
errorMessage = String.format(
"Invalid DataObjectType(%s) passed to deleteAsync",
diff --git a/plugins/storage/volume/nexenta/src/test/java/org/apache/cloudstack/storage/datastore/util/NexentaStorApplianceTest.java b/plugins/storage/volume/nexenta/src/test/java/org/apache/cloudstack/storage/datastore/util/NexentaStorApplianceTest.java
index 89b5ece..d283e4c 100644
--- a/plugins/storage/volume/nexenta/src/test/java/org/apache/cloudstack/storage/datastore/util/NexentaStorApplianceTest.java
+++ b/plugins/storage/volume/nexenta/src/test/java/org/apache/cloudstack/storage/datastore/util/NexentaStorApplianceTest.java
@@ -60,7 +60,6 @@
public void init() {
final String url = "nmsUrl=https://admin:nexenta@10.1.3.182:8457;volume=cloudstack;storageType=iscsi";
NexentaUtil.NexentaPluginParameters parameters = NexentaUtil.parseNexentaPluginUrl(url);
- //client = new NexentaNmsClient(parameters.getNmsUrl());
client = mock(NexentaNmsClient.class);
appliance = new NexentaStorAppliance(client, parameters);
}
diff --git a/plugins/storage/volume/primera/pom.xml b/plugins/storage/volume/primera/pom.xml
index 4f1583a..ac4351b 100644
--- a/plugins/storage/volume/primera/pom.xml
+++ b/plugins/storage/volume/primera/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/sample/pom.xml b/plugins/storage/volume/sample/pom.xml
index 0a9de06..425303a 100644
--- a/plugins/storage/volume/sample/pom.xml
+++ b/plugins/storage/volume/sample/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/scaleio/pom.xml b/plugins/storage/volume/scaleio/pom.xml
index 79a707b..b166404 100644
--- a/plugins/storage/volume/scaleio/pom.xml
+++ b/plugins/storage/volume/scaleio/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/api/VTreeMigrationInfo.java b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/api/VTreeMigrationInfo.java
index f4e926b..072b52b 100644
--- a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/api/VTreeMigrationInfo.java
+++ b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/api/VTreeMigrationInfo.java
@@ -59,7 +59,7 @@
}
public void setMigrationStatus(String migrationStatus) {
- this.migrationStatus = EnumUtils.fromString(MigrationStatus.class, migrationStatus, MigrationStatus.None);
+ this.migrationStatus = EnumUtils.getEnumIgnoreCase(MigrationStatus.class, migrationStatus, MigrationStatus.None);
}
public void setMigrationStatus(MigrationStatus migrationStatus) {
diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml
index 65a91af..65ba90b 100644
--- a/plugins/storage/volume/solidfire/pom.xml
+++ b/plugins/storage/volume/solidfire/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/solidfire/src/test/java/org/apache/cloudstack/storage/test/VolumeTest.java b/plugins/storage/volume/solidfire/src/test/java/org/apache/cloudstack/storage/test/VolumeTest.java
index 08f95b1..d721412 100644
--- a/plugins/storage/volume/solidfire/src/test/java/org/apache/cloudstack/storage/test/VolumeTest.java
+++ b/plugins/storage/volume/solidfire/src/test/java/org/apache/cloudstack/storage/test/VolumeTest.java
@@ -64,8 +64,6 @@
DataCenterDao dcDao;
@Inject
PrimaryDataStoreDao primaryStoreDao;
- // @Inject
- // PrimaryDataStoreProviderManager primaryDataStoreProviderMgr;
@Inject
AgentManager agentMgr;
Long dcId;
@@ -109,25 +107,15 @@
results.add(host);
Mockito.when(hostDao.listAll()).thenReturn(results);
Mockito.when(hostDao.findHypervisorHostInCluster(ArgumentMatchers.anyLong())).thenReturn(results);
- // CreateObjectAnswer createVolumeFromImageAnswer = new
- // CreateObjectAnswer(null,UUID.randomUUID().toString(), null);
-
- // Mockito.when(primaryStoreDao.findById(Mockito.anyLong())).thenReturn(primaryStore);
}
private PrimaryDataStoreInfo createPrimaryDataStore() {
try {
- // primaryDataStoreProviderMgr.configure("primary data store mgr",
- // new HashMap<String, Object>());
- // PrimaryDataStoreProvider provider =
- // primaryDataStoreProviderMgr.getDataStoreProvider("Solidfre Primary Data Store Provider");
Map<String, String> params = new HashMap<String, String>();
params.put("url", "nfs://test/test");
params.put("dcId", dcId.toString());
params.put("clusterId", clusterId.toString());
params.put("name", "my primary data store");
- // PrimaryDataStoreInfo primaryDataStoreInfo =
- // provider.registerDataStore(params);
return null;
} catch (Exception e) {
return null;
diff --git a/plugins/storage/volume/storpool/pom.xml b/plugins/storage/volume/storpool/pom.xml
index 0829575..7bdc76d 100644
--- a/plugins/storage/volume/storpool/pom.xml
+++ b/plugins/storage/volume/storpool/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/StorPoolDownloadVolumeCommandWrapper.java b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/StorPoolDownloadVolumeCommandWrapper.java
index 1679e64..de8b948 100644
--- a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/StorPoolDownloadVolumeCommandWrapper.java
+++ b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/StorPoolDownloadVolumeCommandWrapper.java
@@ -29,7 +29,6 @@
import org.apache.cloudstack.utils.qemu.QemuImg;
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
import org.apache.cloudstack.utils.qemu.QemuImgFile;
-//import java.io.File;
import com.cloud.agent.api.storage.StorPoolDownloadVolumeCommand;
import com.cloud.agent.api.to.DataStoreTO;
diff --git a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java
index 84abb1e..7bfa633 100644
--- a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java
+++ b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/collector/StorPoolAbandonObjectsCollector.java
@@ -23,7 +23,6 @@
import com.cloud.storage.dao.SnapshotDetailsDao;
import com.cloud.storage.dao.SnapshotDetailsVO;
-
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.DB;
diff --git a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java
index f0398e9..f666711 100644
--- a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java
+++ b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java
@@ -934,7 +934,6 @@
if (resp.getError() != null) {
err = String.format("Could not create Storpool volume for CS template %s. Error: %s", name, resp.getError());
} else {
- //updateVolume(dstData.getId());
VolumeObjectTO dstTO = (VolumeObjectTO)dstData.getTO();
dstTO.setPath(StorPoolUtil.devPath(StorPoolUtil.getNameFromResponse(resp, false)));
dstTO.setSize(size);
diff --git a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java
index 055853a..388211e 100644
--- a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java
+++ b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolHelper.java
@@ -178,32 +178,6 @@
return tags;
}
- // Initialize custom logger for updated volume and snapshots
-// public static void appendLogger(Logger log, String filePath, String kindOfLog) {
-// Appender appender = null;
-// PatternLayout patternLayout = new PatternLayout();
-// patternLayout.setConversionPattern("%d{YYYY-MM-dd HH:mm:ss.SSS} %m%n");
-// SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
-// Timestamp timestamp = new Timestamp(System.currentTimeMillis());
-// String path = filePath + "-" + sdf.format(timestamp) + ".log";
-// try {
-// appender = new RollingFileAppender(patternLayout, path);
-// log.setAdditivity(false);
-// log.addAppender(appender);
-// } catch (IOException e) {
-// e.printStackTrace();
-// }
-// if (kindOfLog.equals("update")) {
-// StorPoolUtil.spLog(
-// "You can find information about volumes and snapshots, which will be updated in Database with their globalIs in %s log file",
-// path);
-// } else if (kindOfLog.equals("abandon")) {
-// StorPoolUtil.spLog(
-// "You can find information about volumes and snapshots, for which CloudStack doesn't have information in %s log file",
-// path);
-// }
-// }
-
public static void setSpClusterIdIfNeeded(long hostId, String clusterId, ClusterDao clusterDao, HostDao hostDao,
ClusterDetailsDao clusterDetails) {
HostVO host = hostDao.findById(hostId);
diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml
index 7f58d8f..c9e5a08 100644
--- a/plugins/user-authenticators/ldap/pom.xml
+++ b/plugins/user-authenticators/ldap/pom.xml
@@ -24,12 +24,12 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
- <ads.version>2.0.0.AM25</ads.version>
+ <ads.version>2.0.0.AM27</ads.version>
<ldap-maven.version>1.3.2</ldap-maven.version>
<ldapunit.version>1.1.3</ldapunit.version>
<groovy.version>1.1-groovy-2.4</groovy.version>
@@ -215,5 +215,11 @@
<artifactId>commons-io</artifactId>
<version>${cs.commons-io.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-api</artifactId>
+ <version>${project.version}</version>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java
index ae86d1c..0f6e43c 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java
@@ -46,7 +46,7 @@
@Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, required = true, description = "Port")
private int port;
- @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "Linked domain")
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Linked Domain")
private Long domainId;
public LdapAddConfigurationCmd() {
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java
index 55ae853..a33b4e9 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java
@@ -21,6 +21,7 @@
import com.cloud.user.AccountService;
import com.cloud.user.User;
import com.cloud.user.UserAccount;
+import com.cloud.utils.StringUtils;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
@@ -39,7 +40,6 @@
import org.bouncycastle.util.encoders.Base64;
import javax.inject.Inject;
-import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Map;
@@ -107,7 +107,7 @@
if (accountType == null) {
return RoleType.getAccountTypeByRole(roleService.findRole(roleId), null);
}
- return RoleType.getAccountTypeByRole(roleService.findRole(roleId), Account.Type.getFromValue(accountType.intValue()));
+ return RoleType.getAccountTypeByRole(roleService.findRole(roleId), Account.Type.getFromValue(accountType));
}
public Long getRoleId() {
@@ -158,10 +158,10 @@
private String generatePassword() throws ServerApiException {
try {
final SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG");
- final byte bytes[] = new byte[20];
+ final byte[] bytes = new byte[20];
randomGen.nextBytes(bytes);
- return new String(Base64.encode(bytes), "UTF-8");
- } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
+ return new String(Base64.encode(bytes), StringUtils.getPreferredCharset());
+ } catch (NoSuchAlgorithmException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate random password");
}
}
@@ -180,7 +180,7 @@
return Account.ACCOUNT_ID_SYSTEM;
}
- private boolean validateUser(final LdapUser user) throws ServerApiException {
+ private void validateUser(final LdapUser user) throws ServerApiException {
if (user.getEmail() == null) {
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, username + " has no email address set within LDAP");
}
@@ -190,6 +190,5 @@
if (user.getLastname() == null) {
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, username + " has no lastname set within LDAP");
}
- return true;
}
}
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java
index 86d34c6..d2d4e5a 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java
@@ -46,10 +46,10 @@
@Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, description = "Hostname")
private String hostname;
- @Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, required = false, description = "Port")
+ @Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, description = "Port")
private int port;
- @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "Linked domain")
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Linked Domain")
private Long domainId;
public LdapDeleteConfigurationCmd() {
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapImportUsersCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
index a3445d6..d6df27c 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
@@ -16,7 +16,6 @@
// under the License.
package org.apache.cloudstack.api.command;
-import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
@@ -41,7 +40,6 @@
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
-import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.encoders.Base64;
import com.cloud.domain.Domain;
@@ -56,6 +54,7 @@
import com.cloud.user.DomainService;
import com.cloud.user.User;
import com.cloud.user.UserAccount;
+import com.cloud.utils.StringUtils;
@APICommand(name = "importLdapUsers", description = "Import LDAP users", responseObject = LdapUserResponse.class, since = "4.3.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class LdapImportUsersCmd extends BaseListCmd {
@@ -106,14 +105,14 @@
private void createCloudstackUserAccount(LdapUser user, String accountName, Domain domain) {
Account account = _accountService.getActiveAccountByName(accountName, domain.getId());
if (account == null) {
- logger.debug("No account exists with name: " + accountName + " creating the account and an user with name: " + user.getUsername() + " in the account");
+ logger.debug("No account exists with name: {}. Creating the account and a user with name: {} in the account", accountName, user.getUsername());
_accountService.createUserAccount(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, getAccountType(), getRoleId(),
domain.getId(), domain.getNetworkDomain(), details, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP);
} else {
// check if the user exists. if yes, call update
UserAccount csuser = _accountService.getActiveUserAccount(user.getUsername(), domain.getId());
if (csuser == null) {
- logger.debug("No user exists with name: " + user.getUsername() + " creating a user in the account: " + accountName);
+ logger.debug("No user exists with name: {}. Creating a user in the account: {}", user.getUsername(), accountName);
_accountService.createUser(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, domain.getId(),
UUID.randomUUID().toString(), User.Source.LDAP);
} else {
@@ -145,21 +144,21 @@
users = _ldapManager.getUsers(domainId);
}
} catch (NoLdapUserMatchingQueryException ex) {
- users = new ArrayList<LdapUser>();
- logger.info("No Ldap user matching query. " + " ::: " + ex.getMessage());
+ users = new ArrayList<>();
+ logger.info("No Ldap user matching query. ::: {}", ex.getMessage());
}
- List<LdapUser> addedUsers = new ArrayList<LdapUser>();
+ List<LdapUser> addedUsers = new ArrayList<>();
for (LdapUser user : users) {
Domain domain = getDomain(user);
try {
createCloudstackUserAccount(user, getAccountName(user), domain);
addedUsers.add(user);
} catch (InvalidParameterValueException ex) {
- logger.error("Failed to create user with username: " + user.getUsername() + " ::: " + ex.getMessage());
+ logger.error("Failed to create user with username: {} ::: {}", user.getUsername(), ex.getMessage());
}
}
- ListResponse<LdapUserResponse> response = new ListResponse<LdapUserResponse>();
+ ListResponse<LdapUserResponse> response = new ListResponse<>();
response.setResponses(createLdapUserResponse(addedUsers));
response.setResponseName(getCommandName());
setResponseObject(response);
@@ -169,7 +168,7 @@
if (accountType == null) {
return RoleType.getAccountTypeByRole(roleService.findRole(roleId), null);
}
- return RoleType.getAccountTypeByRole(roleService.findRole(roleId), Account.Type.getFromValue(accountType.intValue()));
+ return RoleType.getAccountTypeByRole(roleService.findRole(roleId), Account.Type.getFromValue(accountType));
}
public Long getRoleId() {
@@ -202,11 +201,11 @@
private Domain getDomain(LdapUser user) {
Domain domain;
if (_domain != null) {
- //this means either domain id or groupname is passed and this will be same for all the users in this call. hence returning it.
+ // This means that either a domain id or group name is passed and this will be same for all the users in this call, hence returning it.
domain = _domain;
} else {
if (domainId != null) {
- // a domain Id is passed. use it for this user and all the users in the same api call (by setting _domain)
+ // a domain ID is passed. Use it for this user and all the users in the same API call (by setting _domain)
domain = _domain = _domainService.getDomain(domainId);
} else {
// a group name is passed. use it for this user and all the users in the same api call(by setting _domain)
@@ -225,7 +224,7 @@
}
private List<LdapUserResponse> createLdapUserResponse(List<LdapUser> users) {
- final List<LdapUserResponse> ldapResponses = new ArrayList<LdapUserResponse>();
+ final List<LdapUserResponse> ldapResponses = new ArrayList<>();
for (final LdapUser user : users) {
final LdapUserResponse ldapResponse = _ldapManager.createLdapUserResponse(user);
ldapResponse.setObjectName("LdapUser");
@@ -242,10 +241,10 @@
private String generatePassword() throws ServerApiException {
try {
final SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG");
- final byte bytes[] = new byte[20];
+ final byte[] bytes = new byte[20];
randomGen.nextBytes(bytes);
- return new String(Base64.encode(bytes), "UTF-8");
- } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
+ return new String(Base64.encode(bytes), StringUtils.getPreferredCharset());
+ } catch (NoSuchAlgorithmException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate random password");
}
}
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java
index edcf18b..2904a72 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java
@@ -44,20 +44,22 @@
@Inject
private LdapManager _ldapManager;
- @Parameter(name = ApiConstants. HOST_NAME, type = CommandType.STRING, required = false, description = "Hostname")
+ @Parameter(name = ApiConstants. HOST_NAME, type = CommandType.STRING, description = "Hostname")
private String hostname;
- @Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, required = false, description = "Port")
+ @Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, description = "Port")
private int port;
- @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "Linked domain")
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class,
+ description = "Linked Domain")
private Long domainId;
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = LdapConfigurationResponse.class, description = "list ldap configuration by ID; when passed, all other parameters are ignored")
private Long id;
- @Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN, description = "If set to true, "
- + " and no domainid specified, list all LDAP configurations irrespective of the linked domain", since = "4.13.2")
+ @Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN,
+ description = "If set to true, and no `domainid` specified, list all LDAP configurations irrespective of the linked domain",
+ since = "4.13.2")
private Boolean listAll;
public LdapListConfigurationCmd() {
@@ -70,7 +72,7 @@
}
private List<LdapConfigurationResponse> createLdapConfigurationResponses(final List<? extends LdapConfigurationVO> configurations) {
- final List<LdapConfigurationResponse> responses = new ArrayList<LdapConfigurationResponse>();
+ final List<LdapConfigurationResponse> responses = new ArrayList<>();
for (final LdapConfigurationVO resource : configurations) {
final LdapConfigurationResponse configurationResponse = _ldapManager.createLdapConfigurationResponse(resource);
configurationResponse.setObjectName("LdapConfiguration");
@@ -83,7 +85,7 @@
public void execute() {
final Pair<List<? extends LdapConfigurationVO>, Integer> result = _ldapManager.listConfigurations(this);
final List<LdapConfigurationResponse> responses = createLdapConfigurationResponses(result.first());
- final ListResponse<LdapConfigurationResponse> response = new ListResponse<LdapConfigurationResponse>();
+ final ListResponse<LdapConfigurationResponse> response = new ListResponse<>();
response.setResponses(responses, result.second());
response.setResponseName(getCommandName());
setResponseObject(response);
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapListUsersCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapListUsersCmd.java
index 91eff07..c5f6b6f 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapListUsersCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapListUsersCmd.java
@@ -16,10 +16,9 @@
// under the License.
package org.apache.cloudstack.api.command;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import javax.inject.Inject;
@@ -44,9 +43,10 @@
import org.apache.cloudstack.query.QueryService;
import com.cloud.user.Account;
+import org.apache.commons.collections.CollectionUtils;
/**
- * a short flow, use plantuml to view (see http://plantuml.com)
+ * a short flow, use plantuml to view (see <a href="http://plantuml.com">the plantuml site</a>)
* @startuml
* start
* :list ldap users request;
@@ -84,14 +84,12 @@
@Parameter(name = "listtype",
type = CommandType.STRING,
- required = false,
description = "Determines whether all ldap users are returned or just non-cloudstack users. This option is deprecated in favour for the more option rich 'userfilter' parameter")
@Deprecated
private String listType;
@Parameter(name = ApiConstants.USER_FILTER,
type = CommandType.STRING,
- required = false,
since = "4.13",
description = "Determines what type of filter is applied on the list of users returned from LDAP.\n"
+ "\tvalid values are\n"
@@ -102,7 +100,7 @@
+ " including those that are already in cloudstack, the later will be annotated with their userSource")
private String userFilter;
- @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "Linked domain")
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Linked Domain")
private Long domainId;
public LdapListUsersCmd() {
@@ -121,7 +119,7 @@
* @return a (filtered?) list of user response objects
*/
private List<LdapUserResponse> createLdapUserResponse(final List<LdapUser> users) {
- final List<LdapUserResponse> ldapResponses = new ArrayList<LdapUserResponse>();
+ final List<LdapUserResponse> ldapResponses = new ArrayList<>();
for (final LdapUser user : users) {
final LdapUserResponse ldapResponse = _ldapManager.createLdapUserResponse(user);
ldapResponse.setObjectName("LdapUser");
@@ -135,8 +133,8 @@
@Override
public void execute() throws ServerApiException {
cloudstackUsers = null;
- List<LdapUserResponse> ldapResponses = new ArrayList<LdapUserResponse>();
- final ListResponse<LdapUserResponse> response = new ListResponse<LdapUserResponse>();
+ List<LdapUserResponse> ldapResponses = new ArrayList<>();
+ final ListResponse<LdapUserResponse> response = new ListResponse<>();
try {
final List<LdapUser> users = _ldapManager.getUsers(domainId);
ldapResponses = createLdapUserResponse(users);
@@ -177,16 +175,13 @@
users.append(user.getUsername());
}
- logger.trace(String.format("checking against %d cloudstackusers: %s.", this.cloudstackUsers.size(), users.toString()));
+ logger.trace("checking against {} cloudstackusers: {}.", this.cloudstackUsers.size(), users);
}
}
private List<LdapUserResponse> applyUserFilter(List<LdapUserResponse> ldapResponses) {
- if(logger.isTraceEnabled()) {
- logger.trace(String.format("applying filter: %s or %s.", this.getListTypeString(), this.getUserFilter()));
- }
- List<LdapUserResponse> responseList = getUserFilter().filter(this,ldapResponses);
- return responseList;
+ logger.trace("applying filter: {} or {}.", this.getListTypeString(), this.getUserFilter());
+ return getUserFilter().filter(this,ldapResponses);
}
@Override
@@ -211,48 +206,34 @@
return UserFilter.fromString(getUserFilterString());
}
- boolean isACloudstackUser(final LdapUser ldapUser) {
+ boolean isACloudStackUser(final LdapUser ldapUser) {
+ String username = ldapUser.getUsername();
+ return isACloudStackUser(username);
+ }
+
+ boolean isACloudStackUser(final LdapUserResponse ldapUser) {
+ logger.trace("checking response : {}", ldapUser.toString());
+ String username = ldapUser.getUsername();
+ return isACloudStackUser(username);
+ }
+
+ private boolean isACloudStackUser(String username) {
boolean rc = false;
final List<UserResponse> cloudstackUsers = getCloudstackUsers();
- if (cloudstackUsers != null) {
+ if (CollectionUtils.isNotEmpty(cloudstackUsers)) {
for (final UserResponse cloudstackUser : cloudstackUsers) {
- if (ldapUser.getUsername().equals(cloudstackUser.getUsername())) {
- if(logger.isTraceEnabled()) {
- logger.trace(String.format("found user %s in cloudstack", ldapUser.getUsername()));
- }
-
+ if (username.equals(cloudstackUser.getUsername())) {
+ logger.trace("Found user {} in CloudStack", cloudstackUser.getUsername());
rc = true;
+ break;
} else {
- if(logger.isTraceEnabled()) {
- logger.trace(String.format("ldap user %s does not match cloudstack user %s", ldapUser.getUsername(), cloudstackUser.getUsername()));
- }
+ logger.trace("ldap user {} does not match cloudstack user {}", username, cloudstackUser.getUsername());
}
}
}
return rc;
}
- boolean isACloudstackUser(final LdapUserResponse ldapUser) {
- if(logger.isTraceEnabled()) {
- logger.trace("checking response : " + ldapUser.toString());
- }
- final List<UserResponse> cloudstackUsers = getCloudstackUsers();
- if (cloudstackUsers != null && cloudstackUsers.size() != 0) {
- for (final UserResponse cloudstackUser : cloudstackUsers) {
- if (ldapUser.getUsername().equals(cloudstackUser.getUsername())) {
- if(logger.isTraceEnabled()) {
- logger.trace(String.format("found user %s in cloudstack user %s", ldapUser.getUsername(), cloudstackUser.getUsername()));
- }
- return true;
- } else {
- if(logger.isTraceEnabled()) {
- logger.trace(String.format("ldap user %s does not match cloudstack user %s", ldapUser.getUsername(), cloudstackUser.getUsername()));
- }
- }
- }
- }
- return false;
- }
/**
* typecheck for userfilter values and filter type dependend functionalities.
* This could have been in two switch statements elsewhere in the code.
@@ -363,7 +344,7 @@
if(logger.isTraceEnabled()) {
logger.trace("filtering existing users");
}
- final List<LdapUserResponse> ldapResponses = new ArrayList<LdapUserResponse>();
+ final List<LdapUserResponse> ldapResponses = new ArrayList<>();
for (final LdapUserResponse user : input) {
if (isNotAlreadyImportedInTheCurrentDomain(user)) {
ldapResponses.add(user);
@@ -396,7 +377,7 @@
if(logger.isTraceEnabled()) {
logger.trace("filtering local domain users");
}
- final List<LdapUserResponse> ldapResponses = new ArrayList<LdapUserResponse>();
+ final List<LdapUserResponse> ldapResponses = new ArrayList<>();
String domainId = getCurrentDomainId();
for (final LdapUserResponse user : input) {
UserResponse cloudstackUser = getCloudstackUser(user);
@@ -412,7 +393,7 @@
}
private String getCurrentDomainId() {
- String domainId = null;
+ String domainId;
if (this.domainId != null) {
Domain domain = _domainService.getDomain(this.domainId);
domainId = domain.getUuid();
@@ -433,10 +414,10 @@
logger.trace("should be filtering potential imports!!!");
}
// functional possibility do not add only users not yet in cloudstack but include users that would be moved if they are so in ldap?
- // this means if they are part of a account linked to an ldap group/ou
+ // This means if they are part of an Account linked to an LDAP Group/OU
input.removeIf(ldapUser ->
(
- (isACloudstackUser(ldapUser))
+ (isACloudStackUser(ldapUser))
&& (getCloudstackUser(ldapUser).getUserSource().equalsIgnoreCase(User.Source.LDAP.toString()))
)
);
@@ -466,7 +447,7 @@
for (final UserResponse cloudstackUser : cloudstackUsers) {
if (user.getUsername().equals(cloudstackUser.getUsername())) {
returnObject = cloudstackUser;
- if (returnObject.getDomainId() == this.getCurrentDomainId()) {
+ if (Objects.equals(returnObject.getDomainId(), this.getCurrentDomainId())) {
break;
}
}
@@ -474,31 +455,4 @@
}
return returnObject;
}
-
- private void checkFilterMethodType(Type returnType) {
- String msg = null;
- if (returnType instanceof ParameterizedType) {
- ParameterizedType type = (ParameterizedType) returnType;
- if(type.getRawType().equals(List.class)) {
- Type[] typeArguments = type.getActualTypeArguments();
- if (typeArguments.length == 1) {
- if (typeArguments[0].equals(LdapUserResponse.class)) {
- // we're good'
- } else {
- msg = new String("list of return type contains " + typeArguments[0].getTypeName());
- }
- } else {
- msg = String.format("type %s has to the wrong number of arguments", type.getRawType());
- }
- } else {
- msg = String.format("type %s is not a List<>", type.getTypeName());
- }
- } else {
- msg = new String("can't even begin to explain; review your method signature");
- }
- if(msg != null) {
- throw new IllegalArgumentException(msg);
- }
- }
-
}
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapUserSearchCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapUserSearchCmd.java
index 51fc72f..42fbca1 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapUserSearchCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapUserSearchCmd.java
@@ -54,7 +54,7 @@
}
private List<LdapUserResponse> createLdapUserResponse(final List<LdapUser> users) {
- final List<LdapUserResponse> ldapUserResponses = new ArrayList<LdapUserResponse>();
+ final List<LdapUserResponse> ldapUserResponses = new ArrayList<>();
if (users != null) {
for (final LdapUser user : users) {
final LdapUserResponse ldapUserResponse = _ldapManager.createLdapUserResponse(user);
@@ -67,7 +67,7 @@
@Override
public void execute() {
- final ListResponse<LdapUserResponse> response = new ListResponse<LdapUserResponse>();
+ final ListResponse<LdapUserResponse> response = new ListResponse<>();
List<LdapUser> users = null;
try {
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmd.java
index b33c323..d3ab463 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmd.java
@@ -50,7 +50,7 @@
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "The id of the domain that is to contain the linked account.")
private Long domainId;
- @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = false, description = "Type of the ldap name. GROUP or OU, defaults to GROUP")
+ @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "Type of the LDAP name. GROUP or OU, defaults to GROUP")
private String type;
@Parameter(name = ApiConstants.LDAP_DOMAIN, type = CommandType.STRING, required = true, description = "Name of the group or OU in LDAP")
@@ -59,14 +59,14 @@
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "Name of the account, it will be created if it does not exist")
private String accountName;
- @Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, required = false, description = "Domain admin username in LDAP ")
+ @Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, description = "Domain admin username in LDAP ")
private String admin;
- @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.INTEGER, required = false, description = "Type of the account to auto import. Specify 0 for user and 2 for "
+ @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.INTEGER, description = "Type of the account to auto import. Specify 0 for user and 2 for "
+ "domain admin")
private Integer accountType;
- @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, required = false, description = "Creates the account under the specified role.", since="4.19.1")
+ @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.", since="4.19.1")
private Long roleId;
@Inject
@@ -81,7 +81,7 @@
try {
ldapUser = _ldapManager.getUser(admin, type, ldapDomain, domainId);
} catch (NoLdapUserMatchingQueryException e) {
- logger.debug("no ldap user matching username " + admin + " in the given group/ou", e);
+ logger.debug("no ldap user matching username {} in the given group/ou", admin, e);
}
if (ldapUser != null && !ldapUser.isDisabled()) {
Account account = _accountService.getActiveAccountByName(admin, domainId);
@@ -99,7 +99,7 @@
logger.debug("an account with name {} already exists in the domain {} with id {}", admin, _domainService.getDomain(domainId), domainId);
}
} else {
- logger.debug("ldap user with username " + admin + " is disabled in the given group/ou");
+ logger.debug("ldap user with username {} is disabled in the given group/ou", admin);
}
}
response.setObjectName(this.getActualCommandName());
@@ -139,7 +139,7 @@
if (accountType == null) {
return RoleType.getAccountTypeByRole(roleService.findRole(roleId), null);
}
- return RoleType.getAccountTypeByRole(roleService.findRole(roleId), Account.Type.getFromValue(accountType.intValue()));
+ return RoleType.getAccountTypeByRole(roleService.findRole(roleId), Account.Type.getFromValue(accountType));
}
public Long getRoleId() {
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java
index 854fbdd..7b1613e 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java
@@ -51,14 +51,10 @@
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "Type of the ldap name. GROUP or OU")
private String type;
- @Parameter(name = ApiConstants.LDAP_DOMAIN, type = CommandType.STRING, required = false, description = "Name of the group or OU in LDAP")
+ @Parameter(name = ApiConstants.LDAP_DOMAIN, type = CommandType.STRING, required = true, description = "Name of the GROUP or OU in LDAP")
private String ldapDomain;
- @Deprecated
- @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = false, description = "Name of the group or OU in LDAP")
- private String name;
-
- @Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, required = false, description = "Domain admin username in LDAP ")
+ @Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, description = "Domain admin username in LDAP ")
private String admin;
@Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.INTEGER, required = true, description = "Type of the account to auto import. Specify 0 for user and 2 for " +
@@ -77,7 +73,7 @@
}
public String getLdapDomain() {
- return ldapDomain == null ? name : ldapDomain;
+ return ldapDomain;
}
public String getAdmin() {
@@ -98,7 +94,7 @@
try {
ldapUser = _ldapManager.getUser(admin, type, getLdapDomain(), domainId);
} catch (NoLdapUserMatchingQueryException e) {
- logger.debug("no ldap user matching username " + admin + " in the given group/ou", e);
+ logger.debug("no ldap user matching username {} in the given group/ou", admin, e);
}
if (ldapUser != null && !ldapUser.isDisabled()) {
Account account = _accountService.getActiveAccountByName(admin, domainId);
@@ -115,7 +111,7 @@
logger.debug("an account with name {} already exists in the domain {} with id {}", admin, _domainService.getDomain(domainId), domainId);
}
} else {
- logger.debug("ldap user with username "+admin+" is disabled in the given group/ou");
+ logger.debug("ldap user with username {} is disabled in the given Group/OU", admin);
}
}
response.setObjectName("LinkDomainToLdap");
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/UnlinkDomainFromLdapCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/UnlinkDomainFromLdapCmd.java
new file mode 100644
index 0000000..08f5e99
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/UnlinkDomainFromLdapCmd.java
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+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 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.SuccessResponse;
+import org.apache.cloudstack.api.response.DomainResponse;
+import org.apache.cloudstack.ldap.LdapManager;
+
+import javax.inject.Inject;
+
+@APICommand(name = "unlinkDomainFromLdap", description = "remove the linkage of a Domain to a group or OU in ldap",
+ responseObject = SuccessResponse.class, since = "4.23.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class UnlinkDomainFromLdapCmd extends BaseCmd {
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class,
+ description = "The ID of the Domain which has to be unlinked from LDAP.")
+ private Long domainId;
+
+ @Inject
+ private LdapManager _ldapManager;
+
+ public Long getDomainId() {
+ return domainId;
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+ boolean rc = _ldapManager.unlinkDomainFromLdap(this);
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ response.setSuccess(rc);
+ if (rc) {
+ response.setDisplayText("Domain unlinked from LDAP successfully");
+ } else {
+ response.setDisplayText("Failed to unlink domain from LDAP");
+ }
+ setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+}
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/response/LinkAccountToLdapResponse.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/response/LinkAccountToLdapResponse.java
index b1f566a..2059c9e 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/response/LinkAccountToLdapResponse.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/response/LinkAccountToLdapResponse.java
@@ -82,4 +82,8 @@
public void setAdminId(String adminId) {
this.adminId = adminId;
}
+
+ public String getAccountName() {
+ return accountName;
+ }
}
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java
index bf5d503..3f8aa6a 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java
@@ -39,7 +39,7 @@
throw new IllegalArgumentException("ldap group name cannot be blank");
}
- String basedn = _ldapConfiguration.getBaseDn(domainId);
+ String basedn = LdapConfiguration.getBaseDn(domainId);
if (StringUtils.isBlank(basedn)) {
throw new IllegalArgumentException("ldap basedn is not configured");
}
@@ -62,7 +62,7 @@
final StringBuilder userObjectFilter = getUserObjectFilter(domainId);
final StringBuilder memberOfFilter = new StringBuilder();
- String groupCnName = _ldapConfiguration.getCommonNameAttribute() + "=" +groupName + "," + _ldapConfiguration.getBaseDn(domainId);
+ String groupCnName = LdapConfiguration.getCommonNameAttribute() + "=" +groupName + "," + LdapConfiguration.getBaseDn(domainId);
memberOfFilter.append("(").append(getMemberOfAttribute(domainId)).append("=");
memberOfFilter.append(groupCnName);
memberOfFilter.append(")");
@@ -100,7 +100,7 @@
protected String getMemberOfAttribute(final Long domainId) {
String rc;
- if(_ldapConfiguration.isNestedGroupsEnabled(domainId)) {
+ if(LdapConfiguration.isNestedGroupsEnabled(domainId)) {
rc = MICROSOFT_AD_NESTED_MEMBERS_FILTER;
} else {
rc = MICROSOFT_AD_MEMBERS_FILTER;
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapAuthenticator.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapAuthenticator.java
index 36c6635..09519c5 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapAuthenticator.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapAuthenticator.java
@@ -25,6 +25,7 @@
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.auth.UserAuthenticator;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import com.cloud.user.Account;
@@ -59,10 +60,10 @@
@Override
public Pair<Boolean, ActionOnFailedAuthentication> authenticate(final String username, final String password, final Long domainId, final Map<String, Object[]> requestParameters) {
- Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
+ Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<>(false, null);
if (logger.isDebugEnabled()) {
- logger.debug("Retrieving ldap user: " + username);
+ logger.debug("Retrieving ldap user: {}", username);
}
// TODO not allowing an empty password is a policy we shouldn't decide on. A private cloud may well want to allow this.
@@ -76,7 +77,7 @@
return rc;
}
List<LdapTrustMapVO> ldapTrustMapVOs = getLdapTrustMapVOS(domainId);
- if (ldapTrustMapVOs != null && ldapTrustMapVOs.size() > 0) {
+ if (CollectionUtils.isNotEmpty(ldapTrustMapVOs)) {
if (ldapTrustMapVOs.size() == 1 && ldapTrustMapVOs.get(0).getAccountId() == 0) {
if (logger.isTraceEnabled()) {
logger.trace("We have a single mapping of a domain to an ldap group or ou");
@@ -90,7 +91,7 @@
}
} else {
if (logger.isTraceEnabled()) {
- logger.trace(String.format("'this' domain (%d) is not linked to ldap follow normal authentication", domainId));
+ logger.trace("'this' domain ({}) is not linked to LDAP follow normal authentication", domainId);
}
rc = authenticate(username, password, domainId, user);
}
@@ -114,10 +115,10 @@
* @param domainId domain the user is trying to log on to
* @param userAccount cloudstack user object
* @param ldapTrustMapVOs the trust mappings of accounts in the domain to ldap groups
- * @return false if the ldap user object does not exist, is not mapped to an account, is mapped to multiple accounts or if authenitication fails
+ * @return {false,<error-code>} if the ldap user object does not exist, is not mapped to an account, is mapped to multiple accounts or if authentication fails
*/
Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount userAccount, List<LdapTrustMapVO> ldapTrustMapVOs) {
- Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
+ Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<>(false, null);
try {
LdapUser ldapUser = _ldapManager.getUser(username, domainId);
List<String> memberships = ldapUser.getMemberships();
@@ -131,7 +132,7 @@
logAndDisable(userAccount, "attempt to log on using disabled ldap user " + userAccount.getUsername(), false);
} else if (mappedGroups.size() > 1) {
logAndDisable(userAccount, "user '" + username + "' is mapped to more then one account in domain and will be disabled.", false);
- } else if (mappedGroups.size() < 1) {
+ } else if (mappedGroups.isEmpty()) {
logAndDisable(userAccount, "user '" + username + "' is not mapped to an account in domain and will be removed.", true);
} else {
// a valid ldap configured user exists
@@ -230,10 +231,10 @@
* @param domainId domain the user is trying to log on to
* @param user cloudstack user object
* @param ldapTrustMapVO the trust mapping for the domain to the ldap group
- * @return false if the ldap user object does not exist or authenitication fails
+ * @return {false, <error-code>} if the ldap user object does not exist or authentication fails
*/
private Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount user, LdapTrustMapVO ldapTrustMapVO) {
- Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
+ Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<>(false, null);
try {
LdapUser ldapUser = _ldapManager.getUser(username, ldapTrustMapVO.getType().toString(), ldapTrustMapVO.getName(), domainId);
final Account.Type accountType = ldapTrustMapVO.getAccountType();
@@ -270,7 +271,7 @@
* @param password pass phrase
* @param domainId domain the user is trying to log on to
* @param user cloudstack user object
- * @return false if either user object does not exist or authenitication fails
+ * @return {false,<error-code>} if either user object does not exist or authentication fails
*/
Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount user) {
boolean result = false;
@@ -282,7 +283,7 @@
if (!ldapUser.isDisabled()) {
result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId);
} else {
- logger.debug("user with principal "+ ldapUser.getPrincipal() + " is disabled in ldap");
+ logger.debug("user with principal {} is disabled in ldap", () -> ldapUser.getPrincipal());
}
} catch (NoLdapUserMatchingQueryException e) {
logger.debug(e.getMessage());
@@ -296,8 +297,8 @@
private Pair<Boolean, ActionOnFailedAuthentication> processResultAndAction(UserAccount user, boolean result, boolean timedOut) {
return (!result && (user != null || timedOut)) ?
- new Pair<Boolean, ActionOnFailedAuthentication>(result, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT):
- new Pair<Boolean, ActionOnFailedAuthentication>(result, null);
+ new Pair<>(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT):
+ new Pair<>(result, null);
}
private void enableUserInCloudStack(UserAccount user) {
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapConfiguration.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapConfiguration.java
index 87ff2d0..114ca16 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapConfiguration.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapConfiguration.java
@@ -23,7 +23,6 @@
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
-import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import com.cloud.utils.Pair;
import org.apache.cloudstack.ldap.dao.LdapConfigurationDao;
@@ -34,7 +33,7 @@
private final static String factory = "com.sun.jndi.ldap.LdapCtxFactory";
protected Logger logger = LogManager.getLogger(getClass());
- private static final ConfigKey<Long> ldapReadTimeout = new ConfigKey<Long>(
+ private static final ConfigKey<Long> ldapReadTimeout = new ConfigKey<>(
Long.class,
"ldap.read.timeout",
"Advanced",
@@ -42,9 +41,9 @@
"LDAP connection Timeout in milli sec",
true,
ConfigKey.Scope.Domain,
- 1l);
+ 1L);
- private static final ConfigKey<Integer> ldapPageSize = new ConfigKey<Integer>(
+ private static final ConfigKey<Integer> ldapPageSize = new ConfigKey<>(
Integer.class,
"ldap.request.page.size",
"Advanced",
@@ -54,7 +53,7 @@
ConfigKey.Scope.Domain,
1);
- private static final ConfigKey<Boolean> ldapEnableNestedGroups = new ConfigKey<Boolean>(
+ private static final ConfigKey<Boolean> ldapEnableNestedGroups = new ConfigKey<>(
"Advanced",
Boolean.class,
"ldap.nested.groups.enable",
@@ -63,7 +62,7 @@
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapMemberOfAttribute = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapMemberOfAttribute = new ConfigKey<>(
"Advanced",
String.class,
"ldap.user.memberof.attribute",
@@ -72,7 +71,7 @@
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapProvider = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapProvider = new ConfigKey<>(
"Advanced",
String.class,
"ldap.provider",
@@ -81,7 +80,7 @@
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapBaseDn = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapBaseDn = new ConfigKey<>(
"Advanced",
String.class,
"ldap.basedn",
@@ -90,7 +89,7 @@
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapBindPassword = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapBindPassword = new ConfigKey<>(
"Secure",
String.class,
"ldap.bind.password",
@@ -98,7 +97,7 @@
"Sets the bind password for LDAP",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapBindPrincipal = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapBindPrincipal = new ConfigKey<>(
"Secure",
String.class,
"ldap.bind.principal",
@@ -106,7 +105,7 @@
"Sets the bind principal for LDAP",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapEmailAttribute = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapEmailAttribute = new ConfigKey<>(
"Advanced",
String.class,
"ldap.email.attribute",
@@ -114,7 +113,7 @@
"Sets the email attribute used within LDAP",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapFirstnameAttribute = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapFirstnameAttribute = new ConfigKey<>(
"Advanced",
String.class,
"ldap.firstname.attribute",
@@ -122,14 +121,14 @@
"Sets the firstname attribute used within LDAP",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapLastnameAttribute = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapLastnameAttribute = new ConfigKey<>(
"Advanced",
String.class, "ldap.lastname.attribute",
"sn",
"Sets the lastname attribute used within LDAP",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapUsernameAttribute = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapUsernameAttribute = new ConfigKey<>(
"Advanced",
String.class,
"ldap.username.attribute",
@@ -137,7 +136,7 @@
"Sets the username attribute used within LDAP",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapUserObject = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapUserObject = new ConfigKey<>(
"Advanced",
String.class,
"ldap.user.object",
@@ -145,7 +144,7 @@
"Sets the object type of users within LDAP",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapSearchGroupPrinciple = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapSearchGroupPrinciple = new ConfigKey<>(
"Advanced",
String.class,
"ldap.search.group.principle",
@@ -153,7 +152,7 @@
"Sets the principle of the group that users must be a member of",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapGroupObject = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapGroupObject = new ConfigKey<>(
"Advanced",
String.class,
"ldap.group.object",
@@ -161,7 +160,7 @@
"Sets the object type of groups within LDAP",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapGroupUniqueMemberAttribute = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapGroupUniqueMemberAttribute = new ConfigKey<>(
"Advanced",
String.class,
"ldap.group.user.uniquemember",
@@ -170,7 +169,7 @@
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapTrustStore = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapTrustStore = new ConfigKey<>(
"Advanced",
String.class,
"ldap.truststore",
@@ -178,7 +177,7 @@
"Sets the path to the truststore to use for SSL",
true,
ConfigKey.Scope.Domain);
- private static final ConfigKey<String> ldapTrustStorePassword = new ConfigKey<String>(
+ private static final ConfigKey<String> ldapTrustStorePassword = new ConfigKey<>(
"Secure",
String.class,
"ldap.truststore.password",
@@ -199,11 +198,6 @@
_ldapConfigurationDao = ldapConfigurationDao;
}
- @Deprecated
- public LdapConfiguration(final ConfigurationDao configDao, final LdapConfigurationDao ldapConfigurationDao) {
- _ldapConfigurationDao = ldapConfigurationDao;
- }
-
public String getAuthentication(final Long domainId) {
if ((getBindPrincipal(domainId) == null) && (getBindPassword(domainId) == null)) {
return "none";
@@ -212,36 +206,36 @@
}
}
- public String getBaseDn(final Long domainId) {
+ public static String getBaseDn(final Long domainId) {
return ldapBaseDn.valueIn(domainId);
}
- public String getBindPassword(final Long domainId) {
+ public static String getBindPassword(final Long domainId) {
return ldapBindPassword.valueIn(domainId);
}
- public String getBindPrincipal(final Long domainId) {
+ public static String getBindPrincipal(final Long domainId) {
return ldapBindPrincipal.valueIn(domainId);
}
- public String getEmailAttribute(final Long domainId) {
+ public static String getEmailAttribute(final Long domainId) {
return ldapEmailAttribute.valueIn(domainId);
}
- public String getFactory() {
+ public static String getFactory() {
return factory;
}
- public String getFirstnameAttribute(final Long domainId) {
+ public static String getFirstnameAttribute(final Long domainId) {
return ldapFirstnameAttribute.valueIn(domainId);
}
- public String getLastnameAttribute(final Long domainId) {
+ public static String getLastnameAttribute(final Long domainId) {
return ldapLastnameAttribute.valueIn(domainId);
}
public String getProviderUrl(final Long domainId) {
- final String protocol = getSSLStatus(domainId) == true ? "ldaps://" : "ldap://";
+ final String protocol = getSSLStatus(domainId) ? "ldaps://" : "ldap://";
final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(null, 0, domainId);
final StringBuilder providerUrls = new StringBuilder();
String delim = "";
@@ -273,40 +267,36 @@
return ldapSearchGroupPrinciple.valueIn(domainId);
}
- public boolean getSSLStatus(Long domainId) {
- boolean sslStatus = false;
- if (getTrustStore(domainId) != null && getTrustStorePassword(domainId) != null) {
- sslStatus = true;
- }
- return sslStatus;
+ public static boolean getSSLStatus(Long domainId) {
+ return getTrustStore(domainId) != null && getTrustStorePassword(domainId) != null;
}
- public String getTrustStore(Long domainId) {
+ public static String getTrustStore(Long domainId) {
return ldapTrustStore.valueIn(domainId);
}
- public String getTrustStorePassword(Long domainId) {
+ public static String getTrustStorePassword(Long domainId) {
return ldapTrustStorePassword.valueIn(domainId);
}
- public String getUsernameAttribute(final Long domainId) {
+ public static String getUsernameAttribute(final Long domainId) {
return ldapUsernameAttribute.valueIn(domainId);
}
- public String getUserObject(final Long domainId) {
+ public static String getUserObject(final Long domainId) {
return ldapUserObject.valueIn(domainId);
}
- public String getGroupObject(final Long domainId) {
+ public static String getGroupObject(final Long domainId) {
return ldapGroupObject.valueIn(domainId);
}
- public String getGroupUniqueMemberAttribute(final Long domainId) {
+ public static String getGroupUniqueMemberAttribute(final Long domainId) {
return ldapGroupUniqueMemberAttribute.valueIn(domainId);
}
// TODO remove hard-coding
- public String getCommonNameAttribute() {
+ public static String getCommonNameAttribute() {
return "cn";
}
@@ -315,11 +305,11 @@
return "userAccountControl";
}
- public Long getReadTimeout(final Long domainId) {
+ public static Long getReadTimeout(final Long domainId) {
return ldapReadTimeout.valueIn(domainId);
}
- public Integer getLdapPageSize(final Long domainId) {
+ public static Integer getLdapPageSize(final Long domainId) {
return ldapPageSize.valueIn(domainId);
}
@@ -334,7 +324,7 @@
return provider;
}
- public boolean isNestedGroupsEnabled(final Long domainId) {
+ public static boolean isNestedGroupsEnabled(final Long domainId) {
return ldapEnableNestedGroups.valueIn(domainId);
}
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapContextFactory.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapContextFactory.java
index 1c759c6..34ebc7a 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapContextFactory.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapContextFactory.java
@@ -49,8 +49,8 @@
}
public LdapContext createBindContext(final String providerUrl, Long domainId) throws NamingException, IOException {
- final String bindPrincipal = _ldapConfiguration.getBindPrincipal(domainId);
- final String bindPassword = _ldapConfiguration.getBindPassword(domainId);
+ final String bindPrincipal = LdapConfiguration.getBindPrincipal(domainId);
+ final String bindPassword = LdapConfiguration.getBindPassword(domainId);
return createInitialDirContext(bindPrincipal, bindPassword, providerUrl, true, domainId);
}
@@ -70,13 +70,13 @@
}
private void enableSSL(final Hashtable<String, String> environment, Long domainId) {
- final boolean sslStatus = _ldapConfiguration.getSSLStatus(domainId);
+ final boolean sslStatus = LdapConfiguration.getSSLStatus(domainId);
if (sslStatus) {
logger.info("LDAP SSL enabled.");
environment.put(Context.SECURITY_PROTOCOL, "ssl");
- String trustStore = _ldapConfiguration.getTrustStore(domainId);
- String trustStorePassword = _ldapConfiguration.getTrustStorePassword(domainId);
+ String trustStore = LdapConfiguration.getTrustStore(domainId);
+ String trustStorePassword = LdapConfiguration.getTrustStorePassword(domainId);
if (!validateTrustStore(trustStore, trustStorePassword)) {
throw new RuntimeException("Invalid truststore or truststore password");
@@ -109,7 +109,7 @@
}
private Hashtable<String, String> getEnvironment(final String principal, final String password, final String providerUrl, final boolean isSystemContext, Long domainId) {
- final String factory = _ldapConfiguration.getFactory();
+ final String factory = LdapConfiguration.getFactory();
String url = providerUrl == null ? _ldapConfiguration.getProviderUrl(domainId) : providerUrl;
if (StringUtils.isEmpty(url) && domainId != null) {
//try a default ldap implementation
@@ -120,7 +120,7 @@
environment.put(Context.INITIAL_CONTEXT_FACTORY, factory);
environment.put(Context.PROVIDER_URL, url);
- environment.put("com.sun.jndi.ldap.read.timeout", _ldapConfiguration.getReadTimeout(domainId).toString());
+ environment.put("com.sun.jndi.ldap.read.timeout", LdapConfiguration.getReadTimeout(domainId).toString());
environment.put("com.sun.jndi.ldap.connect.pool", "true");
enableSSL(environment, domainId);
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapManager.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapManager.java
index ded6e94..7e561cc 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapManager.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapManager.java
@@ -23,6 +23,7 @@
import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
import org.apache.cloudstack.api.command.LinkAccountToLdapCmd;
import org.apache.cloudstack.api.command.LinkDomainToLdapCmd;
+import org.apache.cloudstack.api.command.UnlinkDomainFromLdapCmd;
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.api.response.LdapUserResponse;
@@ -34,7 +35,7 @@
public interface LdapManager extends PluggableService {
- enum LinkType { GROUP, OU;}
+ enum LinkType { GROUP, OU }
LdapConfigurationResponse addConfiguration(final LdapAddConfigurationCmd cmd) throws InvalidParameterValueException;
@@ -69,12 +70,12 @@
LinkDomainToLdapResponse linkDomainToLdap(LinkDomainToLdapCmd cmd);
+ boolean unlinkDomainFromLdap(UnlinkDomainFromLdapCmd cmd);
+
LdapTrustMapVO getDomainLinkedToLdap(long domainId);
List<LdapTrustMapVO> getDomainLinkage(long domainId);
- LdapTrustMapVO getAccountLinkedToLdap(long domainId, long accountId);
-
LdapTrustMapVO getLinkedLdapGroup(long domainId, String group);
LinkAccountToLdapResponse linkAccountToLdap(LinkAccountToLdapCmd linkAccountToLdapCmd);
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapManagerImpl.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapManagerImpl.java
index abf47d4..8327072 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapManagerImpl.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapManagerImpl.java
@@ -43,16 +43,17 @@
import org.apache.cloudstack.api.command.LdapUserSearchCmd;
import org.apache.cloudstack.api.command.LinkAccountToLdapCmd;
import org.apache.cloudstack.api.command.LinkDomainToLdapCmd;
+import org.apache.cloudstack.api.command.UnlinkDomainFromLdapCmd;
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.api.response.LdapUserResponse;
import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
import org.apache.cloudstack.framework.messagebus.MessageBus;
-import org.apache.cloudstack.framework.messagebus.MessageSubscriber;
import org.apache.cloudstack.ldap.dao.LdapConfigurationDao;
import org.apache.cloudstack.ldap.dao.LdapTrustMapDao;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import com.cloud.domain.DomainVO;
@@ -114,36 +115,30 @@
}
private void addAccountRemovalListener() {
- messageBus.subscribe(AccountManager.MESSAGE_REMOVE_ACCOUNT_EVENT, new MessageSubscriber() {
- @Override
- public void onPublishMessage(String senderAddress, String subject, Object args) {
- try {
- final Account account = accountDao.findByIdIncludingRemoved((Long) args);
- long domainId = account.getDomainId();
- LdapTrustMapVO ldapTrustMapVO = _ldapTrustMapDao.findByAccount(domainId, account.getAccountId());
- if (ldapTrustMapVO != null) {
- removeTrustmap(ldapTrustMapVO);
- }
- } catch (final Exception e) {
- logger.error("Caught exception while removing account linked to LDAP", e);
+ messageBus.subscribe(AccountManager.MESSAGE_REMOVE_ACCOUNT_EVENT, (senderAddress, subject, args) -> {
+ try {
+ final Account account = accountDao.findByIdIncludingRemoved((Long) args);
+ long domainId = account.getDomainId();
+ LdapTrustMapVO ldapTrustMapVO = _ldapTrustMapDao.findByAccount(domainId, account.getAccountId());
+ if (ldapTrustMapVO != null) {
+ removeTrustmap(ldapTrustMapVO);
}
+ } catch (final Exception e) {
+ logger.error("Caught exception while removing account linked to LDAP", e);
}
});
}
private void addDomainRemovalListener() {
- messageBus.subscribe(DomainManager.MESSAGE_REMOVE_DOMAIN_EVENT, new MessageSubscriber() {
- @Override
- public void onPublishMessage(String senderAddress, String subject, Object args) {
- try {
- long domainId = ((DomainVO) args).getId();
- List<LdapTrustMapVO> ldapTrustMapVOs = _ldapTrustMapDao.searchByDomainId(domainId);
- for (LdapTrustMapVO ldapTrustMapVO : ldapTrustMapVOs) {
- removeTrustmap(ldapTrustMapVO);
- }
- } catch (final Exception e) {
- logger.error("Caught exception while removing trust-map for domain linked to LDAP", e);
+ messageBus.subscribe(DomainManager.MESSAGE_REMOVE_DOMAIN_EVENT, (senderAddress, subject, args) -> {
+ try {
+ long domainId = ((DomainVO) args).getId();
+ List<LdapTrustMapVO> ldapTrustMapVOs = _ldapTrustMapDao.searchByDomainId(domainId);
+ for (LdapTrustMapVO ldapTrustMapVO : ldapTrustMapVOs) {
+ removeTrustmap(ldapTrustMapVO);
}
+ } catch (final Exception e) {
+ logger.error("Caught exception while removing trust-map for domain linked to LDAP", e);
}
});
}
@@ -180,7 +175,7 @@
context = _ldapContextFactory.createBindContext(providerUrl,domainId);
configuration = new LdapConfigurationVO(hostname, port, domainId);
_ldapConfigurationDao.persist(configuration);
- logger.info("Added new ldap server with url: " + providerUrl + (domainId == null ? "": " for domain " + domainId));
+ logger.info("Added a new LDAP server with URL: {}{}", providerUrl, domainId == null ? "" : " for domain " + domainId);
return createLdapConfigurationResponse(configuration);
} catch (NamingException | IOException e) {
logger.debug("NamingException while doing an LDAP bind", e);
@@ -200,10 +195,10 @@
/**
* TODO decide if the principal is good enough to get the domain id or we need to add it as parameter
- * @param principal
- * @param password
- * @param domainId
- * @return
+ * @param principal ldap user
+ * @param password the users password to check
+ * @param domainId the domain for logging into
+ * @return true if the user can authenticate
*/
@Override
public boolean canAuthenticate(final String principal, final String password, final Long domainId) {
@@ -211,13 +206,11 @@
// TODO return the right account for this user
final LdapContext context = _ldapContextFactory.createUserContext(principal, password, domainId);
closeContext(context);
- if (logger.isTraceEnabled()) {
- logger.trace(String.format("User(%s) authenticated for domain(%s)", principal, domainId));
- }
+ logger.trace("User({}) authenticated for domain({})", principal, domainId);
return true;
} catch (NamingException | IOException e) {/* AuthenticationException is caught as NamingException */
- logger.debug("Exception while doing an LDAP bind for user "+" "+principal, e);
- logger.info("Failed to authenticate user: " + principal + ". incorrect password.");
+ logger.debug("Exception while doing an LDAP bind for user {}", principal, e);
+ logger.info("Failed to authenticate user: {}. Incorrect password.", principal);
return false;
}
}
@@ -285,14 +278,14 @@
throw new InvalidParameterValueException("Cannot find configuration with hostname " + hostname);
} else {
_ldapConfigurationDao.remove(configuration.getId());
- logger.info("Removed ldap server with url: " + hostname + ':' + port + (domainId == null ? "" : " for domain id " + domainId));
+ logger.info("Removed ldap server with url: {}:{}{}", hostname, port, domainId == null ? "" : " for domain id " + domainId);
return createLdapConfigurationResponse(configuration);
}
}
@Override
public List<Class<?>> getCommands() {
- final List<Class<?>> cmdList = new ArrayList<Class<?>>();
+ final List<Class<?>> cmdList = new ArrayList<>();
cmdList.add(LdapUserSearchCmd.class);
cmdList.add(LdapListUsersCmd.class);
cmdList.add(LdapAddConfigurationCmd.class);
@@ -304,6 +297,7 @@
cmdList.add(LDAPRemoveCmd.class);
cmdList.add(LinkDomainToLdapCmd.class);
cmdList.add(LinkAccountToLdapCmd.class);
+ cmdList.add(UnlinkDomainFromLdapCmd.class);
return cmdList;
}
@@ -393,7 +387,7 @@
final boolean listAll = cmd.listAll();
final Long id = cmd.getId();
final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(id, hostname, port, domainId, listAll);
- return new Pair<List<? extends LdapConfigurationVO>, Integer>(result.first(), result.second());
+ return new Pair<>(result.first(), result.second());
}
@Override
@@ -415,7 +409,7 @@
@Override
public LinkDomainToLdapResponse linkDomainToLdap(LinkDomainToLdapCmd cmd) {
final Long domainId = cmd.getDomainId();
- final String baseDn = _ldapConfiguration.getBaseDn(domainId);
+ final String baseDn = LdapConfiguration.getBaseDn(domainId);
final String ldapDomain = cmd.getLdapDomain();
Validate.isTrue(baseDn != null, String.format("can not link a domain (with id = %d) unless a basedn (%s) is configured for it.", domainId, baseDn));
@@ -423,6 +417,11 @@
return linkDomainToLdap(cmd.getDomainId(),cmd.getType(), ldapDomain,cmd.getAccountType());
}
+ @Override
+ public boolean unlinkDomainFromLdap(UnlinkDomainFromLdapCmd cmd) {
+ return unlinkDomainFromLdap(cmd.getDomainId());
+ }
+
private LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, Account.Type accountType) {
Validate.notNull(type, "type cannot be null. It should either be GROUP or OU");
Validate.notNull(domainId, "domainId cannot be null.");
@@ -430,16 +429,51 @@
//Account type should be 0 or 2. check the constants in com.cloud.user.Account
Validate.isTrue(accountType== Account.Type.NORMAL || accountType== Account.Type.DOMAIN_ADMIN, "accountype should be either 0(normal user) or 2(domain admin)");
LinkType linkType = LdapManager.LinkType.valueOf(type.toUpperCase());
- LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(domainId, linkType, name, accountType, 0));
- DomainVO domain = domainDao.findById(vo.getDomainId());
- String domainUuid = "<unknown>";
+ return linkDomainToLdapAndGetResponse(domainId, name, accountType, linkType);
+ }
+
+ @NotNull
+ private LinkDomainToLdapResponse linkDomainToLdapAndGetResponse(Long domainId, String name, Account.Type accountType, LinkType linkType) {
+ DomainVO domain = getDomainToLink(domainId);
+ LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(domain.getId(), linkType, name, accountType, 0));
+ String domainUuid = domain.getUuid();
+ return new LinkDomainToLdapResponse(domainUuid, vo.getType().toString(), vo.getName(), vo.getAccountType().ordinal());
+ }
+
+ @NotNull
+ private DomainVO getDomainToLink(Long domainId) {
+ DomainVO domain = domainDao.findById(domainId);
if (domain == null) {
- logger.error("no domain in database for id " + vo.getDomainId());
- } else {
- domainUuid = domain.getUuid();
+ String msg = "Cannot link Domain to LDAP. No domain found";
+ logger.error(msg);
+ throw new InvalidParameterValueException(msg);
}
- LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainUuid, vo.getType().toString(), vo.getName(), vo.getAccountType().ordinal());
- return response;
+ return domain;
+ }
+
+ @NotNull
+ private LinkAccountToLdapResponse linkAccountToLdapAndGetResponse(LinkAccountToLdapCmd cmd) {
+ DomainVO domain = getDomainToLink(cmd.getDomainId());
+ LinkType linkType = LinkType.valueOf(cmd.getType().toUpperCase());
+ Account account = accountDao.findActiveAccount(cmd.getAccountName(), cmd.getDomainId());
+ if (account == null) {
+ account = new AccountVO(cmd.getAccountName(), cmd.getDomainId(), null, cmd.getAccountType(), cmd.getRoleId(), UUID.randomUUID().toString());
+ accountDao.persist((AccountVO)account);
+ }
+
+ long accountId = account.getAccountId();
+ clearOldAccountMapping(cmd);
+ LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(cmd.getDomainId(), linkType, cmd.getLdapDomain(), cmd.getAccountType(), accountId));
+ return new LinkAccountToLdapResponse(domain.getUuid(), vo.getType().toString(), vo.getName(), vo.getAccountType().ordinal(), account.getUuid(), cmd.getAccountName());
+ }
+
+ private boolean unlinkDomainFromLdap(Long domainId) {
+ LdapTrustMapVO vo = _ldapTrustMapDao.findByDomainId(domainId);
+ if (vo != null) {
+ removeTrustmap(vo);
+ return true;
+ }
+ return false;
}
@Override
@@ -452,10 +486,6 @@
return _ldapTrustMapDao.searchByDomainId(domainId);
}
- public LdapTrustMapVO getAccountLinkedToLdap(long domainId, long accountId){
- return _ldapTrustMapDao.findByAccount(domainId, accountId);
- }
-
@Override
public LdapTrustMapVO getLinkedLdapGroup(long domainId, String group) {
return _ldapTrustMapDao.findGroupInDomain(domainId, group);
@@ -463,7 +493,7 @@
@Override
public LinkAccountToLdapResponse linkAccountToLdap(LinkAccountToLdapCmd cmd) {
- Validate.notNull(_ldapConfiguration.getBaseDn(cmd.getDomainId()), "can not link an account to ldap in a domain for which no basdn is configured");
+ Validate.notNull(LdapConfiguration.getBaseDn(cmd.getDomainId()), "can not link an account to ldap in a domain for which no basdn is configured");
Validate.notNull(cmd.getDomainId(), "domainId cannot be null.");
Validate.notEmpty(cmd.getAccountName(), "accountName cannot be empty.");
Validate.notEmpty(cmd.getLdapDomain(), "ldapDomain cannot be empty, please supply a GROUP or OU name");
@@ -471,26 +501,7 @@
Validate.notEmpty(cmd.getLdapDomain(), "GROUP or OU name cannot be empty");
Validate.isTrue(cmd.getAccountType() != null || cmd.getRoleId() != null, "Either account type or role ID must be given");
- LinkType linkType = LdapManager.LinkType.valueOf(cmd.getType().toUpperCase());
- Account account = accountDao.findActiveAccount(cmd.getAccountName(),cmd.getDomainId());
- if (account == null) {
- account = new AccountVO(cmd.getAccountName(), cmd.getDomainId(), null, cmd.getAccountType(), cmd.getRoleId(), UUID.randomUUID().toString());
- accountDao.persist((AccountVO)account);
- }
-
- Long accountId = account.getAccountId();
- clearOldAccountMapping(cmd);
- LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(cmd.getDomainId(), linkType, cmd.getLdapDomain(), cmd.getAccountType(), accountId));
- DomainVO domain = domainDao.findById(vo.getDomainId());
- String domainUuid = "<unknown>";
- if (domain == null) {
- logger.error("no domain in database for id " + vo.getDomainId());
- } else {
- domainUuid = domain.getUuid();
- }
-
- LinkAccountToLdapResponse response = new LinkAccountToLdapResponse(domainUuid, vo.getType().toString(), vo.getName(), vo.getAccountType().ordinal(), account.getUuid(), cmd.getAccountName());
- return response;
+ return linkAccountToLdapAndGetResponse(cmd);
}
private void clearOldAccountMapping(LinkAccountToLdapCmd cmd) {
@@ -498,7 +509,7 @@
LdapTrustMapVO oldVo = _ldapTrustMapDao.findGroupInDomain(cmd.getDomainId(), cmd.getLdapDomain());
if (oldVo != null) {
// deal with edge cases, i.e. check if the old account is indeed deleted etc.
- if (oldVo.getAccountId() != 0l) {
+ if (oldVo.getAccountId() != 0L) {
AccountVO oldAcount = accountDao.findByIdIncludingRemoved(oldVo.getAccountId());
String msg = String.format("group %s is mapped to account %d in the current domain (%s)", cmd.getLdapDomain(), oldVo.getAccountId(), cmd.getDomainId());
if (null == oldAcount.getRemoved()) {
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapTrustMapVO.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapTrustMapVO.java
index 2712599..c04c16a 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapTrustMapVO.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapTrustMapVO.java
@@ -123,8 +123,8 @@
public int hashCode() {
int result = type.hashCode();
result = 31 * result + name.hashCode();
- result = 31 * result + (int) (domainId ^ (domainId >>> 32));
- result = 31 * result + (int) (accountId ^ (accountId >>> 32));
+ result = 31 * result + Long.hashCode(domainId);
+ result = 31 * result + Long.hashCode(accountId);
result = 31 * result + accountType.ordinal();
return result;
}
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapUser.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapUser.java
index d2b5865..20b13ff 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapUser.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapUser.java
@@ -27,7 +27,7 @@
private final String username;
private final String domain;
private final boolean disabled;
- private List<String> memberships;
+ private final List<String> memberships;
public LdapUser(final String username, final String email, final String firstname, final String lastname, final String principal, String domain, boolean disabled,
List<String> memberships) {
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapUserManager.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapUserManager.java
index c9fcaa2..e9c7db0 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapUserManager.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/LdapUserManager.java
@@ -26,21 +26,21 @@
public interface LdapUserManager {
- public enum Provider {
- MICROSOFTAD, OPENLDAP;
+ enum Provider {
+ MICROSOFTAD, OPENLDAP
}
- public LdapUser getUser(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
+ LdapUser getUser(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
- public LdapUser getUser(final String username, final String type, final String name, final LdapContext context, Long domainId) throws NamingException, IOException;
+ LdapUser getUser(final String username, final String type, final String name, final LdapContext context, Long domainId) throws NamingException, IOException;
- public List<LdapUser> getUsers(final LdapContext context, Long domainId) throws NamingException, IOException;
+ List<LdapUser> getUsers(final LdapContext context, Long domainId) throws NamingException, IOException;
- public List<LdapUser> getUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
+ List<LdapUser> getUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
- public List<LdapUser> getUsersInGroup(String groupName, LdapContext context, Long domainId) throws NamingException;
+ List<LdapUser> getUsersInGroup(String groupName, LdapContext context, Long domainId) throws NamingException;
- public List<LdapUser> searchUsers(final LdapContext context, Long domainId) throws NamingException, IOException;
+ List<LdapUser> searchUsers(final LdapContext context, Long domainId) throws NamingException, IOException;
- public List<LdapUser> searchUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
+ List<LdapUser> searchUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
}
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java
index 80d394d..50ba2f3 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java
@@ -58,15 +58,15 @@
protected LdapUser createUser(final SearchResult result, Long domainId) throws NamingException {
final Attributes attributes = result.getAttributes();
- final String username = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getUsernameAttribute(domainId));
- final String email = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getEmailAttribute(domainId));
- final String firstname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getFirstnameAttribute(domainId));
- final String lastname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getLastnameAttribute(domainId));
+ final String username = LdapUtils.getAttributeValue(attributes, LdapConfiguration.getUsernameAttribute(domainId));
+ final String email = LdapUtils.getAttributeValue(attributes, LdapConfiguration.getEmailAttribute(domainId));
+ final String firstname = LdapUtils.getAttributeValue(attributes, LdapConfiguration.getFirstnameAttribute(domainId));
+ final String lastname = LdapUtils.getAttributeValue(attributes, LdapConfiguration.getLastnameAttribute(domainId));
final String principal = result.getNameInNamespace();
final List<String> memberships = LdapUtils.getAttributeValues(attributes, getMemberOfAttribute(domainId));
- String domain = principal.replace("cn=" + LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getCommonNameAttribute()) + ",", "");
- domain = domain.replace("," + _ldapConfiguration.getBaseDn(domainId), "");
+ String domain = principal.replace("cn=" + LdapUtils.getAttributeValue(attributes, LdapConfiguration.getCommonNameAttribute()) + ",", "");
+ domain = domain.replace("," + LdapConfiguration.getBaseDn(domainId), "");
domain = domain.replace("ou=", "");
boolean disabled = isUserDisabled(result);
@@ -83,7 +83,7 @@
StringBuilder ldapGroupsFilter = new StringBuilder();
// this should get the trustmaps for this domain
List<String> ldapGroups = getMappedLdapGroups(domainId);
- if (!ldapGroups.isEmpty()) {
+ if (CollectionUtils.isNotEmpty(ldapGroups)) {
ldapGroupsFilter.append("(|");
for (String ldapGroup : ldapGroups) {
ldapGroupsFilter.append(getMemberOfGroupString(ldapGroup, memberOfAttribute));
@@ -110,7 +110,7 @@
private StringBuilder getUsernameFilter(String username, Long domainId) {
final StringBuilder usernameFilter = new StringBuilder();
usernameFilter.append("(");
- usernameFilter.append(_ldapConfiguration.getUsernameAttribute(domainId));
+ usernameFilter.append(LdapConfiguration.getUsernameAttribute(domainId));
usernameFilter.append("=");
usernameFilter.append((username == null ? "*" : LdapUtils.escapeLDAPSearchFilter(username)));
usernameFilter.append(")");
@@ -120,7 +120,7 @@
StringBuilder getUserObjectFilter(Long domainId) {
final StringBuilder userObjectFilter = new StringBuilder();
userObjectFilter.append("(objectClass=");
- userObjectFilter.append(_ldapConfiguration.getUserObject(domainId));
+ userObjectFilter.append(LdapConfiguration.getUserObject(domainId));
userObjectFilter.append(")");
return userObjectFilter;
}
@@ -152,11 +152,11 @@
private String generateGroupSearchFilter(final String groupName, Long domainId) {
String groupObjectFilter = "(objectClass=" +
- _ldapConfiguration.getGroupObject(domainId) +
+ LdapConfiguration.getGroupObject(domainId) +
")";
String groupNameFilter = "(" +
- _ldapConfiguration.getCommonNameAttribute() +
+ LdapConfiguration.getCommonNameAttribute() +
"=" +
(groupName == null ? "*" : LdapUtils.escapeLDAPSearchFilter(groupName)) +
")";
@@ -183,7 +183,7 @@
if("OU".equals(type)) {
basedn = name;
} else {
- basedn = _ldapConfiguration.getBaseDn(domainId);
+ basedn = LdapConfiguration.getBaseDn(domainId);
}
final StringBuilder userObjectFilter = getUserObjectFilter(domainId);
@@ -227,12 +227,12 @@
@Override
public List<LdapUser> getUsersInGroup(String groupName, LdapContext context, Long domainId) throws NamingException {
- String attributeName = _ldapConfiguration.getGroupUniqueMemberAttribute(domainId);
+ String attributeName = LdapConfiguration.getGroupUniqueMemberAttribute(domainId);
final SearchControls controls = new SearchControls();
controls.setSearchScope(_ldapConfiguration.getScope());
controls.setReturningAttributes(new String[] {attributeName});
- NamingEnumeration<SearchResult> result = context.search(_ldapConfiguration.getBaseDn(domainId), generateGroupSearchFilter(groupName, domainId), controls);
+ NamingEnumeration<SearchResult> result = context.search(LdapConfiguration.getBaseDn(domainId), generateGroupSearchFilter(groupName, domainId), controls);
final List<LdapUser> users = new ArrayList<>();
//Expecting only one result which has all the users
@@ -260,7 +260,7 @@
controls.setSearchScope(_ldapConfiguration.getScope());
controls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
- NamingEnumeration<SearchResult> result = context.search(userdn, "(objectClass=" + _ldapConfiguration.getUserObject(domainId) + ")", controls);
+ NamingEnumeration<SearchResult> result = context.search(userdn, "(objectClass=" + LdapConfiguration.getUserObject(domainId) + ")", controls);
if (result.hasMoreElements()) {
return createUser(result.nextElement(), domainId);
} else {
@@ -306,12 +306,12 @@
searchControls.setSearchScope(_ldapConfiguration.getScope());
searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
- String basedn = _ldapConfiguration.getBaseDn(domainId);
+ String basedn = LdapConfiguration.getBaseDn(domainId);
if (StringUtils.isBlank(basedn)) {
throw new IllegalArgumentException(String.format("ldap basedn is not configured (for domain: %s)", domainId));
}
byte[] cookie = null;
- int pageSize = _ldapConfiguration.getLdapPageSize(domainId);
+ int pageSize = LdapConfiguration.getLdapPageSize(domainId);
context.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.NONCRITICAL)});
final List<LdapUser> users = new ArrayList<>();
NamingEnumeration<SearchResult> results;
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/dao/LdapConfigurationDao.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/dao/LdapConfigurationDao.java
index 889efa3..e757def 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/dao/LdapConfigurationDao.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/dao/LdapConfigurationDao.java
@@ -29,16 +29,14 @@
public interface LdapConfigurationDao extends GenericDao<LdapConfigurationVO, Long> {
/**
* @deprecated there might well be more then one ldap implementation on a host and or a double binding of several domains
- * @param hostname
- * @return
+ * @param hostname the hostname or ip address of the LDAP server
+ * @return the LDAP configuration for the given hostname
*/
@Deprecated
LdapConfigurationVO findByHostname(String hostname);
LdapConfigurationVO find(String hostname, int port, Long domainId);
- LdapConfigurationVO find(String hostname, int port, Long domainId, boolean listAll);
-
Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(String hostname, int port, Long domainId);
Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(Long id, String hostname, int port, Long domainId, boolean listAll);
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/dao/LdapConfigurationDaoImpl.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/dao/LdapConfigurationDaoImpl.java
index 67d09fe..1ce52b9 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/dao/LdapConfigurationDaoImpl.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/ldap/dao/LdapConfigurationDaoImpl.java
@@ -69,12 +69,6 @@
}
@Override
- public LdapConfigurationVO find(String hostname, int port, Long domainId, boolean listAll) {
- SearchCriteria<LdapConfigurationVO> sc = getSearchCriteria(null, hostname, port, domainId, listAll);
- return findOneBy(sc);
- }
-
- @Override
public Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(final String hostname, final int port, final Long domainId) {
SearchCriteria<LdapConfigurationVO> sc = getSearchCriteria(null, hostname, port, domainId, false);
return searchAndCount(sc, null);
diff --git a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapListUsersCmdTest.java b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapListUsersCmdTest.java
index bd55926..6af40c5 100644
--- a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapListUsersCmdTest.java
+++ b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapListUsersCmdTest.java
@@ -167,7 +167,7 @@
LdapUser ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null);
- boolean result = ldapListUsersCmd.isACloudstackUser(ldapUser);
+ boolean result = ldapListUsersCmd.isACloudStackUser(ldapUser);
assertTrue(result);
}
@@ -183,7 +183,7 @@
LdapUser ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null);
- boolean result = ldapListUsersCmd.isACloudstackUser(ldapUser);
+ boolean result = ldapListUsersCmd.isACloudStackUser(ldapUser);
assertFalse(result);
}
diff --git a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java
index adf0f98..e616bd5 100644
--- a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java
+++ b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java
@@ -98,5 +98,6 @@
assertEquals("type", type, result.getType());
assertEquals("name", ldapDomain, result.getLdapDomain());
assertEquals("accountId", String.valueOf(accountId), result.getAdminId());
+ assertEquals("accountName", String.valueOf(accountName), result.getAccountName());
}
}
diff --git a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/ldap/ADLdapUserManagerImplTest.java b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/ldap/ADLdapUserManagerImplTest.java
index f2ac1df..6e99445 100644
--- a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/ldap/ADLdapUserManagerImplTest.java
+++ b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/ldap/ADLdapUserManagerImplTest.java
@@ -16,17 +16,21 @@
// under the License.
package org.apache.cloudstack.ldap;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import javax.naming.directory.SearchControls;
import javax.naming.ldap.LdapContext;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;
@@ -35,40 +39,46 @@
ADLdapUserManagerImpl adLdapUserManager;
+ MockedStatic<LdapConfiguration> LdapConfiguration;
@Mock
- LdapConfiguration ldapConfiguration;
+ LdapConfiguration ldapConfigurationMock;
@Before
- public void init() throws Exception {
+ public void init() {
+ LdapConfiguration = Mockito.mockStatic(LdapConfiguration.class,Mockito.CALLS_REAL_METHODS);
adLdapUserManager = new ADLdapUserManagerImpl();
- adLdapUserManager._ldapConfiguration = ldapConfiguration;
+ adLdapUserManager._ldapConfiguration = ldapConfigurationMock;
}
+ @After
+ public void afterEach() {
+ LdapConfiguration.close();
+ }
@Test
public void testGenerateADSearchFilterWithNestedGroupsEnabled() {
- when(ldapConfiguration.getUserObject(any())).thenReturn("user");
- when(ldapConfiguration.getCommonNameAttribute()).thenReturn("CN");
- when(ldapConfiguration.getBaseDn(any())).thenReturn("DC=cloud,DC=citrix,DC=com");
- when(ldapConfiguration.isNestedGroupsEnabled(any())).thenReturn(true);
+ when(adLdapUserManager._ldapConfiguration.getUserObject(anyLong())).thenReturn("user");
+ when(adLdapUserManager._ldapConfiguration.getCommonNameAttribute()).thenReturn("CN");
+ when(adLdapUserManager._ldapConfiguration.getBaseDn(any())).thenReturn("DC=cloud,DC=citrix,DC=com");
+ when(adLdapUserManager._ldapConfiguration.isNestedGroupsEnabled(anyLong())).thenReturn(true);
String [] groups = {"dev", "dev-hyd"};
for (String group: groups) {
String result = adLdapUserManager.generateADGroupSearchFilter(group, 1L);
- assertTrue(("(&(&(objectCategory=person)(objectClass=user))(memberOf:1.2.840.113556.1.4.1941:=CN=" + group + ",DC=cloud,DC=citrix,DC=com))").equals(result));
+ assertEquals(("(&(&(objectCategory=person)(objectClass=user))(memberOf:1.2.840.113556.1.4.1941:=CN=" + group + ",DC=cloud,DC=citrix,DC=com))"), result);
}
}
@Test
public void testGenerateADSearchFilterWithNestedGroupsDisabled() {
- when(ldapConfiguration.getUserObject(any())).thenReturn("user");
- when(ldapConfiguration.getCommonNameAttribute()).thenReturn("CN");
- when(ldapConfiguration.getBaseDn(any())).thenReturn("DC=cloud,DC=citrix,DC=com");
- when(ldapConfiguration.isNestedGroupsEnabled(any())).thenReturn(false);
+ when(adLdapUserManager._ldapConfiguration.getUserObject(anyLong())).thenReturn("user");
+ when(adLdapUserManager._ldapConfiguration.getCommonNameAttribute()).thenReturn("CN");
+ when(adLdapUserManager._ldapConfiguration.getBaseDn(anyLong())).thenReturn("DC=cloud,DC=citrix,DC=com");
+ when(adLdapUserManager._ldapConfiguration.isNestedGroupsEnabled(anyLong())).thenReturn(false);
String [] groups = {"dev", "dev-hyd"};
for (String group: groups) {
String result = adLdapUserManager.generateADGroupSearchFilter(group, 1L);
- assertTrue(("(&(&(objectCategory=person)(objectClass=user))(memberOf=CN=" + group + ",DC=cloud,DC=citrix,DC=com))").equals(result));
+ assertEquals(("(&(&(objectCategory=person)(objectClass=user))(memberOf=CN=" + group + ",DC=cloud,DC=citrix,DC=com))"), result);
}
}
@@ -78,9 +88,9 @@
@Test(expected = IllegalArgumentException.class)
public void testGetUsersInGroupUsingNullGroup() throws Exception {
String[] returnAttributes = {"username", "firstname", "lastname", "email"};
- lenient().when(ldapConfiguration.getScope()).thenReturn(SearchControls.SUBTREE_SCOPE);
- lenient().when(ldapConfiguration.getReturnAttributes(null)).thenReturn(returnAttributes);
- lenient().when(ldapConfiguration.getBaseDn(any())).thenReturn(null).thenReturn(null).thenReturn("DC=cloud,DC=citrix,DC=com");
+ lenient().when(adLdapUserManager._ldapConfiguration.getScope()).thenReturn(SearchControls.SUBTREE_SCOPE);
+ lenient().when(adLdapUserManager._ldapConfiguration.getReturnAttributes(null)).thenReturn(returnAttributes);
+ lenient().when(adLdapUserManager._ldapConfiguration.getBaseDn(any())).thenReturn(null).thenReturn(null).thenReturn("DC=cloud,DC=citrix,DC=com");
LdapContext context = ldapContext;
String [] groups = {null, "group", null};
diff --git a/plugins/user-authenticators/md5/pom.xml b/plugins/user-authenticators/md5/pom.xml
index 11f0a42..f0f998c 100644
--- a/plugins/user-authenticators/md5/pom.xml
+++ b/plugins/user-authenticators/md5/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/user-authenticators/oauth2/pom.xml b/plugins/user-authenticators/oauth2/pom.xml
index 8caf06f..6ab7b9f 100644
--- a/plugins/user-authenticators/oauth2/pom.xml
+++ b/plugins/user-authenticators/oauth2/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/VerifyOAuthCodeAndGetUserCmd.java b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/VerifyOAuthCodeAndGetUserCmd.java
index bd49f87..b3d2d33 100644
--- a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/VerifyOAuthCodeAndGetUserCmd.java
+++ b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/VerifyOAuthCodeAndGetUserCmd.java
@@ -20,8 +20,10 @@
import java.util.List;
import java.util.Map;
-import com.cloud.api.response.ApiResponseSerializer;
-import com.cloud.user.Account;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
@@ -37,13 +39,13 @@
import org.apache.cloudstack.oauth2.api.response.OauthProviderResponse;
import org.apache.commons.lang.ArrayUtils;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
+import com.cloud.api.response.ApiResponseSerializer;
+import com.cloud.user.Account;
@APICommand(name = "verifyOAuthCodeAndGetUser", description = "Verify the OAuth Code and fetch the corresponding user from provider", responseObject = OauthProviderResponse.class, entityType = {},
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
- authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}, since = "4.19.0")
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}, since = "4.19.0",
+ httpMethod = "GET")
public class VerifyOAuthCodeAndGetUserCmd extends BaseListCmd implements APIAuthenticator {
/////////////////////////////////////////////////////
diff --git a/plugins/user-authenticators/pbkdf2/pom.xml b/plugins/user-authenticators/pbkdf2/pom.xml
index 75351f2..6ffa118 100644
--- a/plugins/user-authenticators/pbkdf2/pom.xml
+++ b/plugins/user-authenticators/pbkdf2/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/user-authenticators/plain-text/pom.xml b/plugins/user-authenticators/plain-text/pom.xml
index ceddc54..54a9650 100644
--- a/plugins/user-authenticators/plain-text/pom.xml
+++ b/plugins/user-authenticators/plain-text/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/user-authenticators/saml2/pom.xml b/plugins/user-authenticators/saml2/pom.xml
index 8802ab9..4cd6f70 100644
--- a/plugins/user-authenticators/saml2/pom.xml
+++ b/plugins/user-authenticators/saml2/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/user-authenticators/sha256salted/pom.xml b/plugins/user-authenticators/sha256salted/pom.xml
index 2938e21..2b47e01 100644
--- a/plugins/user-authenticators/sha256salted/pom.xml
+++ b/plugins/user-authenticators/sha256salted/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/user-two-factor-authenticators/static-pin/pom.xml b/plugins/user-two-factor-authenticators/static-pin/pom.xml
index 1fe95fa..522e245 100644
--- a/plugins/user-two-factor-authenticators/static-pin/pom.xml
+++ b/plugins/user-two-factor-authenticators/static-pin/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/user-two-factor-authenticators/totp/pom.xml b/plugins/user-two-factor-authenticators/totp/pom.xml
index dcf051f..eb3cc0b 100644
--- a/plugins/user-two-factor-authenticators/totp/pom.xml
+++ b/plugins/user-two-factor-authenticators/totp/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/pom.xml b/pom.xml
index e56c8b9..883e7a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Apache CloudStack</name>
<description>Apache CloudStack is an IaaS ("Infrastructure as a Service") cloud orchestration platform.</description>
@@ -53,6 +53,8 @@
<project.systemvm.template.version>4.22.0.0</project.systemvm.template.version>
<sonar.organization>apache</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
+ <sonar.exclusions>engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingDetailsVO.java</sonar.exclusions>
+ <sonar.exclusions>api/src/main/java/org/apache/cloudstack/api/response/BackupOfferingResponse.java</sonar.exclusions>
<!-- Build properties -->
<cs.jdk.version>11</cs.jdk.version>
@@ -87,7 +89,7 @@
<cs.log4j.extras.version>1.2.17</cs.log4j.extras.version>
<!-- Apache Commons versions -->
- <cs.codec.version>1.15</cs.codec.version>
+ <cs.codec.version>1.20.0</cs.codec.version>
<cs.commons-cli.version>1.5.0</cs.commons-cli.version>
<cs.commons-collections.version>4.4</cs.commons-collections.version>
<cs.commons-compress.version>1.26.0</cs.commons-compress.version>
@@ -102,7 +104,7 @@
<cs.configuration.version>1.10</cs.configuration.version>
<cs.daemon.version>1.3.3</cs.daemon.version>
<cs.dbcp.version>2.9.0</cs.dbcp.version>
- <cs.hikaricp.version>5.1.0</cs.hikaricp.version>
+ <cs.hikaricp.version>7.0.2</cs.hikaricp.version>
<cs.discovery.version>0.5</cs.discovery.version>
<cs.lang.version>2.6</cs.lang.version>
<cs.pool.version>2.9.0</cs.pool.version>
@@ -126,7 +128,7 @@
<cs.amqp-client.version>5.17.0</cs.amqp-client.version>
<cs.apache-cloudstack-java-client.version>1.0.9</cs.apache-cloudstack-java-client.version>
<cs.aspectjrt.version>1.9.19</cs.aspectjrt.version>
- <cs.aws.sdk.version>1.12.439</cs.aws.sdk.version>
+ <cs.aws.sdk.version>1.12.795</cs.aws.sdk.version>
<cs.axiom.version>1.2.8</cs.axiom.version>
<cs.axis2.version>1.6.4</cs.axis2.version>
<cs.batik.version>1.14</cs.batik.version>
@@ -144,7 +146,7 @@
<cs.guava.version>31.1-jre</cs.guava.version>
<cs.httpclient.version>4.5.14</cs.httpclient.version>
<cs.httpcore.version>4.4.16</cs.httpcore.version>
- <cs.influxdb-java.version>2.22</cs.influxdb-java.version>
+ <cs.influxdb-java.version>2.25</cs.influxdb-java.version>
<cs.jackson.version>2.13.3</cs.jackson.version>
<cs.jasypt.version>1.9.3</cs.jasypt.version>
<cs.java-ipv6.version>0.17</cs.java-ipv6.version>
@@ -468,8 +470,8 @@
<version>${cs.reload4j.version}</version>
</dependency>
<dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
+ <groupId>com.mysql</groupId>
+ <artifactId>mysql-connector-j</artifactId>
<version>${cs.mysql.version}</version>
<scope>test</scope>
</dependency>
@@ -485,12 +487,6 @@
</exclusions>
</dependency>
<dependency>
- <groupId>com.mysql</groupId>
- <artifactId>mysql-connector-j</artifactId>
- <version>${cs.mysql.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>${cs.ehcache.version}</version>
@@ -1090,6 +1086,7 @@
<exclude>ui/legacy/**</exclude>
<exclude>utils/testsmallfileinactive</exclude>
<exclude>**/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker</exclude>
+ <exclude>.github/workflows/dependabot.yaml</exclude>
</excludes>
</configuration>
</plugin>
diff --git a/quickcloud/pom.xml b/quickcloud/pom.xml
index d4d759f..cc0bacb 100644
--- a/quickcloud/pom.xml
+++ b/quickcloud/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
</project>
diff --git a/scripts/installer/createtmplt.sh b/scripts/installer/createtmplt.sh
index b9b403a..8d9b987 100755
--- a/scripts/installer/createtmplt.sh
+++ b/scripts/installer/createtmplt.sh
@@ -272,9 +272,4 @@
zfs snapshot -r $tmpltfs@vmops_ss
rollback_if_needed $tmpltfs $? "Failed to snapshot filesystem"
-#if [ "$cleanup" == "true" ]
-#then
- #rm -f $tmpltimg
-#fi
-
exit 0
diff --git a/scripts/installer/createvolume.sh b/scripts/installer/createvolume.sh
index 4726404..716bb85 100755
--- a/scripts/installer/createvolume.sh
+++ b/scripts/installer/createvolume.sh
@@ -273,9 +273,4 @@
zfs snapshot -r $volfs@vmops_ss
rollback_if_needed $volfs $? "Failed to snapshot filesystem"
-#if [ "$cleanup" == "true" ]
-#then
- #rm -f $volimg
-#fi
-
exit 0
diff --git a/scripts/storage/multipath/connectVolume.sh b/scripts/storage/multipath/connectVolume.sh
index fb8387e..1e20526 100755
--- a/scripts/storage/multipath/connectVolume.sh
+++ b/scripts/storage/multipath/connectVolume.sh
@@ -100,7 +100,7 @@
done
echo "$(date): Doing a recan to make sure we have proper current size locally"
-for device in $(multipath -ll 3${WWID} | egrep '^ ' | awk '{print $2}'); do
+for device in $(multipath -ll 3${WWID} | grep -E '^ ' | awk '{print $2}'); do
echo "1" > /sys/bus/scsi/drivers/sd/${device}/rescan;
done
diff --git a/scripts/storage/multipath/resizeVolume.sh b/scripts/storage/multipath/resizeVolume.sh
index 1b44a71..491c1bd 100755
--- a/scripts/storage/multipath/resizeVolume.sh
+++ b/scripts/storage/multipath/resizeVolume.sh
@@ -51,7 +51,7 @@
logger -t "CS_SCSI_VOL_RESIZE" "${WWID} resizing disk path at /dev/mapper/3${WWID} STARTING"
-for device in $(multipath -ll 3${WWID} | egrep '^ ' | awk '{print $2}'); do
+for device in $(multipath -ll 3${WWID} | grep -E '^ ' | awk '{print $2}'); do
echo "1" > /sys/bus/scsi/drivers/sd/${device}/rescan;
done
diff --git a/scripts/storage/secondary/listvmtmplt.sh b/scripts/storage/secondary/listvmtmplt.sh
index 8463b51..c0f2132 100755
--- a/scripts/storage/secondary/listvmtmplt.sh
+++ b/scripts/storage/secondary/listvmtmplt.sh
@@ -53,11 +53,6 @@
do
d=$(dirname $i)
filename=$(grep "^filename" $i | awk -F"=" '{print $NF}')
-# size=$(grep "virtualsize" $i | awk -F"=" '{print $NF}')
-# if [ -n "$filename" ] && [ -n "$size" ]
-# then
-# d=$d/$filename/$size
-# fi
echo ${d#/}/$filename #remove leading slash
done
diff --git a/scripts/storage/secondary/listvolume.sh b/scripts/storage/secondary/listvolume.sh
index d039c65..605b8b9 100755
--- a/scripts/storage/secondary/listvolume.sh
+++ b/scripts/storage/secondary/listvolume.sh
@@ -53,11 +53,6 @@
do
d=$(dirname $i)
filename=$(grep "^filename" $i | awk -F"=" '{print $NF}')
-# size=$(grep "virtualsize" $i | awk -F"=" '{print $NF}')
-# if [ -n "$filename" ] && [ -n "$size" ]
-# then
-# d=$d/$filename/$size
-# fi
echo ${d#/}/$filename #remove leading slash
done
diff --git a/scripts/util/keystore-setup b/scripts/util/keystore-setup
index 1e1237c..88f5a87 100755
--- a/scripts/util/keystore-setup
+++ b/scripts/util/keystore-setup
@@ -75,7 +75,7 @@
# Generate CSR
$LOGGER_CMD "Generating CSR"
[ -f "$CSR_FILE" ] && rm -f "$CSR_FILE"
-addresses=$(ip address | grep inet | awk '{print $2}' | sed 's/\/.*//g' | grep -v '^169.254.' | grep -v '^127.0.0.1' | egrep -v '^::1|^fe80' | grep -v '^::1' | sed 's/^/ip:/g' | tr '\r\n' ',')
+addresses=$(ip address | grep inet | awk '{print $2}' | sed 's/\/.*//g' | grep -v '^169.254.' | grep -v '^127.0.0.1' | grep -E -v '^::1|^fe80' | grep -v '^::1' | sed 's/^/ip:/g' | tr '\r\n' ',')
$LOGGER_CMD "Found following SAN addresses to add to CSR: ${addresses}"
keytool -certreq -storepass "$KS_PASS" -alias "$ALIAS" -file "$CSR_FILE" -keystore "$KS_FILE" -ext san="$addresses" 2>&1 | $LOGGER_CMD
if [ $? -ne 0 ];then
diff --git a/scripts/vm/hypervisor/kvm/nasbackup.sh b/scripts/vm/hypervisor/kvm/nasbackup.sh
index e298006..7f4a4b6 100755
--- a/scripts/vm/hypervisor/kvm/nasbackup.sh
+++ b/scripts/vm/hypervisor/kvm/nasbackup.sh
@@ -1,20 +1,21 @@
#!/usr/bin/bash
-## 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.
+
+# 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.
set -eo pipefail
diff --git a/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh b/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh
index 2fcfa0b..15ed634 100755
--- a/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh
+++ b/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh
@@ -1,20 +1,21 @@
#!/bin/bash
-## 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.
+
+# 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.
version=0.9.1
OPTIND=1
diff --git a/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh b/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh
index 40a9021..0a6f5f9 100755
--- a/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh
+++ b/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh
@@ -1,20 +1,21 @@
#!/bin/bash
-## 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.
+
+# 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.
version=0.9.1
OPTIND=1
diff --git a/scripts/vm/hypervisor/ovm3/cloudstack.py b/scripts/vm/hypervisor/ovm3/cloudstack.py
index e82863e..39b5926 100644
--- a/scripts/vm/hypervisor/ovm3/cloudstack.py
+++ b/scripts/vm/hypervisor/ovm3/cloudstack.py
@@ -67,10 +67,6 @@
'get_module_version': getModuleVersion,
'get_ovs_version': ovmVersion,
'ping': ping,
-# 'patch': ovmCsPatch,
-# 'ovs_agent_set_ssl': ovsAgentSetSsl,
-# 'ovs_agent_set_port': ovsAgentSetPort,
-# 'ovs_restart_agent': ovsRestartAgent,
}
def getName(self):
diff --git a/scripts/vm/hypervisor/xenserver/perfmon.py b/scripts/vm/hypervisor/xenserver/perfmon.py
index 59c1ac3..fcdc8a6 100755
--- a/scripts/vm/hypervisor/xenserver/perfmon.py
+++ b/scripts/vm/hypervisor/xenserver/perfmon.py
@@ -210,11 +210,6 @@
total_counter = int(args['total_counter'])
now = int(time.time()) / 60
- # Get pool's info of this host
- #pool = login.xenapi.pool.get_all()[0]
- # Get master node's address of pool
- #master = login.xenapi.pool.get_master(pool)
- #master_address = login.xenapi.host.get_address(master)
session = login._session
max_duration = 0
@@ -226,7 +221,6 @@
rrd_updates = RRDUpdates()
rrd_updates.refresh(login.xenapi, now * 60 - max_duration, session, {})
- #for uuid in rrd_updates.get_vm_list():
for vm_count in xrange(1, total_vm + 1):
vm_name = args['vmname' + str(vm_count)]
vm_uuid = getuuid(vm_name)
diff --git a/scripts/vm/hypervisor/xenserver/xcposs/NFSSR.py b/scripts/vm/hypervisor/xenserver/xcposs/NFSSR.py
index 306f941..84eb730 100644
--- a/scripts/vm/hypervisor/xenserver/xcposs/NFSSR.py
+++ b/scripts/vm/hypervisor/xenserver/xcposs/NFSSR.py
@@ -175,20 +175,6 @@
pass
raise exn
- #newpath = os.path.join(self.path, sr_uuid)
- #if util.ioretry(lambda: util.pathexists(newpath)):
- # if len(util.ioretry(lambda: util.listdir(newpath))) != 0:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('SRExists')
- #else:
- # try:
- # util.ioretry(lambda: util.makedirs(newpath))
- # except util.CommandException, inst:
- # if inst.code != errno.EEXIST:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('NFSCreate',
- # opterr='remote directory creation error is %d'
- # % inst.code)
self.detach(sr_uuid)
def delete(self, sr_uuid):
diff --git a/scripts/vm/hypervisor/xenserver/xcpserver/NFSSR.py b/scripts/vm/hypervisor/xenserver/xcpserver/NFSSR.py
index 62031e3..faaf6d9 100755
--- a/scripts/vm/hypervisor/xenserver/xcpserver/NFSSR.py
+++ b/scripts/vm/hypervisor/xenserver/xcpserver/NFSSR.py
@@ -106,7 +106,6 @@
def attach(self, sr_uuid):
self.validate_remotepath(False)
- #self.remotepath = os.path.join(self.dconf['serverpath'], sr_uuid)
self.remotepath = self.dconf['serverpath']
util._testHost(self.dconf['server'], NFSPORT, 'NFSTarget')
self.mount_remotepath(sr_uuid)
@@ -175,20 +174,6 @@
pass
raise exn
- #newpath = os.path.join(self.path, sr_uuid)
- #if util.ioretry(lambda: util.pathexists(newpath)):
- # if len(util.ioretry(lambda: util.listdir(newpath))) != 0:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('SRExists')
- #else:
- # try:
- # util.ioretry(lambda: util.makedirs(newpath))
- # except util.CommandException, inst:
- # if inst.code != errno.EEXIST:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('NFSCreate',
- # opterr='remote directory creation error is %d'
- # % inst.code)
self.detach(sr_uuid)
def delete(self, sr_uuid):
diff --git a/scripts/vm/hypervisor/xenserver/xenserver56/NFSSR.py b/scripts/vm/hypervisor/xenserver/xenserver56/NFSSR.py
index b8489e7..50e9e60 100755
--- a/scripts/vm/hypervisor/xenserver/xenserver56/NFSSR.py
+++ b/scripts/vm/hypervisor/xenserver/xenserver56/NFSSR.py
@@ -178,20 +178,6 @@
pass
raise exn
- #newpath = os.path.join(self.path, sr_uuid)
- #if util.ioretry(lambda: util.pathexists(newpath)):
- # if len(util.ioretry(lambda: util.listdir(newpath))) != 0:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('SRExists')
- #else:
- # try:
- # util.ioretry(lambda: util.makedirs(newpath))
- # except util.CommandException, inst:
- # if inst.code != errno.EEXIST:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('NFSCreate',
- # opterr='remote directory creation error is %d'
- # % inst.code)
self.detach(sr_uuid)
@FileSR.locking("SRUnavailable")
diff --git a/scripts/vm/hypervisor/xenserver/xenserver56fp1/NFSSR.py b/scripts/vm/hypervisor/xenserver/xenserver56fp1/NFSSR.py
index b8c1157..9d2f81f 100755
--- a/scripts/vm/hypervisor/xenserver/xenserver56fp1/NFSSR.py
+++ b/scripts/vm/hypervisor/xenserver/xenserver56fp1/NFSSR.py
@@ -107,7 +107,6 @@
def attach(self, sr_uuid):
self.validate_remotepath(False)
- #self.remotepath = os.path.join(self.dconf['serverpath'], sr_uuid)
self.remotepath = self.dconf['serverpath']
util._testHost(self.dconf['server'], NFSPORT, 'NFSTarget')
self.mount_remotepath(sr_uuid)
@@ -176,20 +175,6 @@
pass
raise exn
- #newpath = os.path.join(self.path, sr_uuid)
- #if util.ioretry(lambda: util.pathexists(newpath)):
- # if len(util.ioretry(lambda: util.listdir(newpath))) != 0:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('SRExists')
- #else:
- # try:
- # util.ioretry(lambda: util.makedirs(newpath))
- # except util.CommandException, inst:
- # if inst.code != errno.EEXIST:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('NFSCreate',
- # opterr='remote directory creation error is %d'
- # % inst.code)
self.detach(sr_uuid)
def delete(self, sr_uuid):
diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/NFSSR.py b/scripts/vm/hypervisor/xenserver/xenserver60/NFSSR.py
index 9a3fa8b..68aaeae 100755
--- a/scripts/vm/hypervisor/xenserver/xenserver60/NFSSR.py
+++ b/scripts/vm/hypervisor/xenserver/xenserver60/NFSSR.py
@@ -181,20 +181,6 @@
pass
raise exn
- #newpath = os.path.join(self.path, sr_uuid)
- #if util.ioretry(lambda: util.pathexists(newpath)):
- # if len(util.ioretry(lambda: util.listdir(newpath))) != 0:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('SRExists')
- #else:
- # try:
- # util.ioretry(lambda: util.makedirs(newpath))
- # except util.CommandException, inst:
- # if inst.code != errno.EEXIST:
- # self.detach(sr_uuid)
- # raise xs_errors.XenError('NFSCreate',
- # opterr='remote directory creation error is %d'
- # % inst.code)
self.detach(sr_uuid)
def delete(self, sr_uuid):
diff --git a/scripts/vm/hypervisor/xenserver/xenserver84/vmops b/scripts/vm/hypervisor/xenserver/xenserver84/vmops
index cf6e632..76d4571 100755
--- a/scripts/vm/hypervisor/xenserver/xenserver84/vmops
+++ b/scripts/vm/hypervisor/xenserver/xenserver84/vmops
@@ -1587,6 +1587,43 @@
except:
logging.exception("Failed to network rule!")
+@echo
+def create_vtpm(session, args):
+ util.SMlog("create_vtpm called with args: %s" % str(args))
+
+ try:
+ vm_uuid = args.get('vm_uuid')
+ if not vm_uuid:
+ return "ERROR: vm_uuid parameter is required"
+
+ # Check if vTPM already exists for this VM
+ cmd = ['xe', 'vtpm-list', 'vm-uuid=' + vm_uuid, '--minimal']
+ result = util.pread2(cmd)
+ existing_vtpms = result.strip()
+
+ if existing_vtpms:
+ util.SMlog("vTPM already exists for VM %s: %s" % (vm_uuid, existing_vtpms))
+ return existing_vtpms.split(',')[0]
+
+ cmd = ['xe', 'vtpm-create', 'vm-uuid=' + vm_uuid]
+ result = util.pread2(cmd)
+ vtpm_uuid = result.strip()
+
+ if vtpm_uuid:
+ util.SMlog("Successfully created vTPM %s for VM %s" % (vtpm_uuid, vm_uuid))
+ return vtpm_uuid
+ else:
+ return "ERROR: Failed to create vTPM, empty result"
+
+ except CommandException as e:
+ error_msg = "xe command failed: %s" % str(e)
+ util.SMlog("ERROR: %s" % error_msg)
+ return "ERROR: " + error_msg
+ except Exception as e:
+ error_msg = str(e)
+ util.SMlog("ERROR: %s" % error_msg)
+ return "ERROR: " + error_msg
+
if __name__ == "__main__":
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi,
"preparemigration": preparemigration,
@@ -1604,4 +1641,5 @@
"createFileInDomr":createFileInDomr,
"kill_copy_process":kill_copy_process,
"secureCopyToHost":secureCopyToHost,
- "runPatchScriptInDomr": runPatchScriptInDomr})
+ "runPatchScriptInDomr": runPatchScriptInDomr,
+ "create_vtpm": create_vtpm})
diff --git a/scripts/vm/network/ovs-pvlan-kvm-vm.sh b/scripts/vm/network/ovs-pvlan-kvm-vm.sh
index c8da75f..b28dbda 100755
--- a/scripts/vm/network/ovs-pvlan-kvm-vm.sh
+++ b/scripts/vm/network/ovs-pvlan-kvm-vm.sh
@@ -112,7 +112,7 @@
}
# try to find the physical link to outside, only supports eth and em prefix now
-trunk_port=`ovs-ofctl show $br | egrep "\((eth|em)[0-9]" | cut -d '(' -f 1|tr -d ' '`
+trunk_port=`ovs-ofctl show $br | grep -E "\((eth|em)[0-9]" | cut -d '(' -f 1|tr -d ' '`
vm_port=$(find_port $vm_mac)
# craft the vlan headers. Adding 4096 as in hex, it must be of the form 0x1XXX
diff --git a/scripts/vm/network/ovs-pvlan-vm.sh b/scripts/vm/network/ovs-pvlan-vm.sh
index 95054c8..b55377f 100755
--- a/scripts/vm/network/ovs-pvlan-vm.sh
+++ b/scripts/vm/network/ovs-pvlan-vm.sh
@@ -87,7 +87,7 @@
fi
# try to find the physical link to outside, only supports eth and em prefix now
-trunk_port=`ovs-ofctl show $br | egrep "\((eth|em)[0-9]" | cut -d '(' -f 1|tr -d ' '`
+trunk_port=`ovs-ofctl show $br | grep -E "\((eth|em)[0-9]" | cut -d '(' -f 1|tr -d ' '`
if [ "$op" == "add" ]
then
diff --git a/scripts/vm/network/security_group.py b/scripts/vm/network/security_group.py
index 8e3e779..235e634 100755
--- a/scripts/vm/network/security_group.py
+++ b/scripts/vm/network/security_group.py
@@ -28,6 +28,9 @@
import time
import ipaddress
+NOTRACK_IPV4_IPSET = 'cs_notrack'
+NOTRACK_IPV6_IPSET = 'cs_notrack6'
+
logpath = "/var/run/cloud/" # FIXME: Logs should reside in /var/log/cloud
lock_file = "/var/lock/cloudstack_security_group.lock"
driver = "qemu:///system"
@@ -131,20 +134,37 @@
return ipaddress.ip_address('fe80::' + ':'.join(re.findall(r'.{4}', eui64)))
-def split_ips_by_family(ips):
- if type(ips) is str:
- ips = [ip for ip in ips.split(';') if ip != '']
+def split_ips_by_family(*addresses):
+ """
+ Takes one or more IP addresses as the input, and returns two lists:
+ one for ipv4 addresses, one for ipv6 addresses
+
+ If one of the inputs is a string, it tries to split it by semicolon,
+ and ignores the empty fields, or the fields with the value '0'
+ """
+ ips = []
+ for i in addresses:
+ if not i: # IP address can be sometimes None (e.g. when ipv6 address not present)
+ continue
+ if type(i) is str:
+ ips += [ip for ip in i.split(';') if ip != '' and ip != '0']
+ else:
+ ips.append(str(i))
ip4s = []
ip6s = []
for ip in ips:
- network = ipaddress.ip_network(ip)
- if network.version == 4:
- ip4s.append(ip)
- elif network.version == 6:
- ip6s.append(ip)
+ try:
+ addr = ipaddress.ip_address(ip)
+ if isinstance(addr, ipaddress.IPv4Address):
+ ip4s.append(str(addr))
+ elif isinstance(addr, ipaddress.IPv6Address):
+ ip6s.append(str(addr))
+ except ValueError as e:
+ logging.warning(f"Could not parse one of the IP addresses in the list {ips}: {str(e)}")
return ip4s, ip6s
+
def destroy_network_rules_for_nic(vm_name, vm_ip, vm_mac, vif, sec_ips):
try:
rules = execute("""iptables-save -t filter | awk '/ %s / { sub(/-A/, "-D", $1) ; print }'""" % vif ).split("\n")
@@ -172,6 +192,13 @@
add_to_ipset(vm_name, ips, "-D")
ebtables_rules_vmip(vm_name, vm_mac, ips, "-D")
+ ip4s = sec_ips.split(';')
+ ip4s.pop()
+ ip4s = [ x for x in ip4s if x != '0']
+ ip4s.append(vm_ip)
+
+ add_to_ipset(NOTRACK_IPV4_IPSET, ip4s, "del")
+
vmchain_in = vm_name + "-in"
vmchain_out = vm_name + "-out"
vmchain_in_src = vm_name + "-in-src"
@@ -454,16 +481,11 @@
def add_to_ipset(ipsetname, ips, action):
- result = True
for ip in ips:
- try:
- logging.debug("vm ip " + str(ip))
- execute("ipset " + action + " " + ipsetname + " " + str(ip))
- except:
- logging.debug("vm ip already in ip set " + str(ip))
- continue
+ logging.debug("vm ip " + str(ip))
+ execute("ipset -! " + action + " " + ipsetname + " " + str(ip))
- return result
+ return True
def network_rules_vmSecondaryIp(vm_name, vm_mac, ip_secondary, action):
@@ -487,7 +509,7 @@
return True
-def ebtables_rules_vmip (vmname, vmmac, ips, action):
+def ebtables_rules_vmip(vmname, vmmac, ips, action):
eb_vm_chain=ebtables_chain_name(vmname)
vmchain_inips = eb_vm_chain + "-in-ips"
vmchain_outips = eb_vm_chain + "-out-ips"
@@ -576,28 +598,21 @@
return False
#add secodnary nic ips to ipset
- secIpSet = "1"
- ips = sec_ips.split(';')
- ips.pop()
-
- if len(ips) == 0 or ips[0] == "0":
- secIpSet = "0"
- ip4s = []
- ip6s = []
-
- if secIpSet == "1":
- logging.debug("Adding IPset for secondary IPv4 addresses")
- ip4s, ip6s = split_ips_by_family(ips)
-
+ ip4s, ip6s = split_ips_by_family(sec_ips, vm_ip, vm_ip6, ipv6_link_local)
+ if ip4s:
+ logging.debug("Adding IPset for all IPv4 addresses")
add_to_ipset(vmipsetName, ip4s, action)
if not write_secip_log_for_vm(vm_name, sec_ips, vm_id):
logging.debug("Failed to log default network rules, ignoring")
+ if ip6s:
+ logging.debug("Adding ipset for all ipv6 addresses")
+ add_to_ipset(vmipsetName6, ip6s, action)
+
try:
execute("iptables -A " + brfw + "-OUT" + " -m physdev --physdev-is-bridged --physdev-out " + vif + " -j " + vmchain_default)
execute("iptables -A " + brfw + "-IN" + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -j " + vmchain_default)
- execute("iptables -A " + vmchain_default + " -m state --state RELATED,ESTABLISHED -j ACCEPT")
#allow dhcp
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -p udp --dport 67 --sport 68 -j ACCEPT")
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-out " + vif + " -p udp --dport 68 --sport 67 -j ACCEPT")
@@ -607,12 +622,16 @@
if vm_ip:
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set ! --match-set " + vmipsetName + " src -j DROP")
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-out " + vif + " -m set ! --match-set " + vmipsetName + " dst -j DROP")
- execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set --match-set " + vmipsetName + " src -p udp --dport 53 -j RETURN ")
- execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set --match-set " + vmipsetName + " src -p tcp --dport 53 -j RETURN ")
+ execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set --match-set " + vmipsetName + " src -p udp --dport 53 -j ACCEPT")
+ execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set --match-set " + vmipsetName + " src -p tcp --dport 53 -j ACCEPT")
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set --match-set " + vmipsetName + " src -j " + vmchain_egress)
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-out " + vif + " -j " + vmchain)
- execute("iptables -A " + vmchain + " -j DROP")
+ execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m state --state ESTABLISHED,RELATED -j ACCEPT")
+ execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-out " + vif + " -m state --state ESTABLISHED,RELATED -j ACCEPT")
+ execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -j DROP")
+ execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-out " + vif + " -j DROP")
+ execute("iptables -A " + vmchain + " -j RETURN")
except:
logging.debug("Failed to program default rules for vm " + vm_name)
return False
@@ -625,59 +644,45 @@
if not write_rule_log_for_vm(vmName, vm_id, vm_ip, domID, '_initial_', '-1'):
logging.debug("Failed to log default network rules, ignoring")
- vm_ip6_addr = [ipv6_link_local]
- try:
- ip6 = ipaddress.ip_address(vm_ip6)
- if ip6.version == 6:
- vm_ip6_addr.append(ip6)
- except (ipaddress.AddressValueError, ValueError):
- pass
-
- add_to_ipset(vmipsetName6, vm_ip6_addr, action)
- if secIpSet == "1":
- logging.debug("Adding ipset for secondary ipv6 addresses")
- add_to_ipset(vmipsetName6, ip6s, action)
-
try:
execute('ip6tables -A ' + brfw + '-OUT' + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -j ' + vmchain_default)
execute('ip6tables -A ' + brfw + '-IN' + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -j ' + vmchain_default)
- execute('ip6tables -A ' + vmchain_default + ' -m state --state RELATED,ESTABLISHED -j ACCEPT')
# Allow Instances to receive Router Advertisements, send out solicitations, but block any outgoing Advertisement from a Instance
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' --src fe80::/64 --dst ff02::1 -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT')
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' --dst ff02::2 -p icmpv6 --icmpv6-type router-solicitation -m hl --hl-eq 255 -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' --dst ff02::2 -p icmpv6 --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT')
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type router-advertisement -j DROP')
# Allow neighbor solicitations and advertisements
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT')
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT')
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type neighbor-advertisement -m set --match-set ' + vmipsetName6 + ' src -m hl --hl-eq 255 -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type neighbor-advertisement -m set --match-set ' + vmipsetName6 + ' src -m hl --hl-eq 255 -j ACCEPT')
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT')
# Packets to allow as per RFC4890
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type packet-too-big -m set --match-set ' + vmipsetName6 + ' src -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type packet-too-big -m set --match-set ' + vmipsetName6 + ' src -j ACCEPT')
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT')
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type destination-unreachable -m set --match-set ' + vmipsetName6 + ' src -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type destination-unreachable -m set --match-set ' + vmipsetName6 + ' src -j ACCEPT')
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT')
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type time-exceeded -m set --match-set ' + vmipsetName6 + ' src -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type time-exceeded -m set --match-set ' + vmipsetName6 + ' src -j ACCEPT')
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT')
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type parameter-problem -m set --match-set ' + vmipsetName6 + ' src -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type parameter-problem -m set --match-set ' + vmipsetName6 + ' src -j ACCEPT')
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT')
# MLDv2 discovery packets
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --dst ff02::16 -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --dst ff02::16 -j ACCEPT')
# Allow Instances to send out DHCPv6 client messages, but block server messages
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p udp --sport 546 --dst ff02::1:2 --src ' + str(ipv6_link_local) + ' -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p udp --sport 546 --dst ff02::1:2 --src ' + str(ipv6_link_local) + ' -j ACCEPT')
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p udp --src fe80::/64 --dport 546 --dst ' + str(ipv6_link_local) + ' -j ACCEPT')
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p udp --sport 547 ! --dst fe80::/64 -j DROP')
# Always allow outbound DNS over UDP and TCP
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p udp --dport 53 -m set --match-set ' + vmipsetName6 + ' src -j RETURN')
- execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p tcp --dport 53 -m set --match-set ' + vmipsetName6 + ' src -j RETURN')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p udp --dport 53 -m set --match-set ' + vmipsetName6 + ' src -j ACCEPT')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p tcp --dport 53 -m set --match-set ' + vmipsetName6 + ' src -j ACCEPT')
# Prevent source address spoofing
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -m set ! --match-set ' + vmipsetName6 + ' src -j DROP')
@@ -687,8 +692,13 @@
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -j ' + vmchain)
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -m state --state ESTABLISHED,RELATED -j ACCEPT')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -m state --state ESTABLISHED,RELATED -j ACCEPT')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -j DROP')
+ execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -j DROP')
+
# Drop all other traffic into the Instance
- execute('ip6tables -A ' + vmchain + ' -j DROP')
+ execute('ip6tables -A ' + vmchain + ' -j RETURN')
except:
logging.debug('Failed to program default rules for vm ' + vm_name)
return False
@@ -1106,11 +1116,6 @@
logging.debug("Rules already programmed for vm " + vm_name)
return True
- if rules == "" or rules == None:
- lines = []
- else:
- lines = rules.split(';')[:-1]
-
logging.debug("programming network rules for IP: " + vm_ip + " vmname=%s", vm_name)
egress_chain_name(vm_name)
@@ -1128,7 +1133,38 @@
egressrule_v4 = 0
egressrule_v6 = 0
- for rule in parse_network_rules(rules):
+ ip4s, ip6s = split_ips_by_family(vm_ip, vm_ip6, sec_ips, str(ipv6_link_local_addr(vmMac)))
+
+ rules = parse_network_rules(rules)
+ conntrack4_not_needed = False
+ conntrack6_not_needed = False
+ for rule in rules:
+ """
+ If any of the rules has an explicit allow all protocols from 0.0.0.0/0 (ipv4)
+ or ::/0 (ipv6), then that IP family doesn't need its connection tracked
+ Example contents of the rules list:
+ [
+ {'ipv4': ['1.0.0.0/24', '0.0.0.0/0'], 'ipv6': ['::/0'], 'ruletype': 'I', 'start': 0, 'end': 0, 'protocol': 'all'},
+ {'ipv4': ['1.1.1.1/32'], 'ipv6': [], 'ruletype': 'I', 'start': 1, 'end': 65535, 'protocol': 'tcp'},
+ {'ipv4': [], 'ipv6': ['2001:db8::/32'], 'ruletype': 'I', 'start': 2000, 'end': 3000, 'protocol': 'tcp'}
+ ]
+ """
+ if '0.0.0.0/0' in rule['ipv4'] and rule['protocol'].lower() == 'all':
+ conntrack4_not_needed = True
+ if '::/0' in rule['ipv6'] and rule['protocol'].lower() == 'all':
+ conntrack6_not_needed = True
+
+ if conntrack4_not_needed:
+ add_to_ipset(NOTRACK_IPV4_IPSET, ip4s, "add")
+ else:
+ add_to_ipset(NOTRACK_IPV4_IPSET, ip4s, "del")
+
+ if conntrack6_not_needed:
+ add_to_ipset(NOTRACK_IPV6_IPSET, ip6s, "add")
+ else:
+ add_to_ipset(NOTRACK_IPV6_IPSET, ip6s, "del")
+
+ for rule in rules:
start = rule['start']
end = rule['end']
protocol = rule['protocol']
@@ -1136,7 +1172,7 @@
if rule['ruletype'] == 'E':
vmchain = egress_vmchain
direction = "-d"
- action = "RETURN"
+ action = "ACCEPT"
if rule['ipv4']:
egressrule_v4 =+ 1
@@ -1155,10 +1191,8 @@
if protocol != 'all' and protocol != 'icmp' and protocol != 'tcp' and protocol != 'udp':
protocol_all = " -p " + protocol
- protocol_state = " "
else:
protocol_all = " -p " + protocol + " -m " + protocol
- protocol_state = " -m state --state NEW "
if 'icmp' == protocol:
range = str(start) + '/' + str(end)
@@ -1167,17 +1201,17 @@
for ip in rule['ipv4']:
if protocol == 'all':
- execute('iptables -I ' + vmchain + ' -m state --state NEW ' + direction + ' ' + ip + ' -j ' + action)
+ execute('iptables -I ' + vmchain + ' ' + direction + ' ' + ip + ' -j ' + action)
elif protocol == 'icmp':
execute("iptables -I " + vmchain + " -p icmp --icmp-type " + range + " " + direction + " " + ip + " -j " + action)
else:
- execute("iptables -I " + vmchain + protocol_all + dport + protocol_state + direction + " " + ip + " -j "+ action)
+ execute("iptables -I " + vmchain + protocol_all + dport + " " + direction + " " + ip + " -j "+ action)
for ip in rule['ipv6']:
if protocol == 'all':
- execute('ip6tables -I ' + vmchain + ' -m state --state NEW ' + direction + ' ' + ip + ' -j ' + action)
+ execute('ip6tables -I ' + vmchain + ' ' + direction + ' ' + ip + ' -j ' + action)
elif 'icmp' != protocol:
- execute("ip6tables -I " + vmchain + protocol_all + dport + protocol_state + direction + " " + ip + " -j "+ action)
+ execute("ip6tables -I " + vmchain + protocol_all + dport + ' ' + direction + " " + ip + " -j "+ action)
else:
# ip6tables does not allow '--icmpv6-type any', allowing all ICMPv6 is done by not allowing a specific type
if range == 'any':
@@ -1187,19 +1221,19 @@
egress_vmchain = egress_chain_name(vm_name)
if egressrule_v4 == 0 :
- execute('iptables -A ' + egress_vmchain + ' -j RETURN')
+ execute('iptables -A ' + egress_vmchain + ' -j ACCEPT')
else:
- execute('iptables -A ' + egress_vmchain + ' -j DROP')
+ execute('iptables -A ' + egress_vmchain + ' -j RETURN')
if egressrule_v6 == 0 :
- execute('ip6tables -A ' + egress_vmchain + ' -j RETURN')
+ execute('ip6tables -A ' + egress_vmchain + ' -j ACCEPT')
else:
- execute('ip6tables -A ' + egress_vmchain + ' -j DROP')
+ execute('ip6tables -A ' + egress_vmchain + ' -j RETURN')
vmchain = iptables_chain_name(vm_name)
- execute('iptables -A ' + vmchain + ' -j DROP')
- execute('ip6tables -A ' + vmchain + ' -j DROP')
+ execute('iptables -A ' + vmchain + ' -j RETURN')
+ execute('ip6tables -A ' + vmchain + ' -j RETURN')
if not write_rule_log_for_vm(vmName, vm_id, vm_ip, domId, signature, seqno):
return False
@@ -1288,7 +1322,7 @@
execute("sysctl -w net.bridge.bridge-nf-call-iptables=1")
execute("sysctl -w net.bridge.bridge-nf-call-ip6tables=1")
except:
- logging.warn("failed to turn on bridge netfilter")
+ logging.warning("failed to turn on bridge netfilter")
brfw = get_br_fw(brname)
try:
@@ -1327,6 +1361,30 @@
physdev = get_bridge_physdev(brname)
+ # Add notrack ipset. The IP addresses from it will be excluded from connection tracking
+ execute(f"ipset -! create {NOTRACK_IPV4_IPSET} hash:ip family inet")
+ execute(f"ipset -! create {NOTRACK_IPV6_IPSET} hash:ip family inet6")
+
+ # Create IPv4 rules that disable connection tracking
+ try:
+ execute(f"iptables -t raw -n -L PREROUTING | grep -q 'match-set {NOTRACK_IPV4_IPSET} dst NOTRACK'")
+ except:
+ execute(f"iptables -t raw -A PREROUTING -m set --match-set {NOTRACK_IPV4_IPSET} dst -j NOTRACK")
+ try:
+ execute(f"iptables -t raw -n -L PREROUTING | grep -q 'match-set {NOTRACK_IPV4_IPSET} src NOTRACK'")
+ except:
+ execute(f"iptables -t raw -A PREROUTING -m set --match-set {NOTRACK_IPV4_IPSET} src -j NOTRACK")
+
+ # Create IPv6 rules that disable connection tracking
+ try:
+ execute(f"ip6tables -t raw -n -L PREROUTING | grep -q 'match-set {NOTRACK_IPV6_IPSET} dst NOTRACK'")
+ except:
+ execute(f"ip6tables -t raw -A PREROUTING -m set --match-set {NOTRACK_IPV6_IPSET} dst -j NOTRACK")
+ try:
+ execute(f"ip6tables -t raw -n -L PREROUTING | grep -q 'match-set {NOTRACK_IPV6_IPSET} src NOTRACK'")
+ except:
+ execute(f"ip6tables -t raw -A PREROUTING -m set --match-set {NOTRACK_IPV6_IPSET} src -j NOTRACK")
+
try:
refs = int(execute("""iptables -n -L %s | awk '/%s(.*)references/ {gsub(/\(/, "") ;print $3}'""" % (brfw,brfw)).strip())
refs_in = int(execute("""iptables -n -L %s-IN | awk '/%s-IN(.*)references/ {gsub(/\(/, "") ;print $3}'""" % (brfw,brfw)).strip())
@@ -1338,7 +1396,6 @@
execute("iptables -I FORWARD -o " + brname + " -j DROP")
execute("iptables -I FORWARD -i " + brname + " -m physdev --physdev-is-bridged -j " + brfw)
execute("iptables -I FORWARD -o " + brname + " -m physdev --physdev-is-bridged -j " + brfw)
- execute("iptables -A " + brfw + " -m state --state RELATED,ESTABLISHED -j ACCEPT")
execute("iptables -A " + brfw + " -m physdev --physdev-is-bridged --physdev-is-in -j " + brfwin)
execute("iptables -A " + brfw + " -m physdev --physdev-is-bridged --physdev-is-out -j " + brfwout)
execute("iptables -A " + brfw + " -m physdev --physdev-is-bridged --physdev-out " + physdev + " -j ACCEPT")
@@ -1348,7 +1405,6 @@
execute('ip6tables -I FORWARD -o ' + brname + ' -j DROP')
execute('ip6tables -I FORWARD -i ' + brname + ' -m physdev --physdev-is-bridged -j ' + brfw)
execute('ip6tables -I FORWARD -o ' + brname + ' -m physdev --physdev-is-bridged -j ' + brfw)
- execute('ip6tables -A ' + brfw + ' -m state --state RELATED,ESTABLISHED -j ACCEPT')
execute('ip6tables -A ' + brfw + ' -m physdev --physdev-is-bridged --physdev-is-in -j ' + brfwin)
execute('ip6tables -A ' + brfw + ' -m physdev --physdev-is-bridged --physdev-is-out -j ' + brfwout)
execute('ip6tables -A ' + brfw + ' -m physdev --physdev-is-bridged --physdev-out ' + physdev + ' -j ACCEPT')
@@ -1382,15 +1438,6 @@
print("Cannot find vif")
sys.exit(1)
- #vm_name = "i-2-55-VM"
- #vm_id = 55
- #vm_ip = "10.11.118.128"
- #vm_ip6 = "fe80::1c00:b4ff:fe00:5"
- #vm_mac = "1e:00:b4:00:00:05"
- #vif = "vnet11"
- #brname = "cloudbr0"
- #sec_ips = "10.11.118.133;10.11.118.135;10.11.118.138;" # end with ";" and separated by ";"
-
vm_ips = []
if sec_ips is not None:
vm_ips = sec_ips.split(';')
@@ -1452,7 +1499,6 @@
expected_rules = []
expected_rules.append("-A FORWARD -o %s -m physdev --physdev-is-bridged -j %s" % (brname, brfw))
expected_rules.append("-A FORWARD -i %s -m physdev --physdev-is-bridged -j %s" % (brname, brfw))
- expected_rules.append("-A %s -m state --state RELATED,ESTABLISHED -j ACCEPT" % (brfw))
expected_rules.append("-A %s -m physdev --physdev-is-in --physdev-is-bridged -j %s" % (brfw, brfwin))
expected_rules.append("-A %s -m physdev --physdev-is-out --physdev-is-bridged -j %s" % (brfw, brfwout))
phydev = get_bridge_physdev(brname)
@@ -1473,16 +1519,19 @@
expected_rules = []
expected_rules.append("-A %s -m physdev --physdev-in %s --physdev-is-bridged -j %s" % (brfwin, vif, vm_def))
expected_rules.append("-A %s -m physdev --physdev-out %s --physdev-is-bridged -j %s" % (brfwout, vif, vm_def))
- expected_rules.append("-A %s -m state --state RELATED,ESTABLISHED -j ACCEPT" % (vm_def))
expected_rules.append("-A %s -p udp -m physdev --physdev-in %s --physdev-is-bridged -m udp --sport 68 --dport 67 -j ACCEPT" % (vm_def, vif))
expected_rules.append("-A %s -p udp -m physdev --physdev-out %s --physdev-is-bridged -m udp --sport 67 --dport 68 -j ACCEPT" % (vm_def, vif))
expected_rules.append("-A %s -p udp -m physdev --physdev-in %s --physdev-is-bridged -m udp --sport 67 -j DROP" % (vm_def, vif))
expected_rules.append("-A %s -m physdev --physdev-in %s --physdev-is-bridged -m set ! --match-set %s src -j DROP" % (vm_def, vif, vm_name))
expected_rules.append("-A %s -m physdev --physdev-out %s --physdev-is-bridged -m set ! --match-set %s dst -j DROP" % (vm_def, vif, vm_name))
- expected_rules.append("-A %s -p udp -m physdev --physdev-in %s --physdev-is-bridged -m set --match-set %s src -m udp --dport 53 -j RETURN" % (vm_def, vif, vm_name))
- expected_rules.append("-A %s -p tcp -m physdev --physdev-in %s --physdev-is-bridged -m set --match-set %s src -m tcp --dport 53 -j RETURN" % (vm_def, vif, vm_name))
+ expected_rules.append("-A %s -p udp -m physdev --physdev-in %s --physdev-is-bridged -m set --match-set %s src -m udp --dport 53 -j ACCEPT" % (vm_def, vif, vm_name))
+ expected_rules.append("-A %s -p tcp -m physdev --physdev-in %s --physdev-is-bridged -m set --match-set %s src -m tcp --dport 53 -j ACCEPT" % (vm_def, vif, vm_name))
expected_rules.append("-A %s -m physdev --physdev-in %s --physdev-is-bridged -m set --match-set %s src -j %s" % (vm_def, vif, vm_name, vmchain_egress))
expected_rules.append("-A %s -m physdev --physdev-out %s --physdev-is-bridged -j %s" % (vm_def, vif, vmchain))
+ expected_rules.append("-A %s -m physdev --physdev-in %s -m state --state RELATED,ESTABLISHED -j ACCEPT" % (vm_def, vif))
+ expected_rules.append("-A %s -m physdev --physdev-out %s -m state --state RELATED,ESTABLISHED -j ACCEPT" % (vm_def, vif))
+ expected_rules.append("-A %s -m physdev --physdev-in %s -j DROP" % (vm_def, vif))
+ expected_rules.append("-A %s -m physdev --physdev-out %s -j DROP" % (vm_def, vif))
rules = execute("iptables-save |grep -E \"%s|%s\" |grep -v \"^:\"" % (vm_name, vm_def)).split('\n')
@@ -1634,7 +1683,7 @@
elif cmd == "default_network_rules" and not args.check:
default_network_rules(args.vmName, args.vmID, args.vmIP, args.vmIP6, args.vmMAC, args.vif, args.brname, args.nicSecIps, args.isFirstNic)
elif cmd == "destroy_network_rules_for_vm":
- if args.vmIP is None:
+ if not args.vmIP:
destroy_network_rules_for_vm(args.vmName, args.vif)
else:
destroy_network_rules_for_nic(args.vmName, args.vmIP, args.vmMAC, args.vif, args.nicSecIps)
diff --git a/scripts/vm/network/vnet/ovstunnel.py b/scripts/vm/network/vnet/ovstunnel.py
index a39b6b1..b47455b 100755
--- a/scripts/vm/network/vnet/ovstunnel.py
+++ b/scripts/vm/network/vnet/ovstunnel.py
@@ -49,17 +49,14 @@
logging.debug("Bridge has been manually created:%s" % res)
if res:
-# result = "FAILURE:%s" % res
result = 'false'
else:
# Verify the bridge actually exists, with the gre_key properly set
res = lib.do_cmd([lib.VSCTL_PATH, "get", "bridge",
bridge, "other_config:gre_key"])
if key in str(res):
-# result = "SUCCESS:%s" % bridge
result = 'true'
else:
-# result = "FAILURE:%s" % res
result = 'false'
lib.do_cmd([lib.VSCTL_PATH, "set", "bridge", bridge, "other_config:is-ovs-tun-network=True"])
@@ -134,10 +131,8 @@
res = lib.do_cmd([lib.VSCTL_PATH, "del-br", bridge])
logging.debug("Bridge has been manually removed:%s" % res)
if res:
-# result = "FAILURE:%s" % res
result = 'false'
else:
-# result = "SUCCESS:%s" % bridge
result = 'true'
logging.debug("Destroy_ovs_bridge completed with result:%s" % result)
@@ -150,7 +145,6 @@
res = lib.check_switch()
if res != "SUCCESS":
logging.debug("Openvswitch running: NO")
-# return "FAILURE:%s" % res
return 'false'
# We need to keep the name below 14 characters
@@ -189,7 +183,6 @@
if len(iface_list) != 1:
logging.debug("WARNING: Unexpected output while verifying " +
"port %s on bridge %s" % (name, bridge))
-# return "FAILURE:VERIFY_PORT_FAILED"
return 'false'
# verify interface
@@ -205,7 +198,6 @@
if key not in str(key_validation) or remote_ip not in str(ip_validation):
logging.debug("WARNING: Unexpected output while verifying " +
"interface %s on bridge %s" % (name, bridge))
-# return "FAILURE:VERIFY_INTERFACE_FAILED"
return 'false'
logging.debug("Tunnel interface validated:%s" % verify_interface_ip)
@@ -268,7 +260,6 @@
ofport = get_field_of_interface(iface_name, "ofport")
lib.del_flows(bridge, in_port=ofport)
lib.del_port(bridge, iface_name)
-# return "SUCCESS"
return 'true'
def get_field_of_interface(iface_name, field):
diff --git a/server/pom.xml b/server/pom.xml
index 3324cdb..2b35a0f 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -194,7 +194,7 @@
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-framework-extensions</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
diff --git a/server/src/main/java/com/cloud/acl/DomainChecker.java b/server/src/main/java/com/cloud/acl/DomainChecker.java
index 24b6346..0500960 100644
--- a/server/src/main/java/com/cloud/acl/DomainChecker.java
+++ b/server/src/main/java/com/cloud/acl/DomainChecker.java
@@ -32,6 +32,8 @@
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
import org.springframework.stereotype.Component;
+import org.apache.cloudstack.backup.dao.BackupOfferingDetailsDao;
+import org.apache.cloudstack.backup.BackupOffering;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DedicatedResourceVO;
import com.cloud.dc.dao.DedicatedResourceDao;
@@ -70,6 +72,8 @@
@Inject
DomainDao _domainDao;
@Inject
+ BackupOfferingDetailsDao backupOfferingDetailsDao;
+ @Inject
AccountDao _accountDao;
@Inject
LaunchPermissionDao _launchPermissionDao;
@@ -475,6 +479,35 @@
}
@Override
+ public boolean checkAccess(Account account, BackupOffering backupOffering) throws PermissionDeniedException {
+ boolean hasAccess = false;
+ if (account == null || backupOffering == null) {
+ hasAccess = true;
+ } else {
+ if (_accountService.isRootAdmin(account.getId())) {
+ hasAccess = true;
+ }
+ else if (_accountService.isNormalUser(account.getId())
+ || account.getType() == Account.Type.RESOURCE_DOMAIN_ADMIN
+ || _accountService.isDomainAdmin(account.getId())
+ || account.getType() == Account.Type.PROJECT) {
+ final List<Long> boDomainIds = backupOfferingDetailsDao.findDomainIds(backupOffering.getId());
+ if (boDomainIds.isEmpty()) {
+ hasAccess = true;
+ } else {
+ for (Long domainId : boDomainIds) {
+ if (_domainDao.isChildDomain(domainId, account.getDomainId())) {
+ hasAccess = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return hasAccess;
+ }
+
+ @Override
public boolean checkAccess(Account account, DataCenter zone) throws PermissionDeniedException {
if (account == null || zone.getDomainId() == null) {//public zone
return true;
diff --git a/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
index 85baf1b..1110804 100644
--- a/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
+++ b/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
@@ -298,7 +298,7 @@
protected List<Host> allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, ServiceOffering offering, VMTemplateVO template, ExcludeList avoid, List<? extends Host> hosts, int returnUpTo,
boolean considerReservedCapacity, Account account) {
String vmAllocationAlgorithm = DeploymentClusterPlanner.VmAllocationAlgorithm.value();
- if (vmAllocationAlgorithm.equals("random") || vmAllocationAlgorithm.equals("userconcentratedpod_random")) {
+ if (vmAllocationAlgorithm.equals("random")) {
// Shuffle this so that we don't check the hosts in the same order.
Collections.shuffle(hosts);
} else if (vmAllocationAlgorithm.equals("userdispersing")) {
diff --git a/server/src/main/java/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java b/server/src/main/java/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java
index b5fb77c..737d696 100644
--- a/server/src/main/java/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java
+++ b/server/src/main/java/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java
@@ -297,8 +297,6 @@
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
Map<String, String> configs = _configDao.getConfiguration("management-server", params);
String stoppedValue = configs.get("vm.resource.release.interval");
- // String destroyedValue =
- // configs.get("capacity.skipcounting.destroyed.hours");
String destroyedValue = null;
_secondsToSkipStoppedVMs = NumbersUtil.parseInt(stoppedValue, 86400);
_secondsToSkipDestroyedVMs = NumbersUtil.parseInt(destroyedValue, 0);
diff --git a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java
index 3eab3fb..27b445b 100644
--- a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java
+++ b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java
@@ -19,7 +19,6 @@
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -37,15 +36,12 @@
import javax.mail.MessagingException;
import javax.naming.ConfigurationException;
-import com.cloud.dc.DataCenter;
-import com.cloud.dc.Pod;
-import com.cloud.org.Cluster;
-
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.framework.config.ConfigDepot;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@@ -54,6 +50,7 @@
import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -70,9 +67,11 @@
import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.dc.ClusterVO;
+import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
+import com.cloud.dc.Pod;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
@@ -86,10 +85,12 @@
import com.cloud.host.dao.HostDao;
import com.cloud.network.Ipv6Service;
import com.cloud.network.dao.IPAddressDao;
+import com.cloud.org.Cluster;
import com.cloud.org.Grouping.AllocationState;
import com.cloud.resource.ResourceManager;
import com.cloud.storage.StorageManager;
import com.cloud.utils.Pair;
+import com.cloud.utils.Ternary;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.SearchCriteria;
@@ -100,20 +101,6 @@
public class AlertManagerImpl extends ManagerBase implements AlertManager, Configurable {
protected Logger logger = LogManager.getLogger(AlertManagerImpl.class.getName());
- public static final List<AlertType> ALERTS = Arrays.asList(AlertType.ALERT_TYPE_HOST
- , AlertType.ALERT_TYPE_USERVM
- , AlertType.ALERT_TYPE_DOMAIN_ROUTER
- , AlertType.ALERT_TYPE_CONSOLE_PROXY
- , AlertType.ALERT_TYPE_SSVM
- , AlertType.ALERT_TYPE_STORAGE_MISC
- , AlertType.ALERT_TYPE_MANAGEMENT_NODE
- , AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED
- , AlertType.ALERT_TYPE_UPLOAD_FAILED
- , AlertType.ALERT_TYPE_OOBM_AUTH_ERROR
- , AlertType.ALERT_TYPE_HA_ACTION
- , AlertType.ALERT_TYPE_CA_CERT
- , AlertType.ALERT_TYPE_EXTENSION_PATH_NOT_READY);
-
private static final long INITIAL_CAPACITY_CHECK_DELAY = 30L * 1000L; // Thirty seconds expressed in milliseconds.
private static final DecimalFormat DfPct = new DecimalFormat("###.##");
@@ -155,6 +142,8 @@
Ipv6Service ipv6Service;
@Inject
HostDao hostDao;
+ @Inject
+ MessageBus messageBus;
private Timer _timer = null;
private long _capacityCheckPeriod = 60L * 60L * 1000L; // One hour by default.
@@ -174,6 +163,8 @@
protected String[] recipients = null;
protected String senderAddress = null;
+ private final List<String> allowedRepetitiveAlertTypeNames = new ArrayList<>();
+
public AlertManagerImpl() {
_executor = Executors.newCachedThreadPool(new NamedThreadFactory("Email-Alerts-Sender"));
}
@@ -253,12 +244,32 @@
_capacityCheckPeriod = Long.parseLong(Config.CapacityCheckPeriod.getDefaultValue());
}
}
+ initMessageBusListener();
+ setupRepetitiveAlertTypes();
_timer = new Timer("CapacityChecker");
return true;
}
+ protected void setupRepetitiveAlertTypes() {
+ allowedRepetitiveAlertTypeNames.clear();
+ String allowedRepetitiveAlertsStr = AllowedRepetitiveAlertTypes.value();
+ logger.trace("Allowed repetitive alert types specified by {}: {} ", AllowedRepetitiveAlertTypes.key(),
+ allowedRepetitiveAlertsStr);
+ if (StringUtils.isBlank(allowedRepetitiveAlertsStr)) {
+ return;
+ }
+ String[] allowedRepetitiveAlertTypesArray = allowedRepetitiveAlertsStr.split(",");
+ for (String allowedTypeName : allowedRepetitiveAlertTypesArray) {
+ if (StringUtils.isBlank(allowedTypeName)) {
+ continue;
+ }
+ allowedRepetitiveAlertTypeNames.add(allowedTypeName.toLowerCase());
+ }
+ logger.trace("{} alert types specified for repetitive alerts", allowedRepetitiveAlertTypeNames.size());
+ }
+
@Override
public boolean start() {
_timer.schedule(new CapacityChecker(), INITIAL_CAPACITY_CHECK_DELAY, _capacityCheckPeriod);
@@ -849,11 +860,11 @@
@Nullable
private AlertVO getAlertForTrivialAlertType(AlertType alertType, long dataCenterId, Long podId, Long clusterId) {
- AlertVO alert = null;
- if (!ALERTS.contains(alertType)) {
- alert = _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId);
+ if (alertType.isRepetitionAllowed() || (StringUtils.isNotBlank(alertType.getName()) &&
+ allowedRepetitiveAlertTypeNames.contains(alertType.getName().toLowerCase()))) {
+ return null;
}
- return alert;
+ return _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId);
}
protected void sendMessage(SMTPMailProperties mailProps) {
@@ -882,7 +893,7 @@
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {CPUCapacityThreshold, MemoryCapacityThreshold, StorageAllocatedCapacityThreshold, StorageCapacityThreshold, AlertSmtpEnabledSecurityProtocols,
- AlertSmtpUseStartTLS, Ipv6SubnetCapacityThreshold, AlertSmtpUseAuth};
+ AlertSmtpUseStartTLS, Ipv6SubnetCapacityThreshold, AlertSmtpUseAuth, AllowedRepetitiveAlertTypes};
}
@Override
@@ -896,4 +907,16 @@
return false;
}
}
+
+ @SuppressWarnings("unchecked")
+ protected void initMessageBusListener() {
+ messageBus.subscribe(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, (senderAddress, subject, args) -> {
+ Ternary<String, ConfigKey.Scope, Long> updatedSetting = (Ternary<String, ConfigKey.Scope, Long>) args;
+ String updatedSettingName = updatedSetting.first();
+ if (!AllowedRepetitiveAlertTypes.key().equals(updatedSettingName)) {
+ return;
+ }
+ setupRepetitiveAlertTypes();
+ });
+ }
}
diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java b/server/src/main/java/com/cloud/api/ApiDBUtils.java
index f7ffb03..57eeb63 100644
--- a/server/src/main/java/com/cloud/api/ApiDBUtils.java
+++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java
@@ -1767,7 +1767,7 @@
return null;
}
String jobInstanceId = null;
- ApiCommandResourceType jobInstanceType = EnumUtils.fromString(ApiCommandResourceType.class, job.getInstanceType(), ApiCommandResourceType.None);
+ ApiCommandResourceType jobInstanceType = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, job.getInstanceType(), ApiCommandResourceType.None);
if (job.getInstanceId() == null) {
// when assert is hit, implement 'getInstanceId' of BaseAsyncCmd and return appropriate instance id
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index e0dcc57..655f5ac 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -39,18 +39,6 @@
import javax.inject.Inject;
-import com.cloud.bgp.ASNumber;
-import com.cloud.bgp.ASNumberRange;
-import com.cloud.configuration.ConfigurationService;
-import com.cloud.dc.ASNumberRangeVO;
-import com.cloud.dc.ASNumberVO;
-import com.cloud.dc.VlanDetailsVO;
-import com.cloud.dc.dao.ASNumberDao;
-import com.cloud.dc.dao.ASNumberRangeDao;
-import com.cloud.dc.dao.VlanDetailsDao;
-import com.cloud.hypervisor.Hypervisor;
-import com.cloud.network.vpc.VpcGateway;
-import com.cloud.storage.BucketVO;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.affinity.AffinityGroup;
@@ -276,14 +264,19 @@
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.api.query.vo.VpcOfferingJoinVO;
import com.cloud.api.response.ApiResponseSerializer;
+import com.cloud.bgp.ASNumber;
+import com.cloud.bgp.ASNumberRange;
import com.cloud.capacity.Capacity;
import com.cloud.capacity.CapacityVO;
import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity;
import com.cloud.configuration.ConfigurationManager;
+import com.cloud.configuration.ConfigurationService;
import com.cloud.configuration.Resource.ResourceOwnerType;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.configuration.ResourceCount;
import com.cloud.configuration.ResourceLimit;
+import com.cloud.dc.ASNumberRangeVO;
+import com.cloud.dc.ASNumberVO;
import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenter;
@@ -294,7 +287,11 @@
import com.cloud.dc.StorageNetworkIpRange;
import com.cloud.dc.Vlan;
import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.VlanDetailsVO;
import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.ASNumberDao;
+import com.cloud.dc.dao.ASNumberRangeDao;
+import com.cloud.dc.dao.VlanDetailsDao;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.event.Event;
@@ -303,6 +300,7 @@
import com.cloud.host.ControlState;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
+import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.HypervisorCapabilities;
import com.cloud.network.GuestVlan;
import com.cloud.network.GuestVlanRange;
@@ -366,9 +364,11 @@
import com.cloud.network.vpc.PrivateGateway;
import com.cloud.network.vpc.StaticRoute;
import com.cloud.network.vpc.Vpc;
+import com.cloud.network.vpc.VpcGateway;
import com.cloud.network.vpc.VpcOffering;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcOfferingDao;
+import com.cloud.network.vpn.Site2SiteVpnManager;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.NetworkOffering.Detail;
@@ -387,6 +387,7 @@
import com.cloud.server.ResourceTag;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.service.ServiceOfferingVO;
+import com.cloud.storage.BucketVO;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.GuestOS;
@@ -528,6 +529,8 @@
@Inject
RoutedIpv4Manager routedIpv4Manager;
@Inject
+ Site2SiteVpnManager site2SiteVpnManager;
+ @Inject
ResourceIconManager resourceIconManager;
public static String getPrettyDomainPath(String path) {
@@ -583,6 +586,7 @@
if (domain.getChildCount() > 0) {
domainResponse.setHasChild(true);
}
+ populateDomainTags(domain.getUuid(), domainResponse);
domainResponse.setObjectName("domain");
return domainResponse;
}
@@ -1880,6 +1884,8 @@
vmResponse.setPublicNetmask(singleNicProfile.getIPv4Netmask());
vmResponse.setGateway(singleNicProfile.getIPv4Gateway());
}
+ } else if (network.getTrafficType() == TrafficType.Storage) {
+ vmResponse.setStorageIp(singleNicProfile.getIPv4Address());
}
}
}
@@ -3045,6 +3051,20 @@
response.setDomainPath(getPrettyDomainPath(object.getDomainPath()));
}
+ public static void populateDomainTags(String domainUuid, DomainResponse domainResponse) {
+ List<ResourceTagJoinVO> tags = ApiDBUtils.listResourceTagViewByResourceUUID(domainUuid,
+ ResourceTag.ResourceObjectType.Domain);
+ if (CollectionUtils.isEmpty(tags)) {
+ return;
+ }
+ Set<ResourceTagResponse> tagResponses = new HashSet<>();
+ for (ResourceTagJoinVO tag : tags) {
+ ResourceTagResponse tagResponse = ApiDBUtils.newResourceTagResponse(tag, true);
+ tagResponses.add(tagResponse);
+ }
+ domainResponse.setTags(tagResponses);
+ }
+
private void populateAccount(ControlledEntityResponse response, long accountId) {
Account account = ApiDBUtils.findAccountById(accountId);
if (account == null) {
@@ -3256,6 +3276,9 @@
PhysicalNetwork pnet = ApiDBUtils.findPhysicalNetworkById(result.getPhysicalNetworkId());
if (pnet != null) {
response.setPhysicalNetworkId(pnet.getUuid());
+ if (!pnet.getIsolationMethods().isEmpty()) {
+ response.setIsolationMethods(String.join(",", pnet.getIsolationMethods()));
+ }
}
if (result.getTrafficType() != null) {
response.setTrafficType(result.getTrafficType().toString());
@@ -3266,6 +3289,7 @@
response.setVmwareLabel(result.getVmwareNetworkLabel());
response.setHypervLabel(result.getHypervNetworkLabel());
response.setOvm3Label(result.getOvm3NetworkLabel());
+ response.setVlan(result.getVlan());
response.setObjectName("traffictype");
return response;
@@ -3880,6 +3904,16 @@
response.setRemoved(result.getRemoved());
response.setIkeVersion(result.getIkeVersion());
response.setSplitConnections(result.getSplitConnections());
+
+ Set<String> obsoleteParameters = site2SiteVpnManager.getObsoleteVpnGatewayParameters(result);
+ if (CollectionUtils.isNotEmpty(obsoleteParameters)) {
+ response.setContainsObsoleteParameters(obsoleteParameters.toString());
+ }
+ Set<String> excludedParameters = site2SiteVpnManager.getExcludedVpnGatewayParameters(result);
+ if (CollectionUtils.isNotEmpty(excludedParameters)) {
+ response.setContainsExcludedParameters(excludedParameters.toString());
+ }
+
response.setObjectName("vpncustomergateway");
response.setHasAnnotation(annotationDao.hasAnnotations(result.getUuid(), AnnotationService.EntityType.VPN_CUSTOMER_GATEWAY.name(),
_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())));
diff --git a/server/src/main/java/com/cloud/api/ApiServer.java b/server/src/main/java/com/cloud/api/ApiServer.java
index 5a3c8c2..95aca28 100644
--- a/server/src/main/java/com/cloud/api/ApiServer.java
+++ b/server/src/main/java/com/cloud/api/ApiServer.java
@@ -461,14 +461,14 @@
final Long snapshotLimit = ConcurrentSnapshotsThresholdPerHost.value();
if (snapshotLimit == null || snapshotLimit <= 0) {
- logger.debug("Global concurrent snapshot config parameter " + ConcurrentSnapshotsThresholdPerHost.value() + " is less or equal 0; defaulting to unlimited");
+ logger.debug("Global concurrent snapshot config parameter {} is less or equal 0; defaulting to unlimited", ConcurrentSnapshotsThresholdPerHost.value());
} else {
dispatcher.setCreateSnapshotQueueSizeLimit(snapshotLimit);
}
final Long migrationLimit = VolumeApiService.ConcurrentMigrationsThresholdPerDatastore.value();
if (migrationLimit == null || migrationLimit <= 0) {
- logger.debug("Global concurrent migration config parameter " + VolumeApiService.ConcurrentMigrationsThresholdPerDatastore.value() + " is less or equal 0; defaulting to unlimited");
+ logger.debug("Global concurrent migration config parameter {} is less or equal 0; defaulting to unlimited", VolumeApiService.ConcurrentMigrationsThresholdPerDatastore.value());
} else {
dispatcher.setMigrateQueueSizeLimit(migrationLimit);
}
@@ -647,7 +647,7 @@
logValue = (value == null) ? "'null'" : value[0];
}
- logger.trace(" key: " + keyStr + ", value: " + logValue);
+ logger.trace(" key: {}, value: {}", keyStr, logValue);
}
}
throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent");
@@ -707,7 +707,7 @@
buf.append(obj.getUuid());
buf.append(" ");
}
- logger.info("PermissionDenied: " + ex.getMessage() + " on objs: [" + buf + "]");
+ logger.info("PermissionDenied: {} on objs: [{}]", ex.getMessage(), buf);
} else {
logger.info("PermissionDenied: {}", ex.getMessage());
}
@@ -1035,7 +1035,7 @@
// if api/secret key are passed to the parameters
if ((signature == null) || (apiKey == null)) {
- logger.debug("Expired session, missing signature, or missing apiKey -- ignoring request. Signature: " + signature + ", apiKey: " + apiKey);
+ logger.warn("Expired session, missing signature, or missing apiKey -- ignoring request. Signature: {}, apiKey: {}", signature, apiKey);
return false; // no signature, bad request
}
@@ -1258,7 +1258,7 @@
float offsetInHrs = 0f;
if (timezone != null) {
final TimeZone t = TimeZone.getTimeZone(timezone);
- logger.info("Current user logged in under " + timezone + " timezone");
+ logger.info("Current user logged in under {} timezone", timezone);
final java.util.Date date = new java.util.Date();
final long longDate = date.getTime();
@@ -1410,9 +1410,9 @@
final Boolean apiSourceCidrChecksEnabled = ApiServiceConfiguration.ApiSourceCidrChecksEnabled.value();
if (apiSourceCidrChecksEnabled) {
- logger.debug("CIDRs from which account '" + account.toString() + "' is allowed to perform API calls: " + accessAllowedCidrs);
+ logger.debug("CIDRs from which account '{}' is allowed to perform API calls: {}", account.toString(), accessAllowedCidrs);
if (!NetUtils.isIpInCidrList(remoteAddress, accessAllowedCidrs.split(","))) {
- logger.warn("Request by account '" + account.toString() + "' was denied since " + remoteAddress + " does not match " + accessAllowedCidrs);
+ logger.warn("Request by account '{}' was denied since {} does not match {}", account.toString(), remoteAddress, accessAllowedCidrs);
throw new OriginDeniedException("Calls from disallowed origin", account, remoteAddress);
}
}
diff --git a/server/src/main/java/com/cloud/api/ApiServlet.java b/server/src/main/java/com/cloud/api/ApiServlet.java
index db17daa..158df22 100644
--- a/server/src/main/java/com/cloud/api/ApiServlet.java
+++ b/server/src/main/java/com/cloud/api/ApiServlet.java
@@ -25,8 +25,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.regex.Pattern;
import java.util.Set;
+import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.servlet.ServletConfig;
@@ -52,10 +52,9 @@
import org.apache.cloudstack.managed.context.ManagedContext;
import org.apache.cloudstack.utils.consoleproxy.ConsoleAccessUtils;
import org.apache.commons.collections.MapUtils;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.LogManager;
import org.apache.commons.lang3.EnumUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
@@ -70,12 +69,12 @@
import com.cloud.user.AccountService;
import com.cloud.user.User;
import com.cloud.user.UserAccount;
-
import com.cloud.utils.HttpUtils;
-import com.cloud.utils.HttpUtils.ApiSessionKeySameSite;
import com.cloud.utils.HttpUtils.ApiSessionKeyCheckOption;
+import com.cloud.utils.HttpUtils.ApiSessionKeySameSite;
import com.cloud.utils.StringUtils;
import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
@Component("apiServlet")
@@ -84,9 +83,7 @@
private static final Logger ACCESSLOGGER = LogManager.getLogger("apiserver." + ApiServlet.class.getName());
private static final String REPLACEMENT = "_";
private static final String LOGGER_REPLACEMENTS = "[\n\r\t]";
- private static final Pattern GET_REQUEST_COMMANDS = Pattern.compile("^(get|list|query|find)(\\w+)+$");
- private static final HashSet<String> GET_REQUEST_COMMANDS_LIST = new HashSet<>(Set.of("isaccountallowedtocreateofferingswithtags",
- "readyforshutdown", "cloudianisenabled", "quotabalance", "quotasummary", "quotatarifflist", "quotaisenabled", "quotastatement", "verifyoauthcodeandgetuser"));
+ public static final Pattern GET_REQUEST_COMMANDS = Pattern.compile("^(get|list|query|find)(\\w+)+$");
private static final HashSet<String> POST_REQUESTS_TO_DISABLE_LOGGING = new HashSet<>(Set.of(
"login",
"oauthlogin",
@@ -367,7 +364,7 @@
}
}
- if (apiServer.isPostRequestsAndTimestampsEnforced() && !isStateChangingCommandUsingPOST(command, req.getMethod(), params)) {
+ if (apiServer.isPostRequestsAndTimestampsEnforced() && isStateChangingCommandNotUsingPOST(command, req.getMethod(), params)) {
String errorText = String.format("State changing command %s needs to be sent using POST request", command);
if (command.equalsIgnoreCase("updateConfiguration") && params.containsKey("name")) {
errorText = String.format("Changes for configuration %s needs to be sent using POST request", params.get("name")[0]);
@@ -485,13 +482,32 @@
return verify2FA;
}
- private boolean isStateChangingCommandUsingPOST(String command, String method, Map<String, Object[]> params) {
- if (command == null || (!GET_REQUEST_COMMANDS.matcher(command.toLowerCase()).matches() && !GET_REQUEST_COMMANDS_LIST.contains(command.toLowerCase())
- && !command.equalsIgnoreCase("updateConfiguration") && !method.equals("POST"))) {
+ protected boolean isStateChangingCommandNotUsingPOST(String command, String method, Map<String, Object[]> params) {
+ if (BaseCmd.HTTPMethod.POST.toString().equalsIgnoreCase(method)) {
return false;
}
- return !command.equalsIgnoreCase("updateConfiguration") || method.equals("POST") || (params.containsKey("name")
- && params.get("name")[0].toString().equalsIgnoreCase(ApiServer.EnforcePostRequestsAndTimestamps.key()));
+ if (command == null || method == null) {
+ return true;
+ }
+ String commandHttpMethod = null;
+ try {
+ Class<?> cmdClass = apiServer.getCmdClass(command);
+ if (cmdClass != null) {
+ APICommand at = cmdClass.getAnnotation(APICommand.class);
+ if (at != null && org.apache.commons.lang3.StringUtils.isNotBlank(at.httpMethod())) {
+ commandHttpMethod = at.httpMethod();
+ }
+ }
+ } catch (CloudRuntimeException e) {
+ LOGGER.trace("Command class not found for {}; falling back to pattern match", command, e);
+ }
+ if (BaseCmd.HTTPMethod.GET.toString().equalsIgnoreCase(commandHttpMethod) ||
+ GET_REQUEST_COMMANDS.matcher(command.toLowerCase()).matches()) {
+ return false;
+ }
+ return !command.equalsIgnoreCase("updateConfiguration") ||
+ !params.containsKey("name") ||
+ !ApiServer.EnforcePostRequestsAndTimestamps.key().equalsIgnoreCase(params.get("name")[0].toString());
}
protected boolean skip2FAcheckForAPIs(String command) {
diff --git a/server/src/main/java/com/cloud/api/doc/ApiXmlDocWriter.java b/server/src/main/java/com/cloud/api/doc/ApiXmlDocWriter.java
index 5de5cd0..87d88df 100644
--- a/server/src/main/java/com/cloud/api/doc/ApiXmlDocWriter.java
+++ b/server/src/main/java/com/cloud/api/doc/ApiXmlDocWriter.java
@@ -77,13 +77,11 @@
List<String> asyncResponses = new ArrayList<String>();
asyncResponses.add(TemplateResponse.class.getName());
asyncResponses.add(VolumeResponse.class.getName());
- //asyncResponses.add(LoadBalancerResponse.class.getName());
asyncResponses.add(HostResponse.class.getName());
asyncResponses.add(IPAddressResponse.class.getName());
asyncResponses.add(StoragePoolResponse.class.getName());
asyncResponses.add(UserVmResponse.class.getName());
asyncResponses.add(SecurityGroupResponse.class.getName());
- //asyncResponses.add(ExternalLoadBalancerResponse.class.getName());
asyncResponses.add(SnapshotResponse.class.getName());
return asyncResponses;
diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
index d42dbae..6713a7d 100644
--- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
@@ -2106,7 +2106,7 @@
}
if (domainId != null && !domainId.equals(caller.getDomainId())) {
- throw new PermissionDeniedException("Can't list domain id= " + domainId + " projects; unauthorized");
+ throw new PermissionDeniedException("Can't list domain ID = " + domainId + " projects; unauthorized");
}
if (StringUtils.isNotEmpty(username) && !username.equals(user.getUsername())) {
@@ -2868,6 +2868,7 @@
boolean listAll = cmd.listAll();
boolean isRecursive = false;
Domain domain = null;
+ Map<String, String> tags = cmd.getTags();
if (domainId != null) {
domain = _domainDao.findById(domainId);
@@ -2897,6 +2898,24 @@
domainSearchBuilder.and("path", domainSearchBuilder.entity().getPath(), SearchCriteria.Op.LIKE);
domainSearchBuilder.and("state", domainSearchBuilder.entity().getState(), SearchCriteria.Op.EQ);
+ if (MapUtils.isNotEmpty(tags)) {
+ SearchBuilder<ResourceTagVO> resourceTagSearch = resourceTagDao.createSearchBuilder();
+ resourceTagSearch.and("resourceType", resourceTagSearch.entity().getResourceType(), Op.EQ);
+ resourceTagSearch.and().op();
+ for (int count = 0; count < tags.size(); count++) {
+ if (count == 0) {
+ resourceTagSearch.op("tagKey" + count, resourceTagSearch.entity().getKey(), Op.EQ);
+ } else {
+ resourceTagSearch.or().op("tagKey" + count, resourceTagSearch.entity().getKey(), Op.EQ);
+ }
+ resourceTagSearch.and("tagValue" + count, resourceTagSearch.entity().getValue(), Op.EQ);
+ resourceTagSearch.cp();
+ }
+ resourceTagSearch.cp();
+
+ domainSearchBuilder.join("tags", resourceTagSearch, resourceTagSearch.entity().getResourceId(), domainSearchBuilder.entity().getId(), JoinBuilder.JoinType.INNER);
+ }
+
if (keyword != null) {
domainSearchBuilder.and("keywordName", domainSearchBuilder.entity().getName(), SearchCriteria.Op.LIKE);
}
@@ -2926,6 +2945,16 @@
}
}
+ if (MapUtils.isNotEmpty(tags)) {
+ int count = 0;
+ sc.setJoinParameters("tags", "resourceType", ResourceObjectType.Domain);
+ for (Map.Entry<String, String> entry : tags.entrySet()) {
+ sc.setJoinParameters("tags", "tagKey" + count, entry.getKey());
+ sc.setJoinParameters("tags", "tagValue" + count, entry.getValue());
+ count++;
+ }
+ }
+
// return only Active domains to the API
sc.setParameters("state", Domain.State.Active);
@@ -5411,6 +5440,10 @@
options.put(VmDetailConstants.RAM_RESERVATION, Collections.emptyList());
options.put(VmDetailConstants.VIRTUAL_TPM_ENABLED, Arrays.asList("true", "false"));
}
+
+ if (HypervisorType.XenServer.equals(hypervisorType)) {
+ options.put(VmDetailConstants.VIRTUAL_TPM_ENABLED, Arrays.asList("true", "false"));
+ }
}
@Override
diff --git a/server/src/main/java/com/cloud/api/query/dao/DomainJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DomainJoinDaoImpl.java
index d4865c5..b6a3370 100644
--- a/server/src/main/java/com/cloud/api/query/dao/DomainJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/DomainJoinDaoImpl.java
@@ -20,10 +20,8 @@
import java.util.EnumSet;
import java.util.List;
+import javax.inject.Inject;
-import com.cloud.api.ApiResponseHelper;
-import com.cloud.configuration.Resource;
-import com.cloud.user.AccountManager;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiConstants.DomainDetails;
@@ -35,15 +33,16 @@
import org.springframework.stereotype.Component;
import com.cloud.api.ApiDBUtils;
+import com.cloud.api.ApiResponseHelper;
import com.cloud.api.query.vo.DomainJoinVO;
+import com.cloud.configuration.Resource;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.domain.Domain;
+import com.cloud.user.AccountManager;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
-import javax.inject.Inject;
-
@Component
public class DomainJoinDaoImpl extends GenericDaoBase<DomainJoinVO, Long> implements DomainJoinDao {
@@ -110,6 +109,7 @@
}
domainResponse.setDetails(ApiDBUtils.getDomainDetails(domain.getId()));
+ ApiResponseHelper.populateDomainTags(domain.getUuid(), domainResponse);
domainResponse.setObjectName("domain");
return domainResponse;
diff --git a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java
index 2de9abc..2940f90 100644
--- a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java
+++ b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java
@@ -50,7 +50,6 @@
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.StartupCommand;
-import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.configuration.Config;
import com.cloud.dc.ClusterDetailsDao;
@@ -82,7 +81,6 @@
import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB;
-import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionStatus;
@@ -167,11 +165,6 @@
return true;
}
- @Override
- public boolean stop() {
- return true;
- }
-
@DB
@Override
public boolean releaseVmCapacity(VirtualMachine vm, final boolean moveFromReserved, final boolean moveToReservered, final Long hostId) {
@@ -395,8 +388,8 @@
long cluster_id = host.getClusterId();
ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id, VmDetailConstants.CPU_OVER_COMMIT_RATIO);
ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id, VmDetailConstants.MEMORY_OVER_COMMIT_RATIO);
- Float cpuOvercommitRatio = Float.parseFloat(cluster_detail_cpu.getValue());
- Float memoryOvercommitRatio = Float.parseFloat(cluster_detail_ram.getValue());
+ float cpuOvercommitRatio = Float.parseFloat(cluster_detail_cpu.getValue());
+ float memoryOvercommitRatio = Float.parseFloat(cluster_detail_ram.getValue());
boolean hostHasCpuCapability, hostHasCapacity = false;
hostHasCpuCapability = checkIfHostHasCpuCapability(host, cpucore, cpuspeed);
@@ -424,14 +417,13 @@
if (e instanceof CloudRuntimeException) {
throw e;
}
- return;
}
}
@Override
public boolean checkIfHostHasCpuCapability(Host host, Integer cpuNum, Integer cpuSpeed) {
// Check host can support the Cpu Number and Speed.
- boolean isCpuNumGood = host.getCpus().intValue() >= cpuNum;
+ boolean isCpuNumGood = host.getCpus() >= cpuNum;
boolean isCpuSpeedGood = host.getSpeed().intValue() >= cpuSpeed;
boolean hasCpuCapability = isCpuNumGood && isCpuSpeedGood;
@@ -482,13 +474,10 @@
String failureReason = "";
if (checkFromReservedCapacity) {
- long freeCpu = reservedCpu;
- long freeMem = reservedMem;
-
if (logger.isDebugEnabled()) {
logger.debug("We need to allocate to the last host again, so checking if there is enough reserved capacity");
- logger.debug("Reserved CPU: " + freeCpu + " , Requested CPU: " + cpu);
- logger.debug("Reserved RAM: " + toHumanReadableSize(freeMem) + " , Requested RAM: " + toHumanReadableSize(ram));
+ logger.debug("Reserved CPU: " + reservedCpu + " , Requested CPU: " + cpu);
+ logger.debug("Reserved RAM: " + toHumanReadableSize(reservedMem) + " , Requested RAM: " + toHumanReadableSize(ram));
}
/* alloc from reserved */
if (reservedCpu >= cpu) {
@@ -586,7 +575,7 @@
@Override
public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateForVmCreation) {
- long totalAllocatedSize = 0;
+ long totalAllocatedSize;
// if the storage pool is managed, the used bytes can be larger than the sum of the sizes of all of the non-destroyed volumes
// in this case, call getUsedBytes(StoragePoolVO)
@@ -700,11 +689,11 @@
Pair<String, String> clusterValues =
clusterValuesCache.get(host.getClusterId());
- Float clusterCpuOvercommitRatio = Float.parseFloat(clusterValues.first());
- Float clusterRamOvercommitRatio = Float.parseFloat(clusterValues.second());
+ float clusterCpuOvercommitRatio = Float.parseFloat(clusterValues.first());
+ float clusterRamOvercommitRatio = Float.parseFloat(clusterValues.second());
for (VMInstanceVO vm : vms) {
- Float cpuOvercommitRatio = 1.0f;
- Float ramOvercommitRatio = 1.0f;
+ float cpuOvercommitRatio;
+ float ramOvercommitRatio;
Map<String, String> vmDetails = getVmDetailsForCapacityCalculation(vm.getId());
String vmDetailCpu = vmDetails.get(VmDetailConstants.CPU_OVER_COMMIT_RATIO);
String vmDetailRam = vmDetails.get(VmDetailConstants.MEMORY_OVER_COMMIT_RATIO);
@@ -717,21 +706,22 @@
}
if (so.isDynamic()) {
usedMemory +=
- ((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.memory.name())) * 1024L * 1024L) / ramOvercommitRatio) *
- clusterRamOvercommitRatio;
+ (long) (((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.memory.name())) * 1024L * 1024L)
+ / ramOvercommitRatio) * clusterRamOvercommitRatio);
if(vmDetails.containsKey(UsageEventVO.DynamicParameters.cpuSpeed.name())) {
usedCpu +=
- ((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuSpeed.name()))) / cpuOvercommitRatio) *
- clusterCpuOvercommitRatio;
+ (long) ((((long) Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name()))
+ * Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuSpeed.name())))
+ / cpuOvercommitRatio) * clusterCpuOvercommitRatio);
} else {
usedCpu +=
- ((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * so.getSpeed()) / cpuOvercommitRatio) *
- clusterCpuOvercommitRatio;
+ (long) ((((long) Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * so.getSpeed()) / cpuOvercommitRatio) *
+ clusterCpuOvercommitRatio);
}
usedCpuCore += Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name()));
} else {
- usedMemory += ((so.getRamSize() * 1024L * 1024L) / ramOvercommitRatio) * clusterRamOvercommitRatio;
- usedCpu += ((so.getCpu() * so.getSpeed()) / cpuOvercommitRatio) * clusterCpuOvercommitRatio;
+ usedMemory += (long) (((so.getRamSize() * 1024L * 1024L) / ramOvercommitRatio) * clusterRamOvercommitRatio);
+ usedCpu += (long) ((((long) so.getCpu() * so.getSpeed()) / cpuOvercommitRatio) * clusterCpuOvercommitRatio);
usedCpuCore += so.getCpu();
}
}
@@ -740,8 +730,8 @@
logger.debug("Found {} VM, not running on {}", vmsByLastHostId.size(), host);
for (VMInstanceVO vm : vmsByLastHostId) {
- Float cpuOvercommitRatio = 1.0f;
- Float ramOvercommitRatio = 1.0f;
+ float cpuOvercommitRatio = 1.0f;
+ float ramOvercommitRatio = 1.0f;
long lastModificationTime = Optional.ofNullable(vm.getUpdateTime()).orElse(vm.getCreated()).getTime();
long secondsSinceLastUpdate = (DateUtil.currentGMTTime().getTime() - lastModificationTime) / 1000;
if (secondsSinceLastUpdate < _vmCapacityReleaseInterval) {
@@ -761,28 +751,28 @@
}
if (so.isDynamic()) {
reservedMemory +=
- ((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.memory.name())) * 1024L * 1024L) / ramOvercommitRatio) *
- clusterRamOvercommitRatio;
+ (long) (((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.memory.name())) * 1024L * 1024L) / ramOvercommitRatio) *
+ clusterRamOvercommitRatio);
if(vmDetails.containsKey(UsageEventVO.DynamicParameters.cpuSpeed.name())) {
reservedCpu +=
- ((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuSpeed.name()))) / cpuOvercommitRatio) *
- clusterCpuOvercommitRatio;
+ (long) (((Long.parseLong(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuSpeed.name()))) / cpuOvercommitRatio) *
+ clusterCpuOvercommitRatio);
} else {
reservedCpu +=
- ((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * so.getSpeed()) / cpuOvercommitRatio) *
- clusterCpuOvercommitRatio;
+ (long) (((Long.parseLong(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * so.getSpeed()) / cpuOvercommitRatio) *
+ clusterCpuOvercommitRatio);
}
reservedCpuCore += Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name()));
} else {
- reservedMemory += ((so.getRamSize() * 1024L * 1024L) / ramOvercommitRatio) * clusterRamOvercommitRatio;
- reservedCpu += (so.getCpu() * so.getSpeed() / cpuOvercommitRatio) * clusterCpuOvercommitRatio;
+ reservedMemory += (long) (((so.getRamSize() * 1024L * 1024L) / ramOvercommitRatio) * clusterRamOvercommitRatio);
+ reservedCpu += (long) (((long) so.getCpu() * so.getSpeed() / cpuOvercommitRatio) * clusterCpuOvercommitRatio);
reservedCpuCore += so.getCpu();
}
} else {
// signal if not done already, that the VM has been stopped for skip.counting.hours,
// hence capacity will not be reserved anymore.
VMInstanceDetailVO messageSentFlag = _vmInstanceDetailsDao.findDetail(vm.getId(), VmDetailConstants.MESSAGE_RESERVED_CAPACITY_FREED_FLAG);
- if (messageSentFlag == null || !Boolean.valueOf(messageSentFlag.getValue())) {
+ if (messageSentFlag == null || !Boolean.parseBoolean(messageSentFlag.getValue())) {
_messageBus.publish(_name, "VM_ReservedCapacity_Free", PublishScope.LOCAL, vm);
if (vm.getType() == VirtualMachine.Type.User) {
@@ -859,7 +849,7 @@
if (host.getTotalMemory() != null) {
memCap.setTotalCapacity(host.getTotalMemory());
}
- long hostTotalCpu = host.getCpus().longValue() * host.getSpeed().longValue();
+ long hostTotalCpu = host.getCpus().longValue() * host.getSpeed();
if (cpuCap.getTotalCapacity() != hostTotalCpu) {
logger.debug("Calibrate total cpu for host: {} old total CPU:{} new total CPU:{}", host, cpuCap.getTotalCapacity(), hostTotalCpu);
@@ -938,7 +928,7 @@
capacity =
new CapacityVO(host.getId(), host.getDataCenterId(), host.getPodId(), host.getClusterId(), usedCpuFinal, host.getCpus().longValue() *
- host.getSpeed().longValue(), Capacity.CAPACITY_TYPE_CPU);
+ host.getSpeed(), Capacity.CAPACITY_TYPE_CPU);
capacity.setReservedCapacity(reservedCpuFinal);
capacity.setCapacityState(capacityState);
_capacityDao.persist(capacity);
@@ -1029,78 +1019,10 @@
return true;
}
- // TODO: Get rid of this case once we've determined that the capacity listeners above have all the changes
- // create capacity entries if none exist for this server
- private void createCapacityEntry(StartupCommand startup, HostVO server) {
- SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria();
- capacitySC.addAnd("hostOrPoolId", SearchCriteria.Op.EQ, server.getId());
- capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, server.getDataCenterId());
- capacitySC.addAnd("podId", SearchCriteria.Op.EQ, server.getPodId());
-
- if (startup instanceof StartupRoutingCommand) {
- SearchCriteria<CapacityVO> capacityCPU = _capacityDao.createSearchCriteria();
- capacityCPU.addAnd("hostOrPoolId", SearchCriteria.Op.EQ, server.getId());
- capacityCPU.addAnd("dataCenterId", SearchCriteria.Op.EQ, server.getDataCenterId());
- capacityCPU.addAnd("podId", SearchCriteria.Op.EQ, server.getPodId());
- capacityCPU.addAnd("capacityType", SearchCriteria.Op.EQ, Capacity.CAPACITY_TYPE_CPU);
- List<CapacityVO> capacityVOCpus = _capacityDao.search(capacitySC, null);
- Float cpuovercommitratio = Float.parseFloat(_clusterDetailsDao.findDetail(server.getClusterId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO).getValue());
- Float memoryOvercommitRatio = Float.parseFloat(_clusterDetailsDao.findDetail(server.getClusterId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO).getValue());
-
- if (capacityVOCpus != null && !capacityVOCpus.isEmpty()) {
- CapacityVO CapacityVOCpu = capacityVOCpus.get(0);
- long newTotalCpu = (long)(server.getCpus().longValue() * server.getSpeed().longValue() * cpuovercommitratio);
- if ((CapacityVOCpu.getTotalCapacity() <= newTotalCpu) || ((CapacityVOCpu.getUsedCapacity() + CapacityVOCpu.getReservedCapacity()) <= newTotalCpu)) {
- CapacityVOCpu.setTotalCapacity(newTotalCpu);
- } else if ((CapacityVOCpu.getUsedCapacity() + CapacityVOCpu.getReservedCapacity() > newTotalCpu) && (CapacityVOCpu.getUsedCapacity() < newTotalCpu)) {
- CapacityVOCpu.setReservedCapacity(0);
- CapacityVOCpu.setTotalCapacity(newTotalCpu);
- } else {
- logger.debug("What? new cpu is :" + newTotalCpu + ", old one is " + CapacityVOCpu.getUsedCapacity() + "," + CapacityVOCpu.getReservedCapacity() +
- "," + CapacityVOCpu.getTotalCapacity());
- }
- _capacityDao.update(CapacityVOCpu.getId(), CapacityVOCpu);
- } else {
- CapacityVO capacity =
- new CapacityVO(server.getId(), server.getDataCenterId(), server.getPodId(), server.getClusterId(), 0L, server.getCpus().longValue() *
- server.getSpeed().longValue(), Capacity.CAPACITY_TYPE_CPU);
- _capacityDao.persist(capacity);
- }
-
- SearchCriteria<CapacityVO> capacityMem = _capacityDao.createSearchCriteria();
- capacityMem.addAnd("hostOrPoolId", SearchCriteria.Op.EQ, server.getId());
- capacityMem.addAnd("dataCenterId", SearchCriteria.Op.EQ, server.getDataCenterId());
- capacityMem.addAnd("podId", SearchCriteria.Op.EQ, server.getPodId());
- capacityMem.addAnd("capacityType", SearchCriteria.Op.EQ, Capacity.CAPACITY_TYPE_MEMORY);
- List<CapacityVO> capacityVOMems = _capacityDao.search(capacityMem, null);
-
- if (capacityVOMems != null && !capacityVOMems.isEmpty()) {
- CapacityVO CapacityVOMem = capacityVOMems.get(0);
- long newTotalMem = (long)((server.getTotalMemory()) * memoryOvercommitRatio);
- if (CapacityVOMem.getTotalCapacity() <= newTotalMem || (CapacityVOMem.getUsedCapacity() + CapacityVOMem.getReservedCapacity() <= newTotalMem)) {
- CapacityVOMem.setTotalCapacity(newTotalMem);
- } else if (CapacityVOMem.getUsedCapacity() + CapacityVOMem.getReservedCapacity() > newTotalMem && CapacityVOMem.getUsedCapacity() < newTotalMem) {
- CapacityVOMem.setReservedCapacity(0);
- CapacityVOMem.setTotalCapacity(newTotalMem);
- } else {
- logger.debug("What? new mem is :" + newTotalMem + ", old one is " + CapacityVOMem.getUsedCapacity() + "," + CapacityVOMem.getReservedCapacity() +
- "," + CapacityVOMem.getTotalCapacity());
- }
- _capacityDao.update(CapacityVOMem.getId(), CapacityVOMem);
- } else {
- CapacityVO capacity =
- new CapacityVO(server.getId(), server.getDataCenterId(), server.getPodId(), server.getClusterId(), 0L, server.getTotalMemory(),
- Capacity.CAPACITY_TYPE_MEMORY);
- _capacityDao.persist(capacity);
- }
- }
-
- }
-
@Override
public float getClusterOverProvisioningFactor(Long clusterId, short capacityType) {
- String capacityOverProvisioningName = "";
+ String capacityOverProvisioningName;
if (capacityType == Capacity.CAPACITY_TYPE_CPU) {
capacityOverProvisioningName = VmDetailConstants.CPU_OVER_COMMIT_RATIO;
} else if (capacityType == Capacity.CAPACITY_TYPE_MEMORY) {
@@ -1110,15 +1032,14 @@
}
ClusterDetailsVO clusterDetailCpu = _clusterDetailsDao.findDetail(clusterId, capacityOverProvisioningName);
- Float clusterOverProvisioningRatio = Float.parseFloat(clusterDetailCpu.getValue());
- return clusterOverProvisioningRatio;
+ return Float.parseFloat(clusterDetailCpu.getValue());
}
@Override
public boolean checkIfClusterCrossesThreshold(Long clusterId, Integer cpuRequested, long ramRequested) {
- Float clusterCpuOverProvisioning = getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_CPU);
- Float clusterMemoryOverProvisioning = getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_MEMORY);
+ float clusterCpuOverProvisioning = getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_CPU);
+ float clusterMemoryOverProvisioning = getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_MEMORY);
Float clusterCpuCapacityDisableThreshold = DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.valueIn(clusterId);
Float clusterMemoryCapacityDisableThreshold = DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.valueIn(clusterId);
@@ -1148,8 +1069,8 @@
int cpu_requested = offering.getCpu() * offering.getSpeed();
long ram_requested = offering.getRamSize() * 1024L * 1024L;
Pair<String, String> clusterDetails = getClusterValues(host.getClusterId());
- Float cpuOvercommitRatio = Float.parseFloat(clusterDetails.first());
- Float memoryOvercommitRatio = Float.parseFloat(clusterDetails.second());
+ float cpuOvercommitRatio = Float.parseFloat(clusterDetails.first());
+ float memoryOvercommitRatio = Float.parseFloat(clusterDetails.second());
boolean hostHasCpuCapability = checkIfHostHasCpuCapability(host, offering.getCpu(), offering.getSpeed());
boolean hostHasCapacity = checkIfHostHasCapacity(host, cpu_requested, ram_requested, false, cpuOvercommitRatio, memoryOvercommitRatio,
diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index 193ecda..7b171e5 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -49,6 +49,11 @@
import javax.inject.Inject;
import javax.naming.ConfigurationException;
+import com.cloud.consoleproxy.ConsoleProxyManager;
+import com.cloud.network.router.VirtualNetworkApplianceManager;
+import com.cloud.storage.secondary.SecondaryStorageVmManager;
+import com.cloud.utils.DomainHelper;
+import com.cloud.vm.VirtualMachineManager;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.AffinityGroup;
@@ -150,7 +155,6 @@
import com.cloud.capacity.CapacityManager;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.configuration.Resource.ResourceType;
-import com.cloud.consoleproxy.ConsoleProxyManager;
import com.cloud.dc.AccountVlanMapVO;
import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterDetailsVO;
@@ -245,7 +249,6 @@
import com.cloud.network.element.NetrisProviderVO;
import com.cloud.network.element.NsxProviderVO;
import com.cloud.network.netris.NetrisService;
-import com.cloud.network.router.VirtualNetworkApplianceManager;
import com.cloud.network.rules.LoadBalancerContainer.Scheme;
import com.cloud.network.vpc.VpcManager;
import com.cloud.offering.DiskOffering;
@@ -280,7 +283,6 @@
import com.cloud.storage.dao.StoragePoolTagsDao;
import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.secondary.SecondaryStorageVmManager;
import com.cloud.test.IPRangeConfig;
import com.cloud.user.Account;
import com.cloud.user.AccountDetailVO;
@@ -314,7 +316,6 @@
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.NicIpAlias;
import com.cloud.vm.VirtualMachine;
-import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.VmDetailConstants;
import com.cloud.vm.dao.NicIpAliasDao;
import com.cloud.vm.dao.NicIpAliasVO;
@@ -399,6 +400,8 @@
ClusterDao _clusterDao;
@Inject
AlertManager _alertMgr;
+ @Inject
+ DomainHelper domainHelper;
List<SecurityChecker> _secChecker;
List<ExternalProvisioner> externalProvisioners;
@@ -991,6 +994,19 @@
}
}
+ protected String getNormalizedEmptyValueForConfig(final String name, final String inputValue,
+ final Long configStorageId) {
+ String value = inputValue.trim();
+ if (!value.isEmpty() && !value.equals("null")) {
+ return value;
+ }
+ if (configStorageId != null) {
+ return "";
+ }
+ ConfigKey<?> key = _configDepot.get(name);
+ return (key != null && key.type() == String.class) ? "" : null;
+ }
+
@Override
@ActionEvent(eventType = EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, eventDescription = "updating configuration")
public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidParameterValueException {
@@ -1085,11 +1101,7 @@
throw new InvalidParameterValueException("cannot handle multiple IDs, provide only one ID corresponding to the scope");
}
- value = value.trim();
-
- if (value.isEmpty() || value.equals("null")) {
- value = (id == null) ? null : "";
- }
+ value = getNormalizedEmptyValueForConfig(name, value, id);
String currentValueInScope = getConfigurationValueInScope(config, name, scope, id);
final String updatedValue = updateConfiguration(userId, name, category, value, scope, id);
@@ -3035,7 +3047,7 @@
mgmtPhyNetwork = _networkModel.getDefaultPhysicalNetworkByZoneAndTrafficType(zoneId, TrafficType.Management);
if (NetworkType.Advanced == zone.getNetworkType() && !zone.isSecurityGroupEnabled()) {
// advanced zone without SG should have a physical
- // network with public Thpe
+ // network with public Type
_networkModel.getDefaultPhysicalNetworkByZoneAndTrafficType(zoneId, TrafficType.Public);
}
@@ -3510,7 +3522,7 @@
final boolean isCustomized, final boolean encryptRoot, Long vgpuProfileId, Integer gpuCount, Boolean gpuDisplay, final boolean purgeResources, Integer leaseDuration, VMLeaseManager.ExpiryAction leaseExpiryAction) {
// Filter child domains when both parent and child domains are present
- List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
+ List<Long> filteredDomainIds = domainHelper.filterChildSubDomains(domainIds);
// Check if user exists in the system
final User user = _userDao.findById(userId);
@@ -3899,7 +3911,7 @@
final Account account = _accountDao.findById(user.getAccountId());
// Filter child domains when both parent and child domains are present
- List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
+ List<Long> filteredDomainIds = domainHelper.filterChildSubDomains(domainIds);
Collections.sort(filteredDomainIds);
// avoid domain update of service offering if any instance is associated to it
@@ -4109,7 +4121,7 @@
}
// Filter child domains when both parent and child domains are present
- List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
+ List<Long> filteredDomainIds = domainHelper.filterChildSubDomains(domainIds);
// Check if user exists in the system
final User user = _userDao.findById(userId);
@@ -4385,7 +4397,7 @@
final Account account = _accountDao.findById(user.getAccountId());
// Filter child domains when both parent and child domains are present
- List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
+ List<Long> filteredDomainIds = domainHelper.filterChildSubDomains(domainIds);
Collections.sort(filteredDomainIds);
List<Long> filteredZoneIds = new ArrayList<>();
@@ -7392,7 +7404,7 @@
}
if (offering != null) {
// Filter child domains when both parent and child domains are present
- List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
+ List<Long> filteredDomainIds = domainHelper.filterChildSubDomains(domainIds);
List<NetworkOfferingDetailsVO> detailsVO = new ArrayList<>();
for (Long domainId : filteredDomainIds) {
detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.domainid, String.valueOf(domainId), false));
@@ -7858,7 +7870,7 @@
}
// Filter child domains when both parent and child domains are present
- List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
+ List<Long> filteredDomainIds = domainHelper.filterChildSubDomains(domainIds);
Collections.sort(filteredDomainIds);
List<Long> filteredZoneIds = new ArrayList<>();
@@ -8425,30 +8437,6 @@
return false;
}
- private List<Long> filterChildSubDomains(final List<Long> domainIds) {
- List<Long> filteredDomainIds = new ArrayList<>();
- if (domainIds != null) {
- filteredDomainIds.addAll(domainIds);
- }
- if (filteredDomainIds.size() > 1) {
- for (int i = filteredDomainIds.size() - 1; i >= 1; i--) {
- long first = filteredDomainIds.get(i);
- for (int j = i - 1; j >= 0; j--) {
- long second = filteredDomainIds.get(j);
- if (_domainDao.isChildDomain(filteredDomainIds.get(i), filteredDomainIds.get(j))) {
- filteredDomainIds.remove(j);
- i--;
- }
- if (_domainDao.isChildDomain(filteredDomainIds.get(j), filteredDomainIds.get(i))) {
- filteredDomainIds.remove(i);
- break;
- }
- }
- }
- }
- return filteredDomainIds;
- }
-
protected void validateCacheMode(String cacheMode){
if(cacheMode != null &&
!Enums.getIfPresent(DiskOffering.DiskCacheMode.class,
diff --git a/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
index ad3e4ab..db15a44 100644
--- a/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
+++ b/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
@@ -156,7 +156,7 @@
import static com.cloud.vm.VirtualMachineManager.SystemVmEnableUserData;
/**
- * Class to manage console proxys. <br><br>
+ * Class to manage console proxies. <br><br>
* Possible console proxy state transition cases:<br>
* - Stopped -> Starting -> Running <br>
* - HA -> Stopped -> Starting -> Running <br>
@@ -569,7 +569,7 @@
if (!allowToLaunchNew(dataCenterId)) {
String configKey = ConsoleProxyLaunchMax.key();
Integer configValue = ConsoleProxyLaunchMax.valueIn(dataCenterId);
- logger.warn(String.format("The number of launched console proxys on zone [%s] has reached the limit [%s]. Limit set in [%s].", dataCenterId, configValue, configKey));
+ logger.warn(String.format("The number of launched console proxies on zone [%s] has reached the limit [%s]. Limit set in [%s].", dataCenterId, configValue, configKey));
return null;
}
diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
index d40b5b2..97c4530 100644
--- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
+++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
@@ -16,6 +16,9 @@
// under the License.
package com.cloud.hypervisor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -24,18 +27,31 @@
import javax.inject.Inject;
import com.cloud.agent.api.to.GPUDeviceTO;
+import com.cloud.agent.api.to.VirtualMachineMetadataTO;
import com.cloud.cpu.CPU;
+import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.HostPodVO;
+import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
import com.cloud.domain.Domain;
+import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.gpu.VgpuProfileVO;
import com.cloud.gpu.dao.VgpuProfileDao;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcDao;
+import com.cloud.projects.ProjectVO;
+import com.cloud.projects.dao.ProjectDao;
+import com.cloud.server.ResourceTag;
+import com.cloud.tags.dao.ResourceTagDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.dao.UserVmDao;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
@@ -97,7 +113,7 @@
@Inject
protected AccountManager accountManager;
@Inject
- private DomainDao domainDao;
+ protected DomainDao domainDao;
@Inject
private DataCenterDao dcDao;
@Inject
@@ -125,7 +141,19 @@
@Inject
private UserVmManager userVmManager;
@Inject
+ protected UserVmDao userVmDao;
+ @Inject
+ protected ProjectDao projectDao;
+ @Inject
+ protected ClusterDao clusterDao;
+ @Inject
+ protected DataCenterDao dataCenterDao;
+ @Inject
+ protected HostPodDao hostPodDao;
+ @Inject
private ConfigurationManager configurationManager;
+ @Inject
+ ResourceTagDao tagsDao;
public static ConfigKey<Boolean> VmMinMemoryEqualsMemoryDividedByMemOverprovisioningFactor = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.min.memory.equals.memory.divided.by.mem.overprovisioning.factor", "true",
"If we set this to 'true', a minimum memory (memory/ mem.overprovisioning.factor) will be set to the VM, independent of using a scalable service offering or not.", true, ConfigKey.Scope.Cluster);
@@ -212,7 +240,7 @@
}
to.setNicSecIps(secIps);
} else {
- logger.warn("Unabled to load NicVO for NicProfile {}", profile);
+ logger.warn("Unable to load NicVO for NicProfile {}", profile);
//Workaround for dynamically created nics
//FixMe: uuid and secondary IPs can be made part of nic profile
to.setUuid(UUID.randomUUID().toString());
@@ -470,4 +498,144 @@
logger.error("Unsupported operation: cannot remove template file");
return false;
}
+
+ /**
+ * Generates VirtualMachineMetadataTO object from VirtualMachineProfile
+ * It is a helper function to be used in the inherited classes to avoid repetition
+ * while generating metadata for multiple Guru implementations
+ *
+ * @param vmProfile virtual machine profile object
+ * @return A VirtualMachineMetadataTO ready to be appended to VirtualMachineTO object
+ * @see KVMGuru
+ */
+ protected VirtualMachineMetadataTO makeVirtualMachineMetadata(VirtualMachineProfile vmProfile) {
+ String vmName = "unknown",
+ instanceName = "unknown",
+ displayName = "unknown",
+ instanceUuid = "unknown",
+ clusterName = "unknown",
+ clusterUuid = "unknown",
+ zoneUuid = "unknown",
+ zoneName = "unknown",
+ podUuid = "unknown",
+ podName = "unknown",
+ domainUuid = "unknown",
+ domainName = "unknown",
+ accountUuid = "unknown",
+ accountName = "unknown",
+ projectName = "", // the project can be empty
+ projectUuid = "", // the project can be empty
+ serviceOfferingName = "unknown";
+ long created = 0L;
+ Integer cpuCores = -1, memory = -1;
+ List<String> serviceOfferingTags = new ArrayList<>();
+ HashMap<String, String> resourceTags = new HashMap<>();
+
+ UserVmVO vmVO = userVmDao.findById(vmProfile.getVirtualMachine().getId());
+ if (vmVO != null) {
+ instanceUuid = vmVO.getUuid();
+ vmName = vmVO.getHostName(); // this returns the VM name field
+ instanceName = vmVO.getInstanceName();
+ displayName = vmVO.getDisplayName();
+ created = vmVO.getCreated().getTime() / 1000L;
+
+ HostVO host = hostDao.findById(vmVO.getHostId());
+ if (host != null) {
+ // Find zone and cluster
+ Long clusterId = host.getClusterId();
+ ClusterVO cluster = clusterDao.findById(clusterId);
+
+ if (cluster != null) {
+ clusterName = cluster.getName();
+ clusterUuid = cluster.getUuid();
+
+ DataCenterVO zone = dataCenterDao.findById(cluster.getDataCenterId());
+ if (zone != null) {
+ zoneUuid = zone.getUuid();
+ zoneName = zone.getName();
+ }
+
+ HostPodVO pod = hostPodDao.findById(cluster.getPodId());
+ if (pod != null) {
+ podUuid = pod.getUuid();
+ podName = pod.getName();
+ }
+ }
+ } else {
+ logger.warn("Could not find the Host object for the virtual machine (null value returned). Libvirt metadata for cluster, pod, zone will not be populated.");
+ }
+
+ DomainVO domain = domainDao.findById(vmVO.getDomainId());
+ if (domain != null) {
+ domainUuid = domain.getUuid();
+ domainName = domain.getName();
+ } else {
+ logger.warn("Could not find the Domain object for the virtual machine (null value returned). Libvirt metadata for domain will not be populated.");
+ }
+
+ Account account = accountManager.getAccount(vmVO.getAccountId());
+ if (account != null) {
+ accountUuid = account.getUuid();
+ accountName = account.getName();
+
+ ProjectVO project = projectDao.findByProjectAccountId(account.getId());
+ if (project != null) {
+ projectName = project.getName();
+ projectUuid = project.getUuid();
+ }
+ } else {
+ logger.warn("Could not find the Account object for the virtual machine (null value returned). Libvirt metadata for account and project will not be populated.");
+ }
+
+ List<? extends ResourceTag> resourceTagsList = tagsDao.listBy(vmVO.getId(), ResourceTag.ResourceObjectType.UserVm);
+ if (resourceTagsList != null) {
+ for (ResourceTag tag : resourceTagsList) {
+ resourceTags.put(tag.getKey(), tag.getValue());
+ }
+ }
+ } else {
+ logger.warn("Could not find the VirtualMachine object by its profile (null value returned). Libvirt metadata will not be populated.");
+ }
+
+ ServiceOffering serviceOffering = vmProfile.getServiceOffering();
+ if (serviceOffering != null) {
+ serviceOfferingName = serviceOffering.getName();
+ cpuCores = serviceOffering.getCpu();
+ memory = serviceOffering.getRamSize();
+
+ String hostTagsCommaSeparated = serviceOffering.getHostTag();
+ if (hostTagsCommaSeparated != null) { // when service offering has no host tags, this value is null
+ serviceOfferingTags = Arrays.asList(hostTagsCommaSeparated.split(","));
+ }
+ } else {
+ logger.warn("Could not find the ServiceOffering object by its profile (null value returned). Libvirt metadata for service offering will not be populated.");
+ }
+
+
+ return new VirtualMachineMetadataTO(
+ vmName, // name
+ instanceName, // internalName
+ displayName, // displayName
+ instanceUuid , // instanceUUID
+ cpuCores, // cpuCores
+ memory, // memory
+ created, // created, unix epoch in seconds
+ System.currentTimeMillis() / 1000L, // started, unix epoch in seconds
+ domainUuid, // ownerDomainUUID
+ domainName, // ownerDomainName
+ accountUuid, // ownerAccountUUID
+ accountName, // ownerAccountName
+ projectUuid,
+ projectName,
+ serviceOfferingName,
+ serviceOfferingTags, // serviceOfferingTags
+ zoneName,
+ zoneUuid,
+ podName,
+ podUuid,
+ clusterName,
+ clusterUuid,
+ resourceTags
+ );
+ }
}
diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
index 4bdd56e..3303bc0 100644
--- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
+++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
@@ -158,7 +158,6 @@
}
@Override
-
public VirtualMachineTO implement(VirtualMachineProfile vm) {
VirtualMachineTO to = toVirtualMachineTO(vm);
setVmQuotaPercentage(to, vm);
@@ -173,6 +172,9 @@
configureVmOsDescription(virtualMachine, to, host);
configureVmMemoryAndCpuCores(to, host, virtualMachine, vm);
+
+ to.setMetadata(makeVirtualMachineMetadata(vm));
+
return to;
}
diff --git a/server/src/main/java/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/main/java/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java
index 1ded4ec..f5031dc 100644
--- a/server/src/main/java/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java
@@ -342,7 +342,7 @@
for (ExternalLoadBalancerDeviceVO lbDevice : lbDevices) {
if (lbDevice.getParentHostId() == hostId) {
throw new CloudRuntimeException(
- "This load balancer device can not be deleted as there are one or more load balancers applainces provisioned by cloudstack on the device.");
+ "This load balancer device can not be deleted as there are one or more load balancers appliances provisioned by cloudstack on the device.");
}
}
}
diff --git a/server/src/main/java/com/cloud/network/ExternalNetworkDeviceManagerImpl.java b/server/src/main/java/com/cloud/network/ExternalNetworkDeviceManagerImpl.java
index a983af8..f756a49 100644
--- a/server/src/main/java/com/cloud/network/ExternalNetworkDeviceManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/ExternalNetworkDeviceManagerImpl.java
@@ -139,20 +139,6 @@
}
private List<Host> listNetworkDevice(Long zoneId, Long physicalNetworkId, Long podId, Host.Type type) {
-// List<Host> res = new ArrayList<Host>();
-// if (podId != null) {
-// List<HostVO> devs = _hostDao.listBy(type, null, podId, zoneId);
-// if (devs.size() == 1) {
-// res.add(devs.get(0));
-// } else {
-// logger.debug("List " + type + ": " + devs.size() + " found");
-// }
-// } else {
-// List<HostVO> devs = _hostDao.listBy(type, zoneId);
-// res.addAll(devs);
- // }
-
- // return res;
return null;
}
diff --git a/server/src/main/java/com/cloud/network/as/AutoScaleManager.java b/server/src/main/java/com/cloud/network/as/AutoScaleManager.java
index 88a9fd3..eec1eec 100644
--- a/server/src/main/java/com/cloud/network/as/AutoScaleManager.java
+++ b/server/src/main/java/com/cloud/network/as/AutoScaleManager.java
@@ -16,9 +16,10 @@
// under the License.
package com.cloud.network.as;
-import com.cloud.user.Account;
import org.apache.cloudstack.framework.config.ConfigKey;
+import com.cloud.user.Account;
+
public interface AutoScaleManager extends AutoScaleService {
ConfigKey<Integer> AutoScaleStatsInterval = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED, Integer.class,
@@ -63,7 +64,5 @@
void removeVmFromVmGroup(Long vmId);
- String getNextVmHostName(AutoScaleVmGroupVO asGroup);
-
void checkAutoScaleVmGroupName(String groupName);
}
diff --git a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
index 8e93c68..e080a34 100644
--- a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
@@ -38,7 +38,6 @@
import javax.inject.Inject;
-import com.cloud.network.NetworkModel;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.affinity.AffinityGroupVO;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
@@ -113,6 +112,7 @@
import com.cloud.network.Network;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.IpAddresses;
+import com.cloud.network.NetworkModel;
import com.cloud.network.as.AutoScaleCounter.AutoScaleCounterParam;
import com.cloud.network.as.dao.AutoScalePolicyConditionMapDao;
import com.cloud.network.as.dao.AutoScalePolicyDao;
@@ -146,7 +146,9 @@
import com.cloud.server.ResourceTag;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.storage.GuestOSVO;
import com.cloud.storage.dao.DiskOfferingDao;
+import com.cloud.storage.dao.GuestOSDao;
import com.cloud.template.TemplateManager;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
@@ -280,6 +282,8 @@
private NetworkOfferingDao networkOfferingDao;
@Inject
private VirtualMachineManager virtualMachineManager;
+ @Inject
+ GuestOSDao guestOSDao;
private static final String PARAM_ROOT_DISK_SIZE = "rootdisksize";
private static final String PARAM_DISK_OFFERING_ID = "diskofferingid";
@@ -296,6 +300,10 @@
protected static final String VM_HOSTNAME_PREFIX = "autoScaleVm-";
protected static final int VM_HOSTNAME_RANDOM_SUFFIX_LENGTH = 6;
+ // Windows OS has a limit of 15 characters for hostname
+ // https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/naming-conventions-for-computer-domain-site-ou
+ protected static final String WINDOWS_VM_HOSTNAME_PREFIX = "as-WinVm-";
+
private static final Long DEFAULT_HOST_ID = -1L;
ExecutorService groupExecutor;
@@ -1818,13 +1826,15 @@
List<Long> affinityGroupIdList = getVmAffinityGroupId(deployParams);
updateVmDetails(deployParams, customParameters);
- String vmHostName = getNextVmHostName(asGroup);
+ Pair<String, String> vmHostAndDisplayName = getNextVmHostAndDisplayName(asGroup, template);
+ String vmHostName = vmHostAndDisplayName.first();
+ String vmDisplayName = vmHostAndDisplayName.second();
asGroup.setNextVmSeq(asGroup.getNextVmSeq() + 1);
autoScaleVmGroupDao.persist(asGroup);
if (zone.getNetworkType() == NetworkType.Basic) {
vm = userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, vmHostName,
- vmHostName, diskOfferingId, dataDiskSize, null, null,
+ vmDisplayName, diskOfferingId, dataDiskSize, null, null,
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
null, true, overrideDiskOfferingId, null, null);
@@ -1832,12 +1842,12 @@
if (networkModel.checkSecurityGroupSupportForNetwork(owner, zone, networkIds,
Collections.emptyList())) {
vm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, null,
- owner, vmHostName,vmHostName, diskOfferingId, dataDiskSize, null, null,
+ owner, vmHostName, vmDisplayName, diskOfferingId, dataDiskSize, null, null,
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
null, true, overrideDiskOfferingId, null, null, null);
} else {
- vm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, vmHostName, vmHostName,
+ vm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, vmHostName, vmDisplayName,
diskOfferingId, dataDiskSize, null, null,
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
null, addrs, true, null, affinityGroupIdList, customParameters, null, null, null,
@@ -1962,13 +1972,29 @@
}
}
- @Override
- public String getNextVmHostName(AutoScaleVmGroupVO asGroup) {
- String vmHostNameSuffix = "-" + asGroup.getNextVmSeq() + "-" +
- RandomStringUtils.random(VM_HOSTNAME_RANDOM_SUFFIX_LENGTH, 0, 0, true, false, (char[])null, new SecureRandom()).toLowerCase();
+ protected boolean isWindowsOs(VirtualMachineTemplate template) {
+ GuestOSVO guestOSVO = guestOSDao.findById(template.getGuestOSId());
+ if (guestOSVO == null) {
+ return false;
+ }
+ String osName = StringUtils.firstNonBlank(guestOSVO.getName(), guestOSVO.getDisplayName());
+ if (StringUtils.isBlank(osName)) {
+ return false;
+ }
+ return osName.toLowerCase().contains("windows");
+ }
+
+ protected Pair<String, String> getNextVmHostAndDisplayName(AutoScaleVmGroupVO asGroup, VirtualMachineTemplate template) {
+ boolean isWindows = isWindowsOs(template);
+ String winVmHostNameSuffix = RandomStringUtils.random(VM_HOSTNAME_RANDOM_SUFFIX_LENGTH, 0, 0, true, false, (char[])null, new SecureRandom()).toLowerCase();
+ String vmHostNameSuffix = "-" + asGroup.getNextVmSeq() + "-" + winVmHostNameSuffix;
// Truncate vm group name because max length of vm name is 63
int subStringLength = Math.min(asGroup.getName().length(), 63 - VM_HOSTNAME_PREFIX.length() - vmHostNameSuffix.length());
- return VM_HOSTNAME_PREFIX + asGroup.getName().substring(0, subStringLength) + vmHostNameSuffix;
+ String name = VM_HOSTNAME_PREFIX + asGroup.getName().substring(0, subStringLength) + vmHostNameSuffix;
+ if (!isWindows) {
+ return new Pair<>(name, name);
+ }
+ return new Pair<>(WINDOWS_VM_HOSTNAME_PREFIX + winVmHostNameSuffix, name);
}
@Override
diff --git a/server/src/main/java/com/cloud/network/rules/PrivateGatewayRules.java b/server/src/main/java/com/cloud/network/rules/PrivateGatewayRules.java
index 1b827b3..8e70e4e 100644
--- a/server/src/main/java/com/cloud/network/rules/PrivateGatewayRules.java
+++ b/server/src/main/java/com/cloud/network/rules/PrivateGatewayRules.java
@@ -69,7 +69,6 @@
// setup source nat
if (_nicProfile != null) {
_isAddOperation = true;
- // result = setupVpcPrivateNetwork(router, true, guestNic);
result = visitor.visit(this);
}
} catch (final Exception ex) {
diff --git a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java
index db79cad..1f1e294 100644
--- a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java
@@ -564,9 +564,7 @@
_accountMgr.checkAccess(vmOwner, SecurityChecker.AccessType.UseEntry, false, network);
//is static nat is for vm secondary ip
- //dstIp = guestNic.getIp4Address();
if (vmGuestIp != null) {
- //dstIp = guestNic.getIp4Address();
if (!dstIp.equals(vmGuestIp)) {
//check whether the secondary ip set to the vm or not
@@ -667,7 +665,7 @@
}
} else if (ipAddress.getAssociatedWithVmId() != null && ipAddress.getAssociatedWithVmId().longValue() != vmId) {
throw new NetworkRuleConflictException("Failed to enable static for the ip address " + ipAddress + " and vm id=" + vmId +
- " as it's already assigned to antoher vm");
+ " as it's already assigned to another vm");
}
//check whether the vm ip is already associated with any public ip address
diff --git a/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java b/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java
index f0e3b32..585b65a 100644
--- a/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java
@@ -212,7 +212,6 @@
try {
cleanupFinishedWork();
cleanupUnfinishedWork();
- //processScheduledWork();
} catch (Throwable th) {
logger.error("Problem with SG Cleanup", th);
}
diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
index e4219c8..60b93d4 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -63,6 +63,7 @@
import com.cloud.network.element.NsxProviderVO;
import com.cloud.network.rules.RulesManager;
import com.cloud.network.vpn.RemoteAccessVpnService;
+import com.cloud.utils.DomainHelper;
import com.cloud.vm.dao.VMInstanceDao;
import com.google.common.collect.Sets;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
@@ -285,6 +286,8 @@
@Inject
DomainDao domainDao;
@Inject
+ DomainHelper domainHelper;
+ @Inject
private AnnotationDao annotationDao;
@Inject
NetworkOfferingDao _networkOfferingDao;
@@ -636,7 +639,7 @@
}
// Filter child domains when both parent and child domains are present
- List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
+ List<Long> filteredDomainIds = domainHelper.filterChildSubDomains(domainIds);
final Map<Network.Service, Set<Network.Provider>> svcProviderMap = new HashMap<Network.Service, Set<Network.Provider>>();
final Set<Network.Provider> defaultProviders = new HashSet<Network.Provider>();
@@ -1118,7 +1121,7 @@
// Filter child domains when both parent and child domains are present
- List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
+ List<Long> filteredDomainIds = domainHelper.filterChildSubDomains(domainIds);
Collections.sort(filteredDomainIds);
List<Long> filteredZoneIds = new ArrayList<>();
@@ -3658,30 +3661,6 @@
return _ntwkMgr.areRoutersRunning(routerDao.listByVpcId(vpc.getId()));
}
- private List<Long> filterChildSubDomains(final List<Long> domainIds) {
- List<Long> filteredDomainIds = new ArrayList<>();
- if (domainIds != null) {
- filteredDomainIds.addAll(domainIds);
- }
- if (filteredDomainIds.size() > 1) {
- for (int i = filteredDomainIds.size() - 1; i >= 1; i--) {
- long first = filteredDomainIds.get(i);
- for (int j = i - 1; j >= 0; j--) {
- long second = filteredDomainIds.get(j);
- if (domainDao.isChildDomain(filteredDomainIds.get(i), filteredDomainIds.get(j))) {
- filteredDomainIds.remove(j);
- i--;
- }
- if (domainDao.isChildDomain(filteredDomainIds.get(j), filteredDomainIds.get(i))) {
- filteredDomainIds.remove(i);
- break;
- }
- }
- }
- }
- return filteredDomainIds;
- }
-
protected boolean isGlobalAcl(Long aclVpcId) {
return aclVpcId != null && aclVpcId == 0;
}
diff --git a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManager.java b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManager.java
index 25c84d6..9cf604f 100644
--- a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManager.java
+++ b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManager.java
@@ -17,11 +17,17 @@
package com.cloud.network.vpn;
import java.util.List;
+import java.util.Set;
+import com.cloud.network.Site2SiteCustomerGateway;
import com.cloud.network.dao.Site2SiteVpnConnectionVO;
import com.cloud.vm.DomainRouterVO;
public interface Site2SiteVpnManager extends Site2SiteVpnService {
+ Set<String> getExcludedVpnGatewayParameters(Site2SiteCustomerGateway customerGw);
+
+ Set<String> getObsoleteVpnGatewayParameters(Site2SiteCustomerGateway customerGw);
+
boolean cleanupVpnConnectionByVpc(long vpcId);
boolean cleanupVpnGatewayByVpc(long vpcId);
diff --git a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
index ad1d1f0..09236eb0 100644
--- a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
@@ -17,15 +17,22 @@
package com.cloud.network.vpn;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
+import org.apache.cloudstack.framework.config.Configurable;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;
+import org.apache.cloudstack.alert.AlertService;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.command.user.vpn.CreateVpnConnectionCmd;
@@ -41,9 +48,16 @@
import org.apache.cloudstack.api.command.user.vpn.UpdateVpnCustomerGatewayCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.ConfigKeyScheduledExecutionWrapper;
+import org.apache.cloudstack.managed.context.ManagedContextRunnable;
+import com.cloud.utils.concurrency.NamedThreadFactory;
+
+import com.cloud.alert.AlertManager;
import com.cloud.configuration.Config;
import com.cloud.event.ActionEvent;
+import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
@@ -72,9 +86,11 @@
import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
+import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
+import com.cloud.utils.StringUtils;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB;
@@ -88,7 +104,52 @@
import com.cloud.vm.dao.DomainRouterDao;
@Component
-public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager {
+public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager, Configurable {
+
+ // Configuration keys for VPN gateway cryptographic parameter controls
+ public static final ConfigKey<String> VpnCustomerGatewayExcludedEncryptionAlgorithms = new ConfigKey<String>(
+ ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.excluded.encryption.algorithms", "",
+ "Comma-separated list of encryption algorithms that are excluded and cannot be selected by end users for VPN Customer Gateways." +
+ "Applies to both IKE and ESP phases. Allowed values are aes128, aes192 and aes256 and 3des.",
+ true, ConfigKey.Scope.Domain);
+ public static final ConfigKey<String> VpnCustomerGatewayExcludedHashingAlgorithms = new ConfigKey<String>(
+ ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.excluded.hashing.algorithms", "",
+ "Comma-separated list of hashing algorithms that are excluded and cannot be selected by end users for VPN Customer Gateways." +
+ "Applies to both IKE and ESP phases. Allowed values are sha1, sha256, sha384 and sha512 and md5.",
+ true, ConfigKey.Scope.Domain);
+ public static final ConfigKey<String> VpnCustomerGatewayExcludedIkeVersions = new ConfigKey<String>(
+ ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.excluded.ike.versions", "",
+ "Comma-separated list of IKE versions that are excluded and cannot be selected by end users for VPN Customer Gateways. Allowed values are ikev, ikev1 and ikev2.",
+ true, ConfigKey.Scope.Domain);
+ public static final ConfigKey<String> VpnCustomerGatewayExcludedDhGroup = new ConfigKey<String>(
+ ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.excluded.dh.group", "",
+ "Comma-separated list of Diffie-Hellman groups that are excluded and cannot be selected by end users for VPN Customer Gateways." +
+ "Applies to both IKE and ESP phases. Allowed values are modp1024, modp1536, modp2048, modp3072, modp4096, modp6144 and modp8192.",
+ true, ConfigKey.Scope.Domain);
+ public static final ConfigKey<String> VpnCustomerGatewayObsoleteEncryptionAlgorithms = new ConfigKey<String>(
+ ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.obsolete.encryption.algorithms", "",
+ "Comma-separated list of encryption algorithms that are marked as obsolete/insecure for VPN Customer Gateways." +
+ "Applies to both IKE and ESP phases. Allowed values are aes128, aes192 and aes256 and 3des.",
+ true, ConfigKey.Scope.Domain);
+ public static final ConfigKey<String> VpnCustomerGatewayObsoleteHashingAlgorithms = new ConfigKey<String>(
+ ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.obsolete.hashing.algorithms", "",
+ "Comma-separated list of hashing algorithms that are marked as obsolete/insecure for VPN Customer Gateways." +
+ "Applies to both IKE and ESP phases. Allowed values are sha1, sha256, sha384 and sha512 and md5.",
+ true, ConfigKey.Scope.Domain);
+ public static final ConfigKey<String> VpnCustomerGatewayObsoleteIkeVersions = new ConfigKey<String>(
+ ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.obsolete.ike.versions", "",
+ "Comma-separated list of IKE versions that are marked as obsolete/insecure for VPN Customer Gateways. Allowed values are ikev, ikev1 and ikev2.",
+ true, ConfigKey.Scope.Domain);
+ public static final ConfigKey<String> VpnCustomerGatewayObsoleteDhGroup = new ConfigKey<String>(
+ ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.obsolete.dh.group", "",
+ "Comma-separated list of Diffie-Hellman groups that are marked as obsolete/insecure for VPN Customer Gateways." +
+ "Applies to both IKE and ESP phases. Allowed values are modp1024, modp1536, modp2048, modp3072, modp4096, modp6144 and modp8192.",
+ true, ConfigKey.Scope.Domain);
+ public static final ConfigKey<Long> VpnCustomerGatewayObsoleteCheckInterval = new ConfigKey<Long>(
+ ConfigKey.CATEGORY_NETWORK, Long.class, "vpn.customer.gateway.obsolete.check.interval", "0",
+ "Interval in hours to periodically check VPN customer gateways for obsolete/excluded parameters and generate events and alerts. " +
+ "Set to 0 to disable. Default: 0 (disabled).",
+ true, ConfigKey.Scope.Global);
List<Site2SiteVpnServiceProvider> _s2sProviders;
@Inject
@@ -117,9 +178,12 @@
private IpAddressManager ipAddressManager;
@Inject
private VpcManager vpcManager;
+ @Inject
+ private AlertManager _alertMgr;
int _connLimit;
int _subnetsLimit;
+ private ScheduledExecutorService _vpnCheckExecutor;
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@@ -127,6 +191,7 @@
_connLimit = NumbersUtil.parseInt(configs.get(Config.Site2SiteVpnConnectionPerVpnGatewayLimit.key()), 4);
_subnetsLimit = NumbersUtil.parseInt(configs.get(Config.Site2SiteVpnSubnetsPerCustomerGatewayLimit.key()), 10);
assert (_s2sProviders.iterator().hasNext()) : "Did not get injected with a list of S2S providers!";
+ _vpnCheckExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpnCustomerGateway-ExcludedAndObsoleteCheck"));
return true;
}
@@ -146,7 +211,7 @@
}
Site2SiteVpnGatewayVO gws = _vpnGatewayDao.findByVpcId(vpcId);
if (gws != null) {
- throw new InvalidParameterValueException(String.format("The VPN gateway of VPC %s already existed!", vpc));
+ throw new InvalidParameterValueException(String.format("The VPN gateway of VPC %s already exists!", vpc));
}
IPAddressVO requestedIp = _ipAddressDao.findById(cmd.getIpAddressId());
@@ -187,6 +252,113 @@
}
}
+ private void validateVpnCryptographicParameters(String ikePolicy, String espPolicy, String ikeVersion, Long domainId) {
+ String excludedEncryption = VpnCustomerGatewayExcludedEncryptionAlgorithms.valueIn(domainId);
+ String excludedHashing = VpnCustomerGatewayExcludedHashingAlgorithms.valueIn(domainId);
+ String excludedIkeVersions = VpnCustomerGatewayExcludedIkeVersions.valueIn(domainId);
+ String excludedDhGroup = VpnCustomerGatewayExcludedDhGroup.valueIn(domainId);
+
+ Set<String> excludedParameters = getVpnGatewayParametersInBlockedList(ikePolicy, espPolicy, ikeVersion,
+ excludedEncryption, excludedHashing, excludedIkeVersions, excludedDhGroup);
+ if (!excludedParameters.isEmpty()) {
+ throw new InvalidParameterValueException("The following excluded cryptographic parameter(s) cannot be used in a VPN Customer Gateway: " + excludedParameters.toString());
+ }
+ }
+
+ @Override
+ public Set<String> getExcludedVpnGatewayParameters(Site2SiteCustomerGateway customerGw) {
+ Long domainId = customerGw.getDomainId();
+ String excludedEncryption = VpnCustomerGatewayExcludedEncryptionAlgorithms.valueIn(domainId);
+ String excludedHashing = VpnCustomerGatewayExcludedHashingAlgorithms.valueIn(domainId);
+ String excludedIkeVersions = VpnCustomerGatewayExcludedIkeVersions.valueIn(domainId);
+ String excludedDhGroup = VpnCustomerGatewayExcludedDhGroup.valueIn(domainId);
+
+ return getVpnGatewayParametersInBlockedList(customerGw.getIkePolicy(), customerGw.getEspPolicy(), customerGw.getIkeVersion(),
+ excludedEncryption, excludedHashing, excludedIkeVersions, excludedDhGroup);
+ }
+
+ @Override
+ public Set<String> getObsoleteVpnGatewayParameters(Site2SiteCustomerGateway customerGw) {
+ Long domainId = customerGw.getDomainId();
+ String obsoleteEncryption = VpnCustomerGatewayObsoleteEncryptionAlgorithms.valueIn(domainId);
+ String obsoleteHashing = VpnCustomerGatewayObsoleteHashingAlgorithms.valueIn(domainId);
+ String obsoleteIkeVersions = VpnCustomerGatewayObsoleteIkeVersions.valueIn(domainId);
+ String obsoleteDhGroup = VpnCustomerGatewayObsoleteDhGroup.valueIn(domainId);
+
+ return getVpnGatewayParametersInBlockedList(customerGw.getIkePolicy(), customerGw.getEspPolicy(), customerGw.getIkeVersion(),
+ obsoleteEncryption, obsoleteHashing, obsoleteIkeVersions, obsoleteDhGroup);
+ }
+
+ private Set<String> getVpnGatewayParametersInBlockedList(String ikePolicy, String espPolicy, String ikeVersion,
+ String blockedEncryptionList, String blockedHashingList,
+ String blockedIkeVersionList, String blockedDhGroupList) {
+
+ Set<String> blockedParameters = new HashSet<>();
+ if (StringUtils.isEmpty(blockedEncryptionList)
+ && StringUtils.isEmpty(blockedHashingList)
+ && StringUtils.isEmpty(blockedIkeVersionList)
+ && StringUtils.isEmpty(blockedDhGroupList)) {
+ return blockedParameters;
+ }
+
+ if (isParameterInList(ikeVersion, blockedIkeVersionList)) {
+ blockedParameters.add(ikeVersion);
+ }
+
+ Set<String> ikePolicyResult = getVpnGatewayPolicyParametersInBlockedList(ikePolicy, "IKE", blockedEncryptionList, blockedHashingList, blockedDhGroupList);
+ if (CollectionUtils.isNotEmpty(ikePolicyResult)) {
+ blockedParameters.addAll(ikePolicyResult);
+ }
+
+ Set<String> espPolicyResult = getVpnGatewayPolicyParametersInBlockedList(espPolicy, "ESP", blockedEncryptionList, blockedHashingList, blockedDhGroupList);
+ if (CollectionUtils.isNotEmpty(espPolicyResult)) {
+ blockedParameters.addAll(espPolicyResult);
+ }
+
+ return blockedParameters;
+ }
+
+ private Set<String> getVpnGatewayPolicyParametersInBlockedList(String policy, String policyType, String blockedEncryptionList, String blockedHashingList, String blockedDhGroupList) {
+
+ String trimmedPolicy = policy.trim();
+ String cipherHash = trimmedPolicy.split(";")[0];
+ String[] parts = cipherHash.split("-");
+
+ String encryption = parts[0].trim();
+ String hashing = parts.length > 1 ? parts[1].trim() : "";
+
+ Set<String> blockedParameters = new HashSet<>();
+ if (isParameterInList(encryption, blockedEncryptionList)) {
+ blockedParameters.add(encryption);
+ }
+
+ if (isParameterInList(hashing, blockedHashingList)) {
+ blockedParameters.add(hashing);
+ }
+
+ if (!trimmedPolicy.equals(cipherHash)) {
+ String dhGroup = trimmedPolicy.split(";")[1].trim();
+ if (isParameterInList(dhGroup, blockedDhGroupList)) {
+ blockedParameters.add(dhGroup);
+ }
+ }
+ return blockedParameters;
+ }
+
+ private boolean isParameterInList(String parameter, String list) {
+ if (StringUtils.isEmpty(list) || StringUtils.isEmpty(parameter)) {
+ return false;
+ }
+
+ String[] entries = list.split(",");
+ for (String item : entries) {
+ if (item != null && item.trim().equalsIgnoreCase(parameter.trim())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
protected void checkCustomerGatewayCidrList(String guestCidrList) {
String[] cidrList = guestCidrList.split(",");
if (cidrList.length > _subnetsLimit) {
@@ -235,6 +407,13 @@
if (!NetUtils.isValidS2SVpnPolicy("esp", espPolicy)) {
throw new InvalidParameterValueException("The customer gateway ESP policy " + espPolicy + " is invalid!");
}
+
+ String ikeVersion = cmd.getIkeVersion();
+ if (ikeVersion == null) {
+ ikeVersion = "ike";
+ }
+ validateVpnCryptographicParameters(ikePolicy, espPolicy, ikeVersion, owner.getDomainId());
+
Long ikeLifetime = cmd.getIkeLifetime();
if (ikeLifetime == null) {
// Default value of lifetime is 1 day
@@ -264,7 +443,7 @@
long accountId = owner.getAccountId();
if (_customerGatewayDao.findByNameAndAccountId(name, accountId) != null) {
- throw new InvalidParameterValueException("The customer gateway with name " + name + " already existed!");
+ throw new InvalidParameterValueException("The customer gateway with name " + name + " already exists!");
}
Boolean splitConnections = cmd.getSplitConnections();
@@ -272,11 +451,6 @@
splitConnections = false;
}
- String ikeVersion = cmd.getIkeVersion();
- if (ikeVersion == null) {
- ikeVersion = "ike";
- }
-
checkCustomerGatewayCidrList(peerCidrList);
Site2SiteCustomerGatewayVO gw =
@@ -374,7 +548,7 @@
private void validateVpnConnectionDoesntExist(Site2SiteCustomerGateway customerGateway, Site2SiteVpnGateway vpnGateway) {
if (_vpnConnectionDao.findByVpnGatewayIdAndCustomerGatewayId(vpnGateway.getId(), customerGateway.getId()) != null) {
- throw new InvalidParameterValueException(String.format("The vpn connection with customer gateway %s and vpn gateway %s already existed!", customerGateway, vpnGateway));
+ throw new InvalidParameterValueException(String.format("The vpn connection with customer gateway %s and vpn gateway %s already exists!", customerGateway, vpnGateway));
}
}
@@ -521,6 +695,10 @@
if (!NetUtils.isValidS2SVpnPolicy("esp", espPolicy)) {
throw new InvalidParameterValueException("The customer gateway ESP policy" + espPolicy + " is invalid!");
}
+
+ String ikeVersion = cmd.getIkeVersion();
+ validateVpnCryptographicParameters(ikePolicy, espPolicy, ikeVersion, gw.getDomainId());
+
Long ikeLifetime = cmd.getIkeLifetime();
if (ikeLifetime == null) {
// Default value of lifetime is 1 day
@@ -550,14 +728,12 @@
Boolean splitConnections = cmd.getSplitConnections();
- String ikeVersion = cmd.getIkeVersion();
-
checkCustomerGatewayCidrList(guestCidrList);
long accountId = gw.getAccountId();
Site2SiteCustomerGatewayVO existedGw = _customerGatewayDao.findByNameAndAccountId(name, accountId);
if (existedGw != null && existedGw.getId() != gw.getId()) {
- throw new InvalidParameterValueException("The customer gateway with name " + name + " already existed!");
+ throw new InvalidParameterValueException("The customer gateway with name " + name + " already exists!");
}
gw.setName(name);
@@ -977,4 +1153,83 @@
return _vpnGatewayDao.findById(id);
}
+
+ @Override
+ public boolean start() {
+ ConfigKeyScheduledExecutionWrapper runner = new ConfigKeyScheduledExecutionWrapper(
+ _vpnCheckExecutor,
+ new CheckVpnCustomerGatewayObsoleteParametersTask(),
+ VpnCustomerGatewayObsoleteCheckInterval,
+ 3600,
+ TimeUnit.HOURS);
+ runner.start();
+ return true;
+ }
+
+ @Override
+ public boolean stop() {
+ if (_vpnCheckExecutor != null) {
+ _vpnCheckExecutor.shutdownNow();
+ }
+ return true;
+ }
+
+ @Override
+ public String getConfigComponentName() {
+ return Site2SiteVpnManager.class.getSimpleName();
+ }
+
+ @Override
+ public ConfigKey<?>[] getConfigKeys() {
+ return new ConfigKey<?>[] { VpnCustomerGatewayExcludedEncryptionAlgorithms, VpnCustomerGatewayExcludedHashingAlgorithms,
+ VpnCustomerGatewayExcludedIkeVersions, VpnCustomerGatewayExcludedDhGroup, VpnCustomerGatewayObsoleteEncryptionAlgorithms,
+ VpnCustomerGatewayObsoleteHashingAlgorithms, VpnCustomerGatewayObsoleteIkeVersions, VpnCustomerGatewayObsoleteDhGroup,
+ VpnCustomerGatewayObsoleteCheckInterval};
+ }
+
+ protected class CheckVpnCustomerGatewayObsoleteParametersTask extends ManagedContextRunnable {
+
+ @Override
+ protected void runInContext() {
+ List<Site2SiteCustomerGatewayVO> allGateways = _customerGatewayDao.listAll();
+ int obsoleteCount = 0;
+ int excludedCount = 0;
+
+ for (Site2SiteCustomerGatewayVO gateway : allGateways) {
+ Set<String> excludedParameters = getExcludedVpnGatewayParameters(gateway);
+ Set<String> obsoleteParameters = getObsoleteVpnGatewayParameters(gateway);
+
+ List<String> message = new ArrayList<>();
+ if (CollectionUtils.isNotEmpty(excludedParameters)) {
+ excludedCount++;
+ message.add("excluded parameter(s) " + excludedParameters.toString());
+ }
+ if (CollectionUtils.isNotEmpty(obsoleteParameters)) {
+ obsoleteCount++;
+ message.add("obsolete parameter(s) " + obsoleteParameters.toString());
+ }
+
+ if (CollectionUtils.isNotEmpty(message)) {
+ Account account = _accountDao.findById(gateway.getAccountId());
+ String description = String.format("VPN customer gateway '%s' (Account: %s) contains %s.",
+ gateway.getName(), account.getAccountName(), String.join(" and ", message));
+ ActionEventUtils.onActionEvent(User.UID_SYSTEM, gateway.getAccountId(), gateway.getDomainId(),
+ EventTypes.EVENT_S2S_VPN_GATEWAY_OBSOLETE_PARAMS, description,
+ gateway.getId(), Site2SiteCustomerGateway.class.getSimpleName());
+ }
+ }
+
+ List<String> message = new ArrayList<>();
+ if (excludedCount > 0) {
+ message.add("excluded parameters: " + excludedCount);
+ }
+ if (obsoleteCount > 0) {
+ message.add("obsolete parameters: " + obsoleteCount);
+ }
+ if (CollectionUtils.isNotEmpty(message)) {
+ String subject = String.format("VPN customer gateways using " + String.join(", ", message));
+ _alertMgr.sendAlert(AlertService.AlertType.ALERT_TYPE_VPN_GATEWAY_OBSOLETE_PARAMETERS, 0L, 0L, subject, null);
+ }
+ }
+ }
}
diff --git a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
index f4548ed..0da403c 100644
--- a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
+++ b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
@@ -905,6 +905,11 @@
public ResourceLimitVO updateResourceLimit(Long accountId, Long domainId, Integer typeId, Long max, String tag) {
Account caller = CallContext.current().getCallingAccount();
+ if (caller.getType().equals(Account.Type.NORMAL)) {
+ logger.info("Throwing exception because only root admins and domain admins are allowed to update resource limits.");
+ throw new PermissionDeniedException("Your account does not have the permission to update resource limits.");
+ }
+
if (max == null) {
max = (long)Resource.RESOURCE_UNLIMITED;
} else if (max < Resource.RESOURCE_UNLIMITED) {
diff --git a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
index e476c74..8f10dd8 100644
--- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
@@ -328,8 +328,6 @@
// setup XenServer default PV driver version
initiateXenServerPVDriverVersion();
- // We should not update seed data UUID column here since this will be invoked in upgrade case as well.
- //updateUuids();
// Set init to true
_configDao.update("init", "Hidden", "true");
@@ -616,7 +614,7 @@
}
// FIXME: take a global database lock here for safety.
boolean onWindows = isOnWindows();
- if(!onWindows) {
+ if (!onWindows && !(privkeyfile.exists() && pubkeyfile.exists())) {
Script.runSimpleBashScript("if [ -f " + privkeyfile + " ]; then rm -f " + privkeyfile + "; fi; ssh-keygen -t ecdsa -m PEM -N '' -f " + privkeyfile + " -q 2>/dev/null || ssh-keygen -t ecdsa -N '' -f " + privkeyfile + " -q");
}
diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
index 57d8789..9de2af6 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -721,6 +721,7 @@
import com.cloud.deploy.DeploymentPlanner;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.deploy.DeploymentPlanningManager;
+import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEvent;
@@ -762,6 +763,7 @@
import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.network.Networks;
+import com.cloud.network.vpn.Site2SiteVpnManagerImpl;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.LoadBalancerDao;
@@ -4780,6 +4782,14 @@
final Map<String, Object> capabilities = new HashMap<>();
final Account caller = getCaller();
+ Long domainId = cmd.getDomainId();
+ if (domainId == null) {
+ domainId = caller.getDomainId();
+ } else {
+ Domain domain = _domainDao.findById(domainId);
+ _accountService.checkAccess(caller, domain);
+ }
+
final boolean isCallerRootAdmin = _accountService.isRootAdmin(caller.getId());
final boolean isCallerAdmin = isCallerRootAdmin || _accountService.isAdmin(caller.getId());
boolean securityGroupsEnabled = false;
@@ -4815,7 +4825,7 @@
final boolean allowUserExpungeRecoverVolume = (VolumeApiServiceImpl.AllowUserExpungeRecoverVolume.valueIn(caller.getId()) | isCallerAdmin);
final boolean allowUserForceStopVM = (UserVmManager.AllowUserForceStopVm.valueIn(caller.getId()) | isCallerAdmin);
- final boolean allowUserViewAllDomainAccounts = (QueryService.AllowUserViewAllDomainAccounts.valueIn(caller.getDomainId()));
+ final boolean allowUserViewAllDomainAccounts = (QueryService.AllowUserViewAllDomainAccounts.valueIn(domainId));
final boolean kubernetesServiceEnabled = Boolean.parseBoolean(_configDao.getValue("cloud.kubernetes.service.enabled"));
final boolean kubernetesClusterExperimentalFeaturesEnabled = Boolean.parseBoolean(_configDao.getValue("cloud.kubernetes.cluster.experimental.features.enabled"));
@@ -4869,9 +4879,53 @@
}
capabilities.put(ApiConstants.ADDITONAL_CONFIG_ENABLED, UserVmManager.EnableAdditionalVmConfig.valueIn(caller.getId()));
+ Map<String, Object> vpnParams = getVpnCustomerGatewayParameters(domainId);
+ if (!vpnParams.isEmpty()) {
+ capabilities.put(ApiConstants.VPN_CUSTOMER_GATEWAY_PARAMETERS, vpnParams);
+ }
+
return capabilities;
}
+ private Map<String, Object> getVpnCustomerGatewayParameters(Long domainId) {
+ Map<String, Object> vpnParams = new HashMap<>();
+
+ String excludedEncryption = Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms.valueIn(domainId);
+ String excludedHashing = Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms.valueIn(domainId);
+ String excludedIkeVersions = Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions.valueIn(domainId);
+ String excludedDhGroup = Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup.valueIn(domainId);
+ String obsoleteEncryption = Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms.valueIn(domainId);
+ String obsoleteHashing = Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms.valueIn(domainId);
+ String obsoleteIkeVersions = Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions.valueIn(domainId);
+ String obsoleteDhGroup = Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup.valueIn(domainId);
+
+ if (!excludedEncryption.isEmpty()) {
+ vpnParams.put("excludedencryptionalgorithms", excludedEncryption);
+ }
+ if (!obsoleteEncryption.isEmpty()) {
+ vpnParams.put("obsoleteencryptionalgorithms", obsoleteEncryption);
+ }
+ if (!excludedHashing.isEmpty()) {
+ vpnParams.put("excludedhashingalgorithms", excludedHashing);
+ }
+ if (!obsoleteHashing.isEmpty()) {
+ vpnParams.put("obsoletehashingalgorithms", obsoleteHashing);
+ }
+ if (!excludedIkeVersions.isEmpty()) {
+ vpnParams.put("excludedikeversions", excludedIkeVersions);
+ }
+ if (!obsoleteIkeVersions.isEmpty()) {
+ vpnParams.put("obsoleteikeversions", obsoleteIkeVersions);
+ }
+ if (!excludedDhGroup.isEmpty()) {
+ vpnParams.put("excludeddhgroups", excludedDhGroup);
+ }
+ if (!obsoleteDhGroup.isEmpty()) {
+ vpnParams.put("obsoletedhgroups", obsoleteDhGroup);
+ }
+ return vpnParams;
+ }
+
@Override
public GuestOSVO getGuestOs(final Long guestOsId) {
return _guestOSDao.findById(guestOsId);
diff --git a/server/src/main/java/com/cloud/server/StatsCollector.java b/server/src/main/java/com/cloud/server/StatsCollector.java
index b6637aa..049ed45 100644
--- a/server/src/main/java/com/cloud/server/StatsCollector.java
+++ b/server/src/main/java/com/cloud/server/StatsCollector.java
@@ -986,7 +986,7 @@
double totalcpucap = 0;
if (StringUtils.isEmpty(cpucaps)) {
String totalCpus = Script.runSimpleBashScript("nproc --all| tr '\\n' \" \"");
- String maxCpuSpeed = Script.runSimpleBashScript("lscpu | egrep 'CPU max MHz' | head -1 | cut -f 2 -d : | tr -d ' '| tr '\\n' \" \"");
+ String maxCpuSpeed = Script.runSimpleBashScript("lscpu | grep -E 'CPU max MHz' | head -1 | cut -f 2 -d : | tr -d ' '| tr '\\n' \" \"");
if (StringUtils.isNotEmpty(totalCpus) && StringUtils.isNotEmpty(maxCpuSpeed)) {
totalcpucap = Double.parseDouble(totalCpus) * Double.parseDouble(maxCpuSpeed);
}
diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
index 9f9928b..1f453a8 100644
--- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
@@ -56,10 +56,6 @@
import javax.inject.Inject;
-import com.cloud.dc.HostPodVO;
-import com.cloud.dc.dao.HostPodDao;
-import com.cloud.resource.ResourceManager;
-import com.cloud.storage.dao.StoragePoolAndAccessGroupMapDao;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiConstants;
@@ -189,9 +185,11 @@
import com.cloud.cpu.CPU;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.HostPodVO;
import com.cloud.dc.VsphereStoragePolicyVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.VsphereStoragePolicyDao;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
@@ -218,6 +216,7 @@
import com.cloud.offering.ServiceOffering;
import com.cloud.org.Grouping;
import com.cloud.org.Grouping.AllocationState;
+import com.cloud.resource.ResourceManager;
import com.cloud.resource.ResourceState;
import com.cloud.server.ConfigurationServer;
import com.cloud.server.ManagementServer;
@@ -230,6 +229,7 @@
import com.cloud.storage.dao.BucketDao;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.SnapshotDao;
+import com.cloud.storage.dao.StoragePoolAndAccessGroupMapDao;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.StoragePoolTagsDao;
import com.cloud.storage.dao.StoragePoolWorkDao;
@@ -4019,7 +4019,8 @@
return;
}
String templateName = getValidTemplateName(zoneId, hypervisorType);
- VMTemplateVO registeredTemplate = systemVmTemplateRegistration.getRegisteredTemplate(templateName, arch);
+ VMTemplateVO registeredTemplate = systemVmTemplateRegistration.getRegisteredTemplate(templateName,
+ hypervisorType, arch, url);
TemplateDataStoreVO templateDataStoreVO = null;
if (registeredTemplate != null) {
templateDataStoreVO = _templateStoreDao.findByStoreTemplate(store.getId(), registeredTemplate.getId());
@@ -4035,56 +4036,57 @@
}
}
SystemVmTemplateRegistration.mountStore(storeUrlAndId.first(), filePath, nfsVersion);
- if (templateDataStoreVO != null) {
- systemVmTemplateRegistration.validateAndRegisterTemplate(hypervisorType, templateName,
- storeUrlAndId.second(), registeredTemplate, templateDataStoreVO, filePath);
+ if (registeredTemplate != null) {
+ systemVmTemplateRegistration.validateAndAddTemplateToStore(registeredTemplate, templateDataStoreVO, zoneId,
+ storeUrlAndId.second(), filePath);
} else {
- systemVmTemplateRegistration.validateAndRegisterTemplateForNonExistingEntries(hypervisorType, arch,
- templateName, storeUrlAndId, filePath);
+ systemVmTemplateRegistration.validateAndRegisterNewTemplate(hypervisorType, arch, templateName, zoneId,
+ storeUrlAndId.second(), filePath);
}
}
private void registerSystemVmTemplateOnFirstNfsStore(Long zoneId, String providerName, String url, DataStore store) {
- if (DataStoreProvider.NFS_IMAGE.equals(providerName) && zoneId != null) {
- Transaction.execute(new TransactionCallbackNoReturn() {
- @Override
- public void doInTransactionWithoutResult(final TransactionStatus status) {
- List<ImageStoreVO> stores = _imageStoreDao.listAllStoresInZoneExceptId(zoneId, providerName,
- DataStoreRole.Image, store.getId());
- if (CollectionUtils.isEmpty(stores)) {
- List<Pair<HypervisorType, CPU.CPUArch>> hypervisorTypes =
- _clusterDao.listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
- TransactionLegacy txn = TransactionLegacy.open("AutomaticTemplateRegister");
- SystemVmTemplateRegistration systemVmTemplateRegistration = new SystemVmTemplateRegistration();
- String filePath = null;
- try {
- filePath = Files.createTempDirectory(SystemVmTemplateRegistration.TEMPORARY_SECONDARY_STORE).toString();
- if (filePath == null) {
- throw new CloudRuntimeException("Failed to create temporary file path to mount the store");
+ if (zoneId == null || !DataStoreProvider.NFS_IMAGE.equals(providerName)) {
+ logger.debug("Skipping system VM template registration as either zoneId is null or {} " +
+ "provider is not NFS", store);
+ return;
+ }
+ Transaction.execute(new TransactionCallbackNoReturn() {
+ @Override
+ public void doInTransactionWithoutResult(final TransactionStatus status) {
+ List<ImageStoreVO> stores = _imageStoreDao.listAllStoresInZoneExceptId(zoneId, providerName,
+ DataStoreRole.Image, store.getId());
+ if (CollectionUtils.isEmpty(stores)) {
+ List<Pair<HypervisorType, CPU.CPUArch>> hypervisorArchTypes =
+ _clusterDao.listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
+ TransactionLegacy txn = TransactionLegacy.open("AutomaticTemplateRegister");
+ SystemVmTemplateRegistration systemVmTemplateRegistration = new SystemVmTemplateRegistration();
+ String filePath = null;
+ try {
+ filePath = Files.createTempDirectory(SystemVmTemplateRegistration.TEMPORARY_SECONDARY_STORE)
+ .toString();
+ Pair<String, Long> storeUrlAndId = new Pair<>(url, store.getId());
+ String nfsVersion = imageStoreDetailsUtil.getNfsVersion(store.getId());
+ for (Pair<HypervisorType, CPU.CPUArch> hypervisorArchType : hypervisorArchTypes) {
+ try {
+ registerSystemVmTemplateForHypervisorArch(hypervisorArchType.first(),
+ hypervisorArchType.second(), zoneId, url, store,
+ systemVmTemplateRegistration, filePath, storeUrlAndId, nfsVersion);
+ } catch (CloudRuntimeException e) {
+ SystemVmTemplateRegistration.unmountStore(filePath);
+ logger.error("Failed to register system VM template for hypervisor: {} {}",
+ hypervisorArchType.first().name(), hypervisorArchType.second().name(), e);
}
- Pair<String, Long> storeUrlAndId = new Pair<>(url, store.getId());
- String nfsVersion = imageStoreDetailsUtil.getNfsVersion(store.getId());
- for (Pair<HypervisorType, CPU.CPUArch> hypervisorArchType : hypervisorTypes) {
- try {
- registerSystemVmTemplateForHypervisorArch(hypervisorArchType.first(),
- hypervisorArchType.second(), zoneId, url, store,
- systemVmTemplateRegistration, filePath, storeUrlAndId, nfsVersion);
- } catch (CloudRuntimeException e) {
- SystemVmTemplateRegistration.unmountStore(filePath);
- logger.error("Failed to register system VM template for hypervisor: {} {}",
- hypervisorArchType.first().name(), hypervisorArchType.second().name(), e);
- }
- }
- } catch (Exception e) {
- logger.error("Failed to register systemVM template(s) due to: ", e);
- } finally {
- SystemVmTemplateRegistration.unmountStore(filePath);
- txn.close();
}
+ } catch (Exception e) {
+ logger.error("Failed to register systemVM template(s) due to: ", e);
+ } finally {
+ SystemVmTemplateRegistration.unmountStore(filePath);
+ txn.close();
}
}
- });
- }
+ }
+ });
}
@Override
public ImageStore migrateToObjectStore(String name, String url, String providerName, Map<String, String> details) throws DiscoveryException, InvalidParameterValueException {
diff --git a/server/src/main/java/com/cloud/storage/StoragePoolAutomationImpl.java b/server/src/main/java/com/cloud/storage/StoragePoolAutomationImpl.java
index f03a591..7121f46 100644
--- a/server/src/main/java/com/cloud/storage/StoragePoolAutomationImpl.java
+++ b/server/src/main/java/com/cloud/storage/StoragePoolAutomationImpl.java
@@ -273,7 +273,7 @@
_storagePoolWorkDao.persist(work);
} catch (Exception e) {
if (logger.isDebugEnabled()) {
- logger.debug("Work record already exists, re-using by re-setting values");
+ logger.debug("Work record already exists, reusing by re-setting values");
}
StoragePoolWorkVO work = _storagePoolWorkDao.findByPoolIdAndVmId(pool.getId(), vmInstance.getId());
work.setStartedAfterMaintenance(false);
diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index ca3d31d..31bf80e 100644
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@ -504,9 +504,10 @@
GetUploadParamsResponse response = new GetUploadParamsResponse();
String ssvmUrlDomain = _configDao.getValue(Config.SecStorageSecureCopyCert.key());
- String protocol = UseHttpsToUpload.value() ? "https" : "http";
+ String protocol = UseHttpsToUpload.valueIn(zoneId) ? "https" : "http";
- String url = ImageStoreUtil.generatePostUploadUrl(ssvmUrlDomain, ep.getPublicAddr(), vol.getUuid(), protocol);
+ String url = ImageStoreUtil.generatePostUploadUrl(ssvmUrlDomain, ep.getPublicAddr(), vol.getUuid(),
+ protocol);
response.setPostURL(new URL(url));
// set the post url, this is used in the monitoring thread to determine the SSVM
@@ -526,8 +527,10 @@
/*
* encoded metadata using the post upload config key
*/
- TemplateOrVolumePostUploadCommand command = new TemplateOrVolumePostUploadCommand(vol.getId(), vol.getUuid(), volumeStore.getInstallPath(), cmd.getChecksum(), vol.getType().toString(),
- vol.getName(), vol.getFormat().toString(), dataObject.getDataStore().getUri(), dataObject.getDataStore().getRole().toString());
+ TemplateOrVolumePostUploadCommand command = new TemplateOrVolumePostUploadCommand(vol.getId(),
+ vol.getUuid(), volumeStore.getInstallPath(), cmd.getChecksum(), vol.getType().toString(),
+ vol.getName(), vol.getFormat().toString(), dataObject.getDataStore().getUri(),
+ dataObject.getDataStore().getRole().toString(), zoneId);
command.setLocalPath(volumeStore.getLocalDownloadPath());
//using the existing max upload size configuration
command.setProcessTimeout(NumbersUtil.parseLong(_configDao.getValue("vmware.package.ova.timeout"), 3600));
@@ -2179,14 +2182,16 @@
}
Collections.shuffle(suitableStoragePoolsWithEnoughSpace);
MigrateVolumeCmd migrateVolumeCmd = new MigrateVolumeCmd(volume.getId(), suitableStoragePoolsWithEnoughSpace.get(0).getId(), newDiskOffering.getId(), true);
+ String volumeUuid = volume.getUuid();
try {
Volume result = migrateVolume(migrateVolumeCmd);
volume = (result != null) ? _volsDao.findById(result.getId()) : null;
if (volume == null) {
- throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume: %s migration failed to storage pool %s", volume, suitableStoragePools.get(0)));
+ throw new CloudRuntimeException("Change offering for the volume failed.");
}
} catch (Exception e) {
- throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume: %s migration failed to storage pool %s due to %s", volume, suitableStoragePools.get(0), e.getMessage()));
+ logger.error("Volume change offering operation failed for volume ID: {} migration failed to storage pool {} due to {}", volumeUuid, suitableStoragePoolsWithEnoughSpace.get(0).getId(), e.getMessage());
+ throw new CloudRuntimeException("Change offering for the volume failed.", e);
}
}
@@ -2199,7 +2204,7 @@
if (volumeMigrateRequired) {
logger.warn(String.format("Volume change offering operation succeeded for volume ID: %s but volume resize operation failed, so please try resize volume operation separately", volume.getUuid()));
} else {
- throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume ID: %s due to resize volume operation failed", volume.getUuid()));
+ throw new CloudRuntimeException(String.format("Volume disk offering change operation failed for volume ID [%s] because the volume resize operation failed.", volume.getUuid()));
}
}
}
diff --git a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManager.java b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManager.java
index b245a37..10dcc26 100644
--- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManager.java
+++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManager.java
@@ -68,7 +68,9 @@
"Whether to show chain size (sum of physical size of snapshot and all its parents) for incremental snapshots in the snapshot response",
true, ConfigKey.Scope.Global, null);
- public static final ConfigKey<Boolean> UseStorageReplication = new ConfigKey<Boolean>(Boolean.class, "use.storage.replication", "Snapshots", "false", "For snapshot copy to another primary storage in a different zone. Supports only StorPool storage for now", true, ConfigKey.Scope.StoragePool, null);
+ ConfigKey<Boolean> UseStorageReplication = new ConfigKey<>(Boolean.class, "use.storage.replication", "Snapshots", "false",
+ "For snapshot copy to another primary storage in a different zone. This is supported only for StorPool storage for now.",
+ true, ConfigKey.Scope.StoragePool, null);
void deletePoliciesForVolume(Long volumeId);
diff --git a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index 900c59a..b5a03d1 100755
--- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -587,8 +587,9 @@
}
if (ObjectUtils.anyNull(chosenStore, snapshotDataStoreReference)) {
- logger.error("Snapshot [{}] not found in any secondary storage.", snapshot);
- throw new InvalidParameterValueException("Snapshot not found.");
+ String errorMessage = String.format("Snapshot [%s] not found in any secondary storage. The snapshot may be on primary storage, where it cannot be downloaded.", snapshot.getUuid());
+ logger.error(errorMessage);
+ throw new InvalidParameterValueException(errorMessage);
}
snapshotSrv.syncVolumeSnapshotsToRegionStore(snapshot.getVolumeId(), chosenStore);
diff --git a/server/src/main/java/com/cloud/template/TemplateAdapterBase.java b/server/src/main/java/com/cloud/template/TemplateAdapterBase.java
index da620a3..b50aced 100644
--- a/server/src/main/java/com/cloud/template/TemplateAdapterBase.java
+++ b/server/src/main/java/com/cloud/template/TemplateAdapterBase.java
@@ -234,9 +234,10 @@
throw new CloudRuntimeException(errMsg);
}
- TemplateOrVolumePostUploadCommand payload = new TemplateOrVolumePostUploadCommand(template.getId(), template.getUuid(), tmpl.getInstallPath(), tmpl
- .getChecksum(), tmpl.getType().toString(), template.getUniqueName(), template.getFormat().toString(), templateOnStore.getDataStore().getUri(),
- templateOnStore.getDataStore().getRole().toString());
+ TemplateOrVolumePostUploadCommand payload = new TemplateOrVolumePostUploadCommand(template.getId(),
+ template.getUuid(), tmpl.getInstallPath(), tmpl.getChecksum(), tmpl.getType().toString(),
+ template.getUniqueName(), template.getFormat().toString(), templateOnStore.getDataStore().getUri(),
+ templateOnStore.getDataStore().getRole().toString(), zoneId_is);
//using the existing max template size configuration
payload.setMaxUploadSize(_configDao.getValue(Config.MaxTemplateAndIsoSize.key()));
diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
index 4699be6..0b05a0d 100755
--- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
@@ -415,7 +415,7 @@
TemplateOrVolumePostUploadCommand firstCommand = payload.get(0);
String ssvmUrlDomain = _configDao.getValue(Config.SecStorageSecureCopyCert.key());
- String protocol = VolumeApiService.UseHttpsToUpload.value() ? "https" : "http";
+ String protocol = VolumeApiService.UseHttpsToUpload.valueIn(firstCommand.getZoneId()) ? "https" : "http";
String url = ImageStoreUtil.generatePostUploadUrl(ssvmUrlDomain, firstCommand.getRemoteEndPoint(), firstCommand.getEntityUUID(), protocol);
response.setPostURL(new URL(url));
diff --git a/server/src/main/java/com/cloud/test/IPRangeConfig.java b/server/src/main/java/com/cloud/test/IPRangeConfig.java
index 22ebb56..e041f73 100644
--- a/server/src/main/java/com/cloud/test/IPRangeConfig.java
+++ b/server/src/main/java/com/cloud/test/IPRangeConfig.java
@@ -77,7 +77,6 @@
}
String pod = args[2];
String zone = args[3];
- ;
String startIP = args[4];
String endIP = null;
if (args.length == 6) {
@@ -99,31 +98,6 @@
}
}
- public List<String> changePublicIPRangeGUI(String op, String zone, String startIP, String endIP, long physicalNetworkId) {
- String result = checkErrors("public", op, null, zone, startIP, endIP);
- if (!result.equals("success")) {
- return DatabaseConfig.genReturnList("false", result);
- }
-
- long zoneId = PodZoneConfig.getZoneId(zone);
- result = changeRange(op, "public", -1, zoneId, startIP, endIP, null, physicalNetworkId);
-
- return DatabaseConfig.genReturnList("true", result);
- }
-
- public List<String> changePrivateIPRangeGUI(String op, String pod, String zone, String startIP, String endIP) {
- String result = checkErrors("private", op, pod, zone, startIP, endIP);
- if (!result.equals("success")) {
- return DatabaseConfig.genReturnList("false", result);
- }
-
- long podId = PodZoneConfig.getPodId(pod, zone);
- long zoneId = PodZoneConfig.getZoneId(zone);
- result = changeRange(op, "private", podId, zoneId, startIP, endIP, null, -1);
-
- return DatabaseConfig.genReturnList("true", result);
- }
-
private String checkErrors(String type, String op, String pod, String zone, String startIP, String endIP) {
if (!op.equals("add") && !op.equals("delete")) {
return usage();
@@ -153,15 +127,7 @@
}
// Check that the IPs that are being added are compatible with either the zone's public netmask, or the pod's CIDR
- if (type.equals("public")) {
- // String publicNetmask = getPublicNetmask(zone);
- // String publicGateway = getPublicGateway(zone);
-
- // if (publicNetmask == null) return "Please ensure that your zone's public net mask is specified";
- // if (!sameSubnet(startIP, endIP, publicNetmask)) return "Please ensure that your start IP and end IP are in the same subnet, as per the zone's netmask.";
- // if (!sameSubnet(startIP, publicGateway, publicNetmask)) return "Please ensure that your start IP is in the same subnet as your zone's gateway, as per the zone's netmask.";
- // if (!sameSubnet(endIP, publicGateway, publicNetmask)) return "Please ensure that your end IP is in the same subnet as your zone's gateway, as per the zone's netmask.";
- } else if (type.equals("private")) {
+ if (type.equals("private")) {
String cidrAddress = getCidrAddress(pod, zone);
long cidrSize = getCidrSize(pod, zone);
diff --git a/server/src/main/java/com/cloud/test/PodZoneConfig.java b/server/src/main/java/com/cloud/test/PodZoneConfig.java
index 7cd6cb1..2d32621 100644
--- a/server/src/main/java/com/cloud/test/PodZoneConfig.java
+++ b/server/src/main/java/com/cloud/test/PodZoneConfig.java
@@ -75,11 +75,6 @@
}
private String checkPodCidrSubnets(long dcId, HashMap<Long, Vector<Object>> currentPodCidrSubnets) {
-
-// DataCenterDao _dcDao = null;
-// final ComponentLocator locator = ComponentLocator.getLocator("management-server");
-
-// _dcDao = locator.getDao(DataCenterDao.class);
// For each pod, return an error if any of the following is true:
// 1. The pod's CIDR subnet conflicts with the guest network subnet
// 2. The pod's CIDR subnet conflicts with the CIDR subnet of any other pod
@@ -87,7 +82,6 @@
String zoneName = PodZoneConfig.getZoneName(dcId);
//get the guest network cidr and guest netmask from the zone
-// DataCenterVO dcVo = _dcDao.findById(dcId);
String guestNetworkCidr = IPRangeConfig.getGuestNetworkCidr(dcId);
diff --git a/server/src/main/java/com/cloud/user/AccountManagerImpl.java b/server/src/main/java/com/cloud/user/AccountManagerImpl.java
index dd60fbf..53b8869 100644
--- a/server/src/main/java/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/main/java/com/cloud/user/AccountManagerImpl.java
@@ -67,6 +67,7 @@
import org.apache.cloudstack.auth.UserAuthenticator;
import org.apache.cloudstack.auth.UserAuthenticator.ActionOnFailedAuthentication;
import org.apache.cloudstack.auth.UserTwoFactorAuthenticator;
+import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.config.ApiServiceConfiguration;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
@@ -3461,7 +3462,7 @@
}
@Override
- public Long finalyzeAccountId(final String accountName, final Long domainId, final Long projectId, final boolean enabledOnly) {
+ public Long finalizeAccountId(final String accountName, final Long domainId, final Long projectId, final boolean enabledOnly) {
if (accountName != null) {
if (domainId == null) {
throw new InvalidParameterValueException("Account must be specified with domainId parameter");
@@ -3575,6 +3576,21 @@
}
@Override
+ public void checkAccess(Account account, BackupOffering bof) throws PermissionDeniedException {
+ for (SecurityChecker checker : _securityCheckers) {
+ if (checker.checkAccess(account, bof)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Access granted to " + account + " to " + bof + " by " + checker.getName());
+ }
+ return;
+ }
+ }
+
+ assert false : "How can all of the security checkers pass on checking this caller?";
+ throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + bof);
+ }
+
+ @Override
public void checkAccess(User user, ControlledEntity entity) throws PermissionDeniedException {
for (SecurityChecker checker : _securityCheckers) {
if (checker.checkAccess(user, entity)) {
diff --git a/server/src/main/java/com/cloud/utils/DomainHelper.java b/server/src/main/java/com/cloud/utils/DomainHelper.java
new file mode 100644
index 0000000..480726d
--- /dev/null
+++ b/server/src/main/java/com/cloud/utils/DomainHelper.java
@@ -0,0 +1,63 @@
+// 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.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import javax.inject.Inject;
+
+import org.springframework.stereotype.Component;
+
+import com.cloud.domain.dao.DomainDao;
+
+@Component
+public class DomainHelper {
+
+ @Inject
+ private DomainDao domainDao;
+
+ /**
+ *
+ * @param domainIds List of domain IDs to filter
+ * @return Filtered list containing only domains that are not descendants of other domains in the list
+ */
+ public List<Long> filterChildSubDomains(final List<Long> domainIds) {
+ if (domainIds == null || domainIds.size() <= 1) {
+ return domainIds == null ? new ArrayList<>() : new ArrayList<>(domainIds);
+ }
+
+ final List<Long> result = new ArrayList<>();
+ for (final Long candidate : domainIds) {
+ boolean isDescendant = false;
+ for (final Long other : domainIds) {
+ if (Objects.equals(candidate, other)) {
+ continue;
+ }
+ if (domainDao.isChildDomain(other, candidate)) {
+ isDescendant = true;
+ break;
+ }
+ }
+ if (!isDescendant) {
+ result.add(candidate);
+ }
+ }
+ return result;
+ }
+}
diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index eccea94..b9b6e5a 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -2866,6 +2866,22 @@
}
}
+ protected void updateVmExtraConfig(UserVmVO userVm, String extraConfig, boolean cleanupExtraConfig) {
+ if (cleanupExtraConfig) {
+ logger.info("Cleaning up extraconfig from user vm: {}", userVm.getUuid());
+ vmInstanceDetailsDao.removeDetailsWithPrefix(userVm.getId(), ApiConstants.EXTRA_CONFIG);
+ return;
+ }
+ if (StringUtils.isNotBlank(extraConfig)) {
+ if (EnableAdditionalVmConfig.valueIn(userVm.getAccountId())) {
+ logger.info("Adding extra configuration to user vm: {}", userVm.getUuid());
+ addExtraConfig(userVm, extraConfig);
+ } else {
+ throw new InvalidParameterValueException("attempted setting extraconfig but enable.additional.vm.configuration is disabled");
+ }
+ }
+ }
+
@Override
@ActionEvent(eventType = EventTypes.EVENT_VM_UPDATE, eventDescription = "updating Vm")
public UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException {
@@ -2883,6 +2899,7 @@
List<Long> securityGroupIdList = getSecurityGroupIdList(cmd);
boolean cleanupDetails = cmd.isCleanupDetails();
String extraConfig = cmd.getExtraConfig();
+ boolean cleanupExtraConfig = cmd.isCleanupExtraConfig();
UserVmVO vmInstance = _vmDao.findById(cmd.getId());
VMTemplateVO template = _templateDao.findById(vmInstance.getTemplateId());
@@ -2919,7 +2936,7 @@
.map(item -> (item).trim())
.collect(Collectors.toList());
List<VMInstanceDetailVO> existingDetails = vmInstanceDetailsDao.listDetails(id);
- if (cleanupDetails){
+ if (cleanupDetails) {
if (caller != null && caller.getType() == Account.Type.ADMIN) {
for (final VMInstanceDetailVO detail : existingDetails) {
if (detail != null && detail.isDisplay() && !isExtraConfig(detail.getName())) {
@@ -2982,15 +2999,8 @@
vmInstance.setDetails(details);
_vmDao.saveDetails(vmInstance);
}
- if (StringUtils.isNotBlank(extraConfig)) {
- if (EnableAdditionalVmConfig.valueIn(accountId)) {
- logger.info("Adding extra configuration to user vm: " + vmInstance.getUuid());
- addExtraConfig(vmInstance, extraConfig);
- } else {
- throw new InvalidParameterValueException("attempted setting extraconfig but enable.additional.vm.configuration is disabled");
- }
- }
}
+ updateVmExtraConfig(userVm, extraConfig, cleanupExtraConfig);
if (VMLeaseManager.InstanceLeaseEnabled.value() && cmd.getLeaseDuration() != null) {
applyLeaseOnUpdateInstance(vmInstance, cmd.getLeaseDuration(), cmd.getLeaseExpiryAction());
diff --git a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
index 617a4e5..d5e25ad 100644
--- a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
@@ -400,10 +400,11 @@
_accountMgr.checkAccess(caller, null, true, userVmVo);
// check max snapshot limit for per VM
- int vmSnapshotMax = VMSnapshotManager.VMSnapshotMax.value();
-
+ boolean vmBelongsToProject = _accountMgr.getAccount(userVmVo.getAccountId()).getType() == Account.Type.PROJECT;
+ long accountIdToRetrieveConfigurationValueFrom = vmBelongsToProject ? caller.getId() : userVmVo.getAccountId();
+ int vmSnapshotMax = VMSnapshotManager.VMSnapshotMax.valueIn(accountIdToRetrieveConfigurationValueFrom);
if (_vmSnapshotDao.findByVm(vmId).size() >= vmSnapshotMax) {
- throw new CloudRuntimeException("Creating Instance Snapshot failed due to a Instance can just have : " + vmSnapshotMax + " Instance Snapshots. Please delete old ones");
+ throw new CloudRuntimeException(String.format("Each VM can have at most [%s] VM snapshots.", vmSnapshotMax));
}
// check if there are active volume snapshots tasks
diff --git a/server/src/main/java/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/main/java/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java
index 650d52f..d212e74 100644
--- a/server/src/main/java/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java
@@ -286,7 +286,7 @@
if(account == null && domainId != null){
group = _affinityGroupDao.findDomainLevelGroupByName(domainId, affinityGroupName);
}else{
- Long accountId = _accountMgr.finalyzeAccountId(account, domainId, projectId, true);
+ Long accountId = _accountMgr.finalizeAccountId(account, domainId, projectId, true);
if(accountId == null){
Account caller = CallContext.current().getCallingAccount();
group = _affinityGroupDao.findByAccountAndName(caller.getAccountId(), affinityGroupName);
diff --git a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java
index 5fac89d..f2c1728 100644
--- a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java
@@ -38,6 +38,7 @@
import javax.inject.Inject;
import javax.naming.ConfigurationException;
+import com.cloud.utils.DomainHelper;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.InternalIdentity;
@@ -68,6 +69,7 @@
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.dao.BackupDetailsDao;
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
+import org.apache.cloudstack.backup.dao.BackupOfferingDetailsDao;
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
@@ -81,12 +83,12 @@
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
-import com.amazonaws.util.CollectionUtils;
import com.cloud.alert.AlertManager;
import com.cloud.api.ApiDispatcher;
import com.cloud.api.ApiGsonHelper;
@@ -184,6 +186,8 @@
@Inject
private BackupOfferingDao backupOfferingDao;
@Inject
+ private BackupOfferingDetailsDao backupOfferingDetailsDao;
+ @Inject
private VMInstanceDao vmInstanceDao;
@Inject
private AccountService accountService;
@@ -237,6 +241,8 @@
private AlertManager alertManager;
@Inject
private GuestOSDao _guestOSDao;
+ @Inject
+ private DomainHelper domainHelper;
private AsyncJobDispatcher asyncJobDispatcher;
private Timer backupTimer;
@@ -280,6 +286,20 @@
throw new CloudRuntimeException("A backup offering with the same name already exists in this zone");
}
+ if (CollectionUtils.isNotEmpty(cmd.getDomainIds())) {
+ for (final Long domainId: cmd.getDomainIds()) {
+ if (domainDao.findById(domainId) == null) {
+ throw new InvalidParameterValueException("Please specify a valid domain id");
+ }
+ }
+ }
+
+ final Account caller = CallContext.current().getCallingAccount();
+ List<Long> filteredDomainIds = cmd.getDomainIds() == null ? new ArrayList<>() : new ArrayList<>(cmd.getDomainIds());
+ if (filteredDomainIds.size() > 1) {
+ filteredDomainIds = domainHelper.filterChildSubDomains(filteredDomainIds);
+ }
+
final BackupProvider provider = getBackupProvider(cmd.getZoneId());
if (!provider.isValidProviderOffering(cmd.getZoneId(), cmd.getExternalId())) {
throw new CloudRuntimeException("Backup offering '" + cmd.getExternalId() + "' does not exist on provider " + provider.getName() + " on zone " + cmd.getZoneId());
@@ -292,15 +312,34 @@
if (savedOffering == null) {
throw new CloudRuntimeException("Unable to create backup offering: " + cmd.getExternalId() + ", name: " + cmd.getName());
}
+ if (CollectionUtils.isNotEmpty(filteredDomainIds)) {
+ List<BackupOfferingDetailsVO> detailsVOList = new ArrayList<>();
+ for (Long domainId : filteredDomainIds) {
+ detailsVOList.add(new BackupOfferingDetailsVO(savedOffering.getId(), ApiConstants.DOMAIN_ID, String.valueOf(domainId), false));
+ }
+ if (!detailsVOList.isEmpty()) {
+ backupOfferingDetailsDao.saveDetails(detailsVOList);
+ }
+ }
logger.debug("Successfully created backup offering " + cmd.getName() + " mapped to backup provider offering " + cmd.getExternalId());
return savedOffering;
}
@Override
+ public List<Long> getBackupOfferingDomains(Long offeringId) {
+ final BackupOffering backupOffering = backupOfferingDao.findById(offeringId);
+ if (backupOffering == null) {
+ throw new InvalidParameterValueException("Unable to find backup offering for id: " + offeringId);
+ }
+ return backupOfferingDetailsDao.findDomainIds(offeringId);
+ }
+
+ @Override
public Pair<List<BackupOffering>, Integer> listBackupOfferings(final ListBackupOfferingsCmd cmd) {
final Long offeringId = cmd.getOfferingId();
final Long zoneId = cmd.getZoneId();
final String keyword = cmd.getKeyword();
+ Long domainId = cmd.getDomainId();
if (offeringId != null) {
BackupOfferingVO offering = backupOfferingDao.findById(offeringId);
@@ -317,6 +356,10 @@
CallContext ctx = CallContext.current();
final Account caller = ctx.getCallingAccount();
+ if (Account.Type.ADMIN != caller.getType() && domainId == null) {
+ domainId = caller.getDomainId();
+ }
+
if (Account.Type.NORMAL == caller.getType()) {
sb.and("user_backups_allowed", sb.entity().isUserDrivenBackupAllowed(), SearchCriteria.Op.EQ);
}
@@ -329,10 +372,36 @@
if (keyword != null) {
sc.setParameters("name", "%" + keyword + "%");
}
+
+ if (Account.Type.NORMAL == caller.getType()) {
+ sc.setParameters("user_backups_allowed", true);
+ }
+
Pair<List<BackupOfferingVO>, Integer> result = backupOfferingDao.searchAndCount(sc, searchFilter);
+
+ if (domainId != null) {
+ List<BackupOfferingVO> filteredOfferings = new ArrayList<>();
+ for (BackupOfferingVO offering : result.first()) {
+ List<Long> offeringDomains = backupOfferingDetailsDao.findDomainIds(offering.getId());
+ if (offeringDomains.isEmpty() || offeringDomains.contains(domainId) || containsParentDomain(offeringDomains, domainId)) {
+ filteredOfferings.add(offering);
+ }
+ }
+ return new Pair<>(new ArrayList<>(filteredOfferings), filteredOfferings.size());
+ }
+
return new Pair<>(new ArrayList<>(result.first()), result.second());
}
+ private boolean containsParentDomain(List<Long> offeringDomains, Long domainId) {
+ for (Long offeringDomainId : offeringDomains) {
+ if (domainDao.isChildDomain(offeringDomainId, domainId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public boolean deleteBackupOffering(final Long offeringId) {
final BackupOfferingVO offering = backupOfferingDao.findById(offeringId);
@@ -340,6 +409,8 @@
throw new CloudRuntimeException("Could not find a backup offering with id: " + offeringId);
}
+ accountManager.checkAccess(CallContext.current().getCallingAccount(), offering);
+
if (backupDao.listByOfferingId(offering.getId()).size() > 0) {
throw new CloudRuntimeException("Backup Offering cannot be removed as it has backups associated with it.");
}
@@ -450,6 +521,12 @@
throw new CloudRuntimeException("Provided backup offering does not exist");
}
+ Account owner = accountManager.getAccount(vm.getAccountId());
+ if (owner == null) {
+ throw new CloudRuntimeException("Unable to find the owner of the VM");
+ }
+ accountManager.checkAccess(owner, offering);
+
final BackupProvider backupProvider = getBackupProvider(offering.getProvider());
if (backupProvider == null) {
throw new CloudRuntimeException("Failed to get the backup provider for the zone, please contact the administrator");
@@ -760,10 +837,11 @@
@ActionEvent(eventType = EventTypes.EVENT_VM_BACKUP_CREATE, eventDescription = "creating VM backup", async = true)
public boolean createBackup(CreateBackupCmd cmd, Object job) throws ResourceAllocationException {
Long vmId = cmd.getVmId();
+ Account caller = CallContext.current().getCallingAccount();
final VMInstanceVO vm = findVmById(vmId);
validateBackupForZone(vm.getDataCenterId());
- accountManager.checkAccess(CallContext.current().getCallingAccount(), null, true, vm);
+ accountManager.checkAccess(caller, null, true, vm);
if (vm.getBackupOfferingId() == null) {
throw new CloudRuntimeException("VM has not backup offering configured, cannot create backup before assigning it to a backup offering");
@@ -1063,7 +1141,7 @@
}
// This is done to handle historic backups if any with Veeam / Networker plugins
- List<Backup.VolumeInfo> backupVolumes = CollectionUtils.isNullOrEmpty(backup.getBackedUpVolumes()) ?
+ List<Backup.VolumeInfo> backupVolumes = CollectionUtils.isEmpty(backup.getBackedUpVolumes()) ?
vm.getBackupVolumeList() : backup.getBackedUpVolumes();
List<VolumeVO> vmVolumes = volumeDao.findByInstance(vm.getId());
if (vmVolumes.size() != backupVolumes.size()) {
@@ -2110,11 +2188,15 @@
String name = updateBackupOfferingCmd.getName();
String description = updateBackupOfferingCmd.getDescription();
Boolean allowUserDrivenBackups = updateBackupOfferingCmd.getAllowUserDrivenBackups();
+ List<Long> domainIds = updateBackupOfferingCmd.getDomainIds();
BackupOfferingVO backupOfferingVO = backupOfferingDao.findById(id);
if (backupOfferingVO == null) {
throw new InvalidParameterValueException(String.format("Unable to find Backup Offering with id: [%s].", id));
}
+
+ accountManager.checkAccess(CallContext.current().getCallingAccount(), backupOfferingVO);
+
logger.debug("Trying to update Backup Offering {} to {}.",
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(backupOfferingVO, "uuid", "name", "description", "userDrivenBackupAllowed"),
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(updateBackupOfferingCmd, "name", "description", "allowUserDrivenBackups"));
@@ -2137,16 +2219,43 @@
fields.add("allowUserDrivenBackups: " + allowUserDrivenBackups);
}
- if (!backupOfferingDao.update(id, offering)) {
+ if (CollectionUtils.isNotEmpty(domainIds)) {
+ for (final Long domainId: domainIds) {
+ if (domainDao.findById(domainId) == null) {
+ throw new InvalidParameterValueException("Please specify a valid domain id");
+ }
+ }
+ }
+ List<Long> filteredDomainIds = domainHelper.filterChildSubDomains(domainIds);
+ Collections.sort(filteredDomainIds);
+
+ boolean success = backupOfferingDao.update(id, offering);
+ if (!success) {
logger.warn(String.format("Couldn't update Backup offering (%s) with [%s].", backupOfferingVO, String.join(", ", fields)));
}
+ if (success || fields.isEmpty()) {
+ List<Long> existingDomainIds = backupOfferingDetailsDao.findDomainIds(id);
+ Collections.sort(existingDomainIds);
+ updateBackupOfferingDomainDetails(id, filteredDomainIds, existingDomainIds);
+ }
+
BackupOfferingVO response = backupOfferingDao.findById(id);
CallContext.current().setEventDetails(String.format("Backup Offering updated [%s].",
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(response, "id", "name", "description", "userDrivenBackupAllowed", "externalId")));
return response;
}
+ private void updateBackupOfferingDomainDetails(Long id, List<Long> filteredDomainIds, List<Long> existingDomainIds) {
+ if (existingDomainIds == null) {
+ existingDomainIds = new ArrayList<>();
+ }
+
+ if(!filteredDomainIds.equals(existingDomainIds)) {
+ backupOfferingDetailsDao.updateBackupOfferingDomainIdsDetail(id, filteredDomainIds);
+ }
+ }
+
Map<String, String> getDetailsFromBackupDetails(Long backupId) {
Map<String, String> details = backupDetailsDao.listDetailsKeyPairs(backupId, true);
if (details == null) {
@@ -2268,7 +2377,7 @@
return;
}
List<Backup> backupsForVm = backupDao.listByVmIdAndOffering(vm.getDataCenterId(), vm.getId(), vm.getBackupOfferingId());
- if (org.apache.commons.collections.CollectionUtils.isEmpty(backupsForVm)) {
+ if (CollectionUtils.isEmpty(backupsForVm)) {
removeVMFromBackupOffering(vm.getId(), true);
} else {
throw new CloudRuntimeException(String.format("This Instance [uuid: %s, name: %s] has a "
diff --git a/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java b/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
index 005e24a..4de1ab3 100644
--- a/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
@@ -423,7 +423,7 @@
}
/**
- * Return pretified PEM certificate
+ * Return prettified PEM certificate
*/
protected String getPretifiedCertificate(String certificateCer) {
String cert = certificateCer.replaceAll("(.{64})", "$1\n");
diff --git a/server/src/main/java/org/apache/cloudstack/network/RoutedIpv4ManagerImpl.java b/server/src/main/java/org/apache/cloudstack/network/RoutedIpv4ManagerImpl.java
index ac12dc3..5e49872 100644
--- a/server/src/main/java/org/apache/cloudstack/network/RoutedIpv4ManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/network/RoutedIpv4ManagerImpl.java
@@ -229,7 +229,7 @@
Long accountId = null;
if (accountName != null || (projectId != null && projectId != -1L)) {
- accountId = accountManager.finalyzeAccountId(accountName, domainId, projectId, false);
+ accountId = accountManager.finalizeAccountId(accountName, domainId, projectId, false);
}
if (accountId != null) {
Account account = accountManager.getAccount(accountId);
@@ -371,7 +371,7 @@
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
}
if (accountName != null || (projectId != null && projectId != -1L)) {
- Long accountId= accountManager.finalyzeAccountId(accountName, domainId, projectId, false);
+ Long accountId= accountManager.finalizeAccountId(accountName, domainId, projectId, false);
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
}
// search via dataCenterIpv4GuestSubnetDao
@@ -394,7 +394,7 @@
}
Long accountId = null;
if (accountName != null || (projectId != null && projectId != -1L)) {
- accountId = accountManager.finalyzeAccountId(accountName, domainId, projectId, false);
+ accountId = accountManager.finalizeAccountId(accountName, domainId, projectId, false);
}
if (accountId != null) {
Account account = accountManager.getAccount(accountId);
@@ -1094,7 +1094,7 @@
Long accountId = null;
if (accountName != null || (projectId != null && projectId != -1L)) {
- accountId = accountManager.finalyzeAccountId(accountName, domainId, projectId, false);
+ accountId = accountManager.finalizeAccountId(accountName, domainId, projectId, false);
}
if (accountId != null) {
Account account = accountManager.getAccount(accountId);
@@ -1283,7 +1283,7 @@
}
Long accountId = null;
if (accountName != null || (projectId != null && projectId != -1L)) {
- accountId = accountManager.finalyzeAccountId(accountName, domainId, projectId, false);
+ accountId = accountManager.finalizeAccountId(accountName, domainId, projectId, false);
}
if (accountId != null) {
Account account = accountManager.getAccount(accountId);
@@ -1350,7 +1350,7 @@
Long accountId = null;
if (accountName != null || (projectId != null && projectId != -1L)) {
- accountId = accountManager.finalyzeAccountId(accountName, domainId, projectId, false);
+ accountId = accountManager.finalizeAccountId(accountName, domainId, projectId, false);
}
if (isDedicated != null) {
SearchCriteria sc1 = createSearchCriteriaForListBgpPeersCmd(id, zoneId, asNumber, keyword);
diff --git a/server/src/main/java/org/apache/cloudstack/storage/NfsMountManagerImpl.java b/server/src/main/java/org/apache/cloudstack/storage/NfsMountManagerImpl.java
index 0d59a6e..f06adac 100644
--- a/server/src/main/java/org/apache/cloudstack/storage/NfsMountManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/storage/NfsMountManagerImpl.java
@@ -97,7 +97,6 @@
if (nfsVersion != null){
command.add("-o", "vers=" + nfsVersion);
}
- // command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0");
if ("Mac OS X".equalsIgnoreCase(System.getProperty("os.name"))) {
command.add("-o", "resvport");
}
diff --git a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java
index 13fa260..14c6741 100644
--- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java
@@ -1550,11 +1550,12 @@
protected VMTemplateVO getTemplateForImportInstance(Long templateId, Hypervisor.HypervisorType hypervisorType) {
VMTemplateVO template;
if (templateId == null) {
- template = templateDao.findByName(VM_IMPORT_DEFAULT_TEMPLATE_NAME);
+ String templateName = (Hypervisor.HypervisorType.KVM.equals(hypervisorType)) ? KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME : VM_IMPORT_DEFAULT_TEMPLATE_NAME;
+ template = templateDao.findByName(templateName);
if (template == null) {
template = createDefaultDummyVmImportTemplate(Hypervisor.HypervisorType.KVM == hypervisorType);
if (template == null) {
- throw new InvalidParameterValueException(String.format("Default VM import template with unique name: %s for hypervisor: %s cannot be created. Please use templateid parameter for import", VM_IMPORT_DEFAULT_TEMPLATE_NAME, hypervisorType.toString()));
+ throw new InvalidParameterValueException(String.format("Default VM import template with unique name: %s for hypervisor: %s cannot be created. Please use templateid parameter for import", templateName, hypervisorType.toString()));
}
}
} else {
diff --git a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-misc-context.xml b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-misc-context.xml
index c633a3b..f4fd57d 100644
--- a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-misc-context.xml
+++ b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-misc-context.xml
@@ -81,4 +81,6 @@
<bean id="DPDKHelper" class="com.cloud.hypervisor.kvm.dpdk.DpdkHelperImpl" />
+ <bean id="domainHelper" class="com.cloud.utils.DomainHelper" />
+
</beans>
diff --git a/server/src/test/java/com/cloud/acl/DomainCheckerTest.java b/server/src/test/java/com/cloud/acl/DomainCheckerTest.java
index a5ec413..8c7817c 100644
--- a/server/src/test/java/com/cloud/acl/DomainCheckerTest.java
+++ b/server/src/test/java/com/cloud/acl/DomainCheckerTest.java
@@ -18,6 +18,9 @@
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.backup.BackupOfferingVO;
+import org.apache.cloudstack.backup.dao.BackupOfferingDetailsDao;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -35,6 +38,8 @@
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.Ternary;
+import java.util.Collections;
+
@RunWith(MockitoJUnitRunner.class)
public class DomainCheckerTest {
@@ -46,6 +51,8 @@
DomainDao _domainDao;
@Mock
ProjectManager _projectMgr;
+ @Mock
+ BackupOfferingDetailsDao backupOfferingDetailsDao;
@Spy
@InjectMocks
@@ -163,4 +170,42 @@
domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ListEntry);
}
+ @Test
+ public void testBackupOfferingAccessRootAdmin() {
+ Account rootAdmin = Mockito.mock(Account.class);
+ Mockito.when(rootAdmin.getId()).thenReturn(1L);
+ BackupOfferingVO backupOfferingVO = Mockito.mock(BackupOfferingVO.class);
+ Mockito.when(_accountService.isRootAdmin(rootAdmin.getId())).thenReturn(true);
+
+ boolean hasAccess = domainChecker.checkAccess(rootAdmin, backupOfferingVO);
+ Assert.assertTrue(hasAccess);
+ }
+
+ @Test
+ public void testBackupOfferingAccessDomainAdmin() {
+ Account domainAdmin = Mockito.mock(Account.class);
+ Mockito.when(domainAdmin.getId()).thenReturn(2L);
+ BackupOfferingVO backupOfferingVO = Mockito.mock(BackupOfferingVO.class);
+ AccountVO owner = Mockito.mock(AccountVO.class);
+ Mockito.when(_accountService.isDomainAdmin(domainAdmin.getId())).thenReturn(true);
+ Mockito.when(domainAdmin.getDomainId()).thenReturn(10L);
+ Mockito.when(_domainDao.isChildDomain(100L, 10L)).thenReturn(true);
+ Mockito.when(backupOfferingDetailsDao.findDomainIds(backupOfferingVO.getId())).thenReturn(Collections.singletonList(100L));
+
+ boolean hasAccess = domainChecker.checkAccess(domainAdmin, backupOfferingVO);
+ Assert.assertTrue(hasAccess);
+ }
+
+ @Test
+ public void testBackupOfferingAccessNoAccess() {
+ Account normalUser = Mockito.mock(Account.class);
+ Mockito.when(normalUser.getId()).thenReturn(3L);
+ BackupOfferingVO backupOfferingVO = Mockito.mock(BackupOfferingVO.class);
+ Mockito.when(_accountService.isRootAdmin(normalUser.getId())).thenReturn(false);
+ Mockito.when(_accountService.isDomainAdmin(normalUser.getId())).thenReturn(false);
+
+ boolean hasAccess = domainChecker.checkAccess(normalUser, backupOfferingVO);
+ Assert.assertFalse(hasAccess);
+ }
+
}
diff --git a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java
index 170fcea..b5932e8 100644
--- a/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java
+++ b/server/src/test/java/com/cloud/alert/AlertManagerImplTest.java
@@ -16,6 +16,12 @@
// under the License.
package com.cloud.alert;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
@@ -25,7 +31,10 @@
import javax.naming.ConfigurationException;
import org.apache.cloudstack.backup.BackupManager;
+import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.messagebus.MessageBus;
+import org.apache.cloudstack.framework.messagebus.MessageSubscriber;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
@@ -40,6 +49,7 @@
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
import com.cloud.alert.dao.AlertDao;
import com.cloud.capacity.Capacity;
@@ -52,16 +62,12 @@
import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.HostPodDao;
+import com.cloud.event.EventTypes;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.storage.StorageManager;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.verify;
+import com.cloud.utils.Ternary;
@RunWith(MockitoJUnitRunner.class)
public class AlertManagerImplTest {
@@ -112,6 +118,9 @@
@Mock
ConfigurationDao configDao;
+ @Mock
+ MessageBus messageBus;
+
private final String[] recipients = new String[]{"test@test.com"};
private final String senderAddress = "sender@test.com";
@@ -268,4 +277,81 @@
assertEquals("Available backup storage space is low, total: 200.0 MB, used: 180.0 MB (90%)", capturedAlert.getContent());
assertEquals(AlertManager.AlertType.ALERT_TYPE_BACKUP_STORAGE.getType(), capturedAlert.getType());
}
+
+ @Test
+ public void initMessageBusListenerSubscribesToConfigurationEditEvent() {
+ MessageBus messageBusMock = Mockito.mock(MessageBus.class);
+ alertManagerImplMock.messageBus = messageBusMock;
+ alertManagerImplMock.initMessageBusListener();
+ Mockito.verify(messageBusMock).subscribe(Mockito.eq(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT), Mockito.any());
+ }
+
+ @Test
+ public void initMessageBusListenerTriggersSetupRepetitiveAlertTypesOnAllowedKeyEdit() {
+ MessageBus messageBusMock = Mockito.mock(MessageBus.class);
+ alertManagerImplMock.messageBus = messageBusMock;
+ alertManagerImplMock.initMessageBusListener();
+ ArgumentCaptor<MessageSubscriber> captor = ArgumentCaptor.forClass(MessageSubscriber.class);
+ Mockito.verify(messageBusMock).subscribe(Mockito.eq(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT), captor.capture());
+ Ternary<String, ConfigKey.Scope, Long> args = new Ternary<>(AlertManager.AllowedRepetitiveAlertTypes.key(), ConfigKey.Scope.Global, 1L);
+ captor.getValue().onPublishMessage(null, null, args);
+ Mockito.verify(alertManagerImplMock).setupRepetitiveAlertTypes();
+ }
+
+ @Test
+ public void initMessageBusListenerDoesNotTriggerSetupRepetitiveAlertTypesOnOtherKeyEdit() {
+ MessageBus messageBusMock = Mockito.mock(MessageBus.class);
+ alertManagerImplMock.messageBus = messageBusMock;
+ alertManagerImplMock.initMessageBusListener();
+ ArgumentCaptor<MessageSubscriber> captor = ArgumentCaptor.forClass(MessageSubscriber.class);
+ Mockito.verify(messageBusMock).subscribe(Mockito.eq(EventTypes.EVENT_CONFIGURATION_VALUE_EDIT), captor.capture());
+ Ternary<String, ConfigKey.Scope, Long> args = new Ternary<>("some.other.key", ConfigKey.Scope.Global, 1L);
+ captor.getValue().onPublishMessage(null, null, args);
+ Mockito.verify(alertManagerImplMock, Mockito.never()).setupRepetitiveAlertTypes();
+ }
+
+ private void mockAllowedRepetitiveAlertTypesConfigKey(String value) {
+ ReflectionTestUtils.setField(AlertManager.AllowedRepetitiveAlertTypes, "_defaultValue", value);
+ }
+
+ @Test
+ public void setupRepetitiveAlertTypesParsesValidAlertTypesCorrectly() {
+ mockAllowedRepetitiveAlertTypesConfigKey(AlertManager.AlertType.ALERT_TYPE_CPU.getName() + "," + AlertManager.AlertType.ALERT_TYPE_MEMORY.getName());
+ alertManagerImplMock.setupRepetitiveAlertTypes();
+ List<String> expectedTypes = (List<String>)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypeNames");
+ Assert.assertNotNull(expectedTypes);
+ Assert.assertEquals(2, expectedTypes.size());
+ Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_CPU.getName().toLowerCase()));
+ Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_MEMORY.getName().toLowerCase()));
+ }
+
+ @Test
+ public void setupRepetitiveAlertTypesHandlesEmptyConfigValue() {
+ mockAllowedRepetitiveAlertTypesConfigKey("");
+ alertManagerImplMock.setupRepetitiveAlertTypes();
+ List<String> expectedTypes = (List<String>)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypeNames");
+ Assert.assertNotNull(expectedTypes);
+ Assert.assertTrue(expectedTypes.isEmpty());
+ }
+
+ @Test
+ public void setupRepetitiveAlertTypesIgnoresCustomAlertTypes() {
+ String customAlertTypeName = "CUSTOM_ALERT_TYPE";
+ mockAllowedRepetitiveAlertTypesConfigKey(AlertManager.AlertType.ALERT_TYPE_CPU.getName() + "," + customAlertTypeName);
+ alertManagerImplMock.setupRepetitiveAlertTypes();
+ List<String> expectedTypes = (List<String>)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypeNames");
+ Assert.assertNotNull(expectedTypes);
+ Assert.assertEquals(2, expectedTypes.size());
+ Assert.assertTrue(expectedTypes.contains(AlertManager.AlertType.ALERT_TYPE_CPU.getName().toLowerCase()));
+ Assert.assertTrue(expectedTypes.contains(customAlertTypeName.toLowerCase()));
+ }
+
+ @Test
+ public void setupRepetitiveAlertTypesHandlesNullConfigValue() {
+ mockAllowedRepetitiveAlertTypesConfigKey(null);
+ alertManagerImplMock.setupRepetitiveAlertTypes();
+ List<String> expectedTypes = (List<String>)ReflectionTestUtils.getField(alertManagerImplMock, "allowedRepetitiveAlertTypeNames");
+ Assert.assertNotNull(expectedTypes);
+ Assert.assertTrue(expectedTypes.isEmpty());
+ }
}
diff --git a/server/src/test/java/com/cloud/api/APITest.java b/server/src/test/java/com/cloud/api/APITest.java
index e76b7a7..dbe9120 100644
--- a/server/src/test/java/com/cloud/api/APITest.java
+++ b/server/src/test/java/com/cloud/api/APITest.java
@@ -187,7 +187,6 @@
* @return login response string
*/
protected void login(String username, String password) {
- //String md5Psw = createMD5String(password);
// send login request
HashMap<String, String> params = new HashMap<String, String>();
params.put("response", "json");
diff --git a/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java b/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java
index 223b074..c0c019f 100644
--- a/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java
+++ b/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java
@@ -16,14 +16,6 @@
// under the License.
package com.cloud.api;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -37,20 +29,6 @@
import java.util.TimeZone;
import java.util.UUID;
-import org.apache.cloudstack.annotation.dao.AnnotationDao;
-import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
-import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
-import org.apache.cloudstack.api.response.DirectDownloadCertificateResponse;
-import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
-import org.apache.cloudstack.api.response.IpQuarantineResponse;
-import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
-import org.apache.cloudstack.api.response.ResourceIconResponse;
-import org.apache.cloudstack.api.response.TemplateResponse;
-import org.apache.cloudstack.api.response.UnmanagedInstanceResponse;
-import org.apache.cloudstack.api.response.UsageRecordResponse;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.usage.UsageService;
-import org.apache.cloudstack.vm.UnmanagedInstanceTO;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -64,10 +42,30 @@
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
+import org.apache.cloudstack.annotation.dao.AnnotationDao;
+import org.apache.cloudstack.api.ResponseObject;
+import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
+import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
+import org.apache.cloudstack.api.response.ConsoleSessionResponse;
+import org.apache.cloudstack.api.response.DirectDownloadCertificateResponse;
+import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
+import org.apache.cloudstack.api.response.IpQuarantineResponse;
+import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
+import org.apache.cloudstack.api.response.ResourceIconResponse;
+import org.apache.cloudstack.api.response.TemplateResponse;
+import org.apache.cloudstack.api.response.UnmanagedInstanceResponse;
+import org.apache.cloudstack.api.response.UsageRecordResponse;
+import org.apache.cloudstack.api.response.TrafficTypeResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.usage.UsageService;
+import org.apache.cloudstack.vm.UnmanagedInstanceTO;
+
import com.cloud.capacity.Capacity;
import com.cloud.configuration.Resource;
import com.cloud.domain.DomainVO;
import com.cloud.host.HostVO;
+import com.cloud.network.Networks;
+import com.cloud.network.PhysicalNetworkTrafficType;
import com.cloud.network.PublicIpQuarantine;
import com.cloud.network.as.AutoScaleVmGroup;
import com.cloud.network.as.AutoScaleVmGroupVO;
@@ -78,6 +76,8 @@
import com.cloud.network.dao.LoadBalancerVO;
import com.cloud.network.dao.NetworkServiceMapDao;
import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.PhysicalNetworkVO;
+import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO;
import com.cloud.resource.icon.ResourceIconVO;
import com.cloud.server.ResourceIcon;
import com.cloud.server.ResourceIconManager;
@@ -97,8 +97,16 @@
import com.cloud.vm.ConsoleSessionVO;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.VMInstanceVO;
-import org.apache.cloudstack.api.ResponseObject;
-import org.apache.cloudstack.api.response.ConsoleSessionResponse;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
@RunWith(MockitoJUnitRunner.class)
public class ApiResponseHelperTest {
@@ -417,7 +425,40 @@
}
}
- private UnmanagedInstanceTO getUnmanagedInstaceForTests() {
+ @Test
+ public void testCreateTrafficTypeResponse() {
+ PhysicalNetworkVO pnet = new PhysicalNetworkVO();
+ pnet.addIsolationMethod("VXLAN");
+ pnet.addIsolationMethod("STT");
+
+ try (MockedStatic<ApiDBUtils> ignored = Mockito.mockStatic(ApiDBUtils.class)) {
+ when(ApiDBUtils.findPhysicalNetworkById(anyLong())).thenReturn(pnet);
+ String xenLabel = "xen";
+ String kvmLabel = "kvm";
+ String vmwareLabel = "vmware";
+ String simulatorLabel = "simulator";
+ String hypervLabel = "hyperv";
+ String ovmLabel = "ovm";
+ String vlan = "vlan";
+ String trafficType = "Public";
+ PhysicalNetworkTrafficType pnetTrafficType = new PhysicalNetworkTrafficTypeVO(pnet.getId(), Networks.TrafficType.getTrafficType(trafficType), xenLabel, kvmLabel, vmwareLabel, simulatorLabel, vlan, hypervLabel, ovmLabel);
+
+ TrafficTypeResponse response = apiResponseHelper.createTrafficTypeResponse(pnetTrafficType);
+ assertFalse(UUID.fromString(response.getId()).toString().isEmpty());
+ assertEquals(response.getphysicalNetworkId(), pnet.getUuid());
+ assertEquals(response.getTrafficType(), trafficType);
+ assertEquals(response.getXenLabel(), xenLabel);
+ assertEquals(response.getKvmLabel(), kvmLabel);
+ assertEquals(response.getVmwareLabel(), vmwareLabel);
+ assertEquals(response.getHypervLabel(), hypervLabel);
+ assertEquals(response.getOvm3Label(), ovmLabel);
+ assertEquals(response.getVlan(), vlan);
+ assertEquals(response.getIsolationMethods(), "VXLAN,STT");
+
+ }
+ }
+
+ private UnmanagedInstanceTO getUnmanagedInstanceForTests() {
UnmanagedInstanceTO instance = Mockito.mock(UnmanagedInstanceTO.class);
Mockito.when(instance.getPowerState()).thenReturn(UnmanagedInstanceTO.PowerState.PowerOff);
Mockito.when(instance.getClusterName()).thenReturn("CL1");
@@ -436,7 +477,7 @@
@Test
public void testCreateUnmanagedInstanceResponseVmwareDcVms() {
- UnmanagedInstanceTO instance = getUnmanagedInstaceForTests();
+ UnmanagedInstanceTO instance = getUnmanagedInstanceForTests();
UnmanagedInstanceResponse response = apiResponseHelper.createUnmanagedInstanceResponse(instance, null, null);
Assert.assertEquals(1, response.getDisks().size());
Assert.assertEquals(1, response.getNics().size());
diff --git a/server/src/test/java/com/cloud/api/ApiServletTest.java b/server/src/test/java/com/cloud/api/ApiServletTest.java
index 79fe4b8..c5ee9f5 100644
--- a/server/src/test/java/com/cloud/api/ApiServletTest.java
+++ b/server/src/test/java/com/cloud/api/ApiServletTest.java
@@ -16,36 +16,8 @@
// under the License.
package com.cloud.api;
-import com.cloud.api.auth.ListUserTwoFactorAuthenticatorProvidersCmd;
-import com.cloud.api.auth.SetupUserTwoFactorAuthenticationCmd;
-import com.cloud.api.auth.ValidateUserTwoFactorAuthenticationCodeCmd;
-import com.cloud.server.ManagementServer;
-import com.cloud.user.Account;
-import com.cloud.user.AccountManagerImpl;
-import com.cloud.user.AccountService;
-import com.cloud.user.User;
-import com.cloud.user.UserAccount;
-import com.cloud.utils.HttpUtils;
-import com.cloud.vm.UserVmManager;
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.auth.APIAuthenticationManager;
-import org.apache.cloudstack.api.auth.APIAuthenticationType;
-import org.apache.cloudstack.api.auth.APIAuthenticator;
-import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
-import org.apache.cloudstack.framework.config.ConfigKey;
-import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.junit.MockitoJUnitRunner;
+import static org.mockito.ArgumentMatchers.nullable;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -57,11 +29,46 @@
import java.util.HashMap;
import java.util.Map;
-import static org.mockito.ArgumentMatchers.nullable;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.auth.APIAuthenticationManager;
+import org.apache.cloudstack.api.auth.APIAuthenticationType;
+import org.apache.cloudstack.api.auth.APIAuthenticator;
+import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
+import org.apache.cloudstack.api.command.admin.offering.IsAccountAllowedToCreateOfferingsWithTagsCmd;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.api.auth.ListUserTwoFactorAuthenticatorProvidersCmd;
+import com.cloud.api.auth.SetupUserTwoFactorAuthenticationCmd;
+import com.cloud.api.auth.ValidateUserTwoFactorAuthenticationCodeCmd;
+import com.cloud.server.ManagementServer;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManagerImpl;
+import com.cloud.user.AccountService;
+import com.cloud.user.User;
+import com.cloud.user.UserAccount;
+import com.cloud.utils.HttpUtils;
+import com.cloud.vm.UserVmManager;
@RunWith(MockitoJUnitRunner.class)
public class ApiServletTest {
+ private static final String[] STATE_CHANGING_COMMAND_CHECK_NAME_PARAM =
+ {ApiServer.EnforcePostRequestsAndTimestamps.key()};
+
@Mock
ApiServer apiServer;
@@ -461,4 +468,88 @@
Assert.assertEquals(false, result);
}
+
+ @Test
+ public void isStateChangingCommandNotUsingPOSTReturnsFalseForPostMethod() {
+ String command = "updateConfiguration";
+ String method = "POST";
+ Map<String, Object[]> params = new HashMap<>();
+
+ boolean result = servlet.isStateChangingCommandNotUsingPOST(command, method, params);
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isStateChangingCommandNotUsingPOSTReturnsTrueForNullCommandAndMethod() {
+ String command = null;
+ String method = null;
+ Map<String, Object[]> params = new HashMap<>();
+
+ boolean result = servlet.isStateChangingCommandNotUsingPOST(command, method, params);
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isStateChangingCommandNotUsingPOSTReturnsFalseForGetHttpMethodAnnotation() {
+ String command = "isAccountAllowedToCreateOfferingsWithTags";
+ String method = "GET";
+ Map<String, Object[]> params = new HashMap<>();
+ Class<?> cmdClass = IsAccountAllowedToCreateOfferingsWithTagsCmd.class;
+ APICommand apiCommand = cmdClass.getAnnotation(APICommand.class);
+ Mockito.doReturn(cmdClass).when(apiServer).getCmdClass(command);
+ Assert.assertNotNull(apiCommand);
+ Assert.assertEquals("GET", apiCommand.httpMethod());
+ boolean result = servlet.isStateChangingCommandNotUsingPOST(command, method, params);
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isStateChangingCommandNotUsingPOSTReturnsFalseForMatchingGetRequestPattern() {
+ String command = "listZones";
+ String method = "GET";
+ Map<String, Object[]> params = new HashMap<>();
+ boolean result = servlet.isStateChangingCommandNotUsingPOST(command, method, params);
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isStateChangingCommandNotUsingPOSTReturnsTrueForMissingNameParameter() {
+ String command = "updateConfiguration";
+ String method = "GET";
+ Map<String, Object[]> params = new HashMap<>();
+ boolean result = servlet.isStateChangingCommandNotUsingPOST(command, method, params);
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isStateChangingCommandNotUsingPOSTReturnsFalseForUpdateConfigurationEnforcePostRequestsKey() {
+ String command = "updateConfiguration";
+ String method = "GET";
+ Map<String, Object[]> params = new HashMap<>();
+ params.put("name", STATE_CHANGING_COMMAND_CHECK_NAME_PARAM);
+ boolean result = servlet.isStateChangingCommandNotUsingPOST(command, method, params);
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void isStateChangingCommandNotUsingPOSTReturnsFalseForWrongApiEnforcePostRequestsKey() {
+ String command = "updateSomeApi";
+ String method = "GET";
+ Map<String, Object[]> params = new HashMap<>();
+ params.put("name", STATE_CHANGING_COMMAND_CHECK_NAME_PARAM);
+ boolean result = servlet.isStateChangingCommandNotUsingPOST(command, method, params);
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void isStateChangingCommandNotUsingPOSTReturnsFalseForUpdateConfigurationNonEnforcePostRequestsKey() {
+ String command = "updateConfiguration";
+ String method = "GET";
+ Map<String, Object[]> params = new HashMap<>();
+ params.put("name", new String[] { "key" });
+ boolean result = servlet.isStateChangingCommandNotUsingPOST(command, method, params);
+ Assert.assertTrue(result);
+ }
}
diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java
index a62f4d1..8295202 100644
--- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java
+++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java
@@ -49,6 +49,7 @@
import com.cloud.user.Account;
import com.cloud.user.AccountManagerImpl;
import com.cloud.user.User;
+import com.cloud.utils.DomainHelper;
import com.cloud.utils.Pair;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.SearchCriteria;
@@ -178,6 +179,8 @@
PrimaryDataStoreDao storagePoolDao;
@Mock
StoragePoolDetailsDao storagePoolDetailsDao;
+ @Mock
+ DomainHelper domainHelper;
DeleteZoneCmd deleteZoneCmd;
CreateNetworkOfferingCmd createNetworkOfferingCmd;
@@ -1102,4 +1105,42 @@
Assert.assertFalse(result);
}
+
+ @Test
+ public void normalizedEmptyValueForConfigReturnsTrimmedValueWhenInputIsValid() {
+ String result = configurationManagerImplSpy.getNormalizedEmptyValueForConfig("someConfig", " validValue ", null);
+ Assert.assertEquals("validValue", result);
+ }
+
+ @Test
+ public void normalizedEmptyValueForConfigReturnsNullWhenInputIsNullAndNoConfigStorageId() {
+ String result = configurationManagerImplSpy.getNormalizedEmptyValueForConfig("someConfig", "null", null);
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void normalizedEmptyValueForConfigReturnsEmptyStringWhenInputIsNullAndConfigStorageIdProvided() {
+ String result = configurationManagerImplSpy.getNormalizedEmptyValueForConfig("someConfig", "null", 123L);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void normalizedEmptyValueForConfigReturnsEmptyStringWhenKeyTypeIsStringAndInputIsEmpty() {
+ ConfigKey<String> mockKey = Mockito.mock(ConfigKey.class);
+ Mockito.when(mockKey.type()).thenReturn(String.class);
+ Mockito.doReturn(mockKey).when(configDepot).get("someConfig");
+
+ String result = configurationManagerImplSpy.getNormalizedEmptyValueForConfig("someConfig", "", null);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void normalizedEmptyValueForConfigReturnsNullWhenKeyTypeIsNotStringAndInputIsEmpty() {
+ ConfigKey<Integer> mockKey = Mockito.mock(ConfigKey.class);
+ Mockito.when(mockKey.type()).thenReturn(Integer.class);
+ Mockito.doReturn(mockKey).when(configDepot).get("someConfig");
+
+ String result = configurationManagerImplSpy.getNormalizedEmptyValueForConfig("someConfig", "", null);
+ Assert.assertNull(result);
+ }
}
diff --git a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
index 7ddd0d6..c186083 100644
--- a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
@@ -135,8 +135,10 @@
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
+import com.cloud.storage.GuestOSVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.dao.DiskOfferingDao;
+import com.cloud.storage.dao.GuestOSDao;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
@@ -259,9 +261,10 @@
LoadBalancingRulesService loadBalancingRulesService;
@Mock
VMInstanceDao vmInstanceDao;
-
@Mock
VirtualMachineManager virtualMachineManager;
+ @Mock
+ GuestOSDao guestOSDao;
AccountVO account;
UserVO user;
@@ -420,6 +423,11 @@
userDataDetails.put("0", new HashMap<>() {{ put("key1", "value1"); put("key2", "value2"); }});
Mockito.doReturn(userDataFinal).when(userVmMgr).finalizeUserData(any(), any(), any());
Mockito.doReturn(userDataFinal).when(userDataMgr).validateUserData(eq(userDataFinal), nullable(BaseCmd.HTTPMethod.class));
+
+ when(templateMock.getGuestOSId()).thenReturn(100L);
+ GuestOSVO guestOSMock = Mockito.mock(GuestOSVO.class);
+ when(guestOSDao.findById(anyLong())).thenReturn(guestOSMock);
+ when(guestOSMock.getName()).thenReturn("linux");
}
@After
@@ -2495,4 +2503,68 @@
Mockito.verify(userVmMgr).expunge(eq(userVmMock));
}
+
+ @Test
+ public void getNextVmHostAndDisplayNameGeneratesCorrectHostAndDisplayNameForLinuxTemplate() {
+ when(asVmGroupMock.getName()).thenReturn(vmGroupName);
+ when(asVmGroupMock.getNextVmSeq()).thenReturn(1L);
+ Pair<String, String> result = autoScaleManagerImplSpy.getNextVmHostAndDisplayName(asVmGroupMock, templateMock);
+ String vmHostNamePattern = AutoScaleManagerImpl.VM_HOSTNAME_PREFIX + vmGroupName +
+ "-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}";
+ Assert.assertTrue(result.first().matches(vmHostNamePattern));
+ Assert.assertEquals(result.first(), result.second());
+ }
+
+ private void runGetNextVmHostAndDisplayNameGeneratesCorrectHostAndDisplayNameForWindowsTemplate() {
+ when(asVmGroupMock.getName()).thenReturn(vmGroupName);
+ when(asVmGroupMock.getNextVmSeq()).thenReturn(1L);
+ when(templateMock.getGuestOSId()).thenReturn(1L);
+ Pair<String, String> result = autoScaleManagerImplSpy.getNextVmHostAndDisplayName(asVmGroupMock, templateMock);
+ String vmHostNamePattern = AutoScaleManagerImpl.WINDOWS_VM_HOSTNAME_PREFIX + "[a-z]{6}";
+ Assert.assertTrue(result.first().matches(vmHostNamePattern));
+ Assert.assertEquals(15, result.first().length());
+ String vmDisplayHostNamePattern = AutoScaleManagerImpl.VM_HOSTNAME_PREFIX + vmGroupName +
+ "-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}";
+ Assert.assertTrue(result.second().matches(vmDisplayHostNamePattern));
+ Assert.assertTrue(result.second().length() <= 63);
+ Assert.assertTrue(result.second().endsWith(result.first().split("-")[2]));
+ }
+
+ @Test
+ public void getNextVmHostAndDisplayNameGeneratesCorrectHostAndDisplayNameForWindowsTemplateUsingGuestOsName() {
+ GuestOSVO guestOS = Mockito.mock(GuestOSVO.class);
+ when(guestOS.getName()).thenReturn("Windows Server");
+ when(guestOSDao.findById(1L)).thenReturn(guestOS);
+ runGetNextVmHostAndDisplayNameGeneratesCorrectHostAndDisplayNameForWindowsTemplate();
+ }
+
+ @Test
+ public void getNextVmHostAndDisplayNameGeneratesCorrectHostAndDisplayNameForWindowsTemplateUsingGuestOsDisplayName() {
+ GuestOSVO guestOS = Mockito.mock(GuestOSVO.class);
+ when(guestOS.getDisplayName()).thenReturn("Windows Server");
+ when(guestOSDao.findById(1L)).thenReturn(guestOS);
+ runGetNextVmHostAndDisplayNameGeneratesCorrectHostAndDisplayNameForWindowsTemplate();
+ }
+
+ @Test
+ public void getNextVmHostAndDisplayNameTruncatesGroupNameWhenExceedingMaxLength() {
+ when(asVmGroupMock.getName()).thenReturn(vmGroupNameWithMaxLength);
+ when(asVmGroupMock.getNextVmSeq()).thenReturn(1L);
+ Pair<String, String> result = autoScaleManagerImplSpy.getNextVmHostAndDisplayName(asVmGroupMock, templateMock);
+ Assert.assertTrue(result.first().length() <= 63);
+ Assert.assertTrue(result.second().length() <= 63);
+ }
+
+ @Test
+ public void getNextVmHostAndDisplayNameHandlesNullGuestOS() {
+ when(asVmGroupMock.getName()).thenReturn(vmGroupName);
+ when(asVmGroupMock.getNextVmSeq()).thenReturn(1L);
+ when(templateMock.getGuestOSId()).thenReturn(1L);
+ when(guestOSDao.findById(1L)).thenReturn(null);
+ Pair<String, String> result = autoScaleManagerImplSpy.getNextVmHostAndDisplayName(asVmGroupMock, templateMock);
+ String vmHostNamePattern = AutoScaleManagerImpl.VM_HOSTNAME_PREFIX + vmGroupName +
+ "-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}";
+ Assert.assertTrue(result.first().matches(vmHostNamePattern));
+ Assert.assertEquals(result.first(), result.second());
+ }
}
diff --git a/server/src/test/java/com/cloud/network/vpn/Site2SiteVpnManagerImplTest.java b/server/src/test/java/com/cloud/network/vpn/Site2SiteVpnManagerImplTest.java
new file mode 100644
index 0000000..291d3a4
--- /dev/null
+++ b/server/src/test/java/com/cloud/network/vpn/Site2SiteVpnManagerImplTest.java
@@ -0,0 +1,944 @@
+/*
+ * 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.vpn;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Site2SiteVpnConnection;
+import com.cloud.network.Site2SiteVpnConnection.State;
+import com.cloud.network.Site2SiteVpnGateway;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.network.dao.Site2SiteCustomerGatewayDao;
+import com.cloud.network.dao.Site2SiteCustomerGatewayVO;
+import com.cloud.network.dao.Site2SiteVpnConnectionDao;
+import com.cloud.network.dao.Site2SiteVpnConnectionVO;
+import com.cloud.network.dao.Site2SiteVpnGatewayDao;
+import com.cloud.network.dao.Site2SiteVpnGatewayVO;
+import com.cloud.network.element.Site2SiteVpnServiceProvider;
+import com.cloud.network.vpc.VpcManager;
+import com.cloud.network.vpc.VpcVO;
+import com.cloud.network.vpc.dao.VpcDao;
+import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.User;
+import com.cloud.user.UserVO;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.DomainRouterVO;
+import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.annotation.dao.AnnotationDao;
+import org.apache.cloudstack.api.command.user.vpn.CreateVpnConnectionCmd;
+import org.apache.cloudstack.api.command.user.vpn.CreateVpnCustomerGatewayCmd;
+import org.apache.cloudstack.api.command.user.vpn.CreateVpnGatewayCmd;
+import org.apache.cloudstack.api.command.user.vpn.DeleteVpnConnectionCmd;
+import org.apache.cloudstack.api.command.user.vpn.DeleteVpnCustomerGatewayCmd;
+import org.apache.cloudstack.api.command.user.vpn.DeleteVpnGatewayCmd;
+import org.apache.cloudstack.api.command.user.vpn.ResetVpnConnectionCmd;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.Silent.class)
+public class Site2SiteVpnManagerImplTest {
+
+ @Mock
+ private Site2SiteCustomerGatewayDao _customerGatewayDao;
+ @Mock
+ private Site2SiteVpnGatewayDao _vpnGatewayDao;
+ @Mock
+ private Site2SiteVpnConnectionDao _vpnConnectionDao;
+ @Mock
+ private VpcDao _vpcDao;
+ @Mock
+ private IPAddressDao _ipAddressDao;
+ @Mock
+ private VpcManager _vpcMgr;
+ @Mock
+ private AccountManager _accountMgr;
+ @Mock
+ private AnnotationDao annotationDao;
+ @Mock
+ private List<Site2SiteVpnServiceProvider> _s2sProviders;
+ @Mock
+ VpcOfferingServiceMapDao vpcOfferingServiceMapDao;
+
+ @InjectMocks
+ private Site2SiteVpnManagerImpl site2SiteVpnManager;
+
+ private AccountVO account;
+ private UserVO user;
+ private VpcVO vpc;
+ private IPAddressVO ipAddress;
+ private Site2SiteVpnGatewayVO vpnGateway;
+ private Site2SiteCustomerGatewayVO customerGateway;
+ private Site2SiteVpnConnectionVO vpnConnection;
+
+ private static final Long ACCOUNT_ID = 1L;
+ private static final Long DOMAIN_ID = 2L;
+ private static final Long VPC_ID = 3L;
+ private static final Long VPN_GATEWAY_ID = 4L;
+ private static final Long CUSTOMER_GATEWAY_ID = 5L;
+ private static final Long VPN_CONNECTION_ID = 6L;
+ private static final Long IP_ADDRESS_ID = 7L;
+
+ @Before
+ public void setUp() throws Exception {
+ account = new AccountVO("testaccount", DOMAIN_ID, "networkdomain", Account.Type.NORMAL, UUID.randomUUID().toString());
+ account.setId(ACCOUNT_ID);
+ user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone",
+ UUID.randomUUID().toString(), User.Source.UNKNOWN);
+ CallContext.register(user, account);
+
+ vpc = mock(VpcVO.class);
+ when(vpc.getId()).thenReturn(VPC_ID);
+ when(vpc.getAccountId()).thenReturn(ACCOUNT_ID);
+ when(vpc.getDomainId()).thenReturn(DOMAIN_ID);
+ when(vpc.getCidr()).thenReturn("10.0.0.0/16");
+
+ ipAddress = mock(IPAddressVO.class);
+ when(ipAddress.getId()).thenReturn(IP_ADDRESS_ID);
+ when(ipAddress.getVpcId()).thenReturn(VPC_ID);
+
+ vpnGateway = mock(Site2SiteVpnGatewayVO.class);
+ when(vpnGateway.getId()).thenReturn(VPN_GATEWAY_ID);
+ when(vpnGateway.getVpcId()).thenReturn(VPC_ID);
+ when(vpnGateway.getAccountId()).thenReturn(ACCOUNT_ID);
+ when(vpnGateway.getDomainId()).thenReturn(DOMAIN_ID);
+
+ customerGateway = mock(Site2SiteCustomerGatewayVO.class);
+ when(customerGateway.getId()).thenReturn(CUSTOMER_GATEWAY_ID);
+ when(customerGateway.getAccountId()).thenReturn(ACCOUNT_ID);
+ when(customerGateway.getDomainId()).thenReturn(DOMAIN_ID);
+ when(customerGateway.getGuestCidrList()).thenReturn("192.168.1.0/24");
+ when(customerGateway.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(customerGateway.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(customerGateway.getIkeVersion()).thenReturn("ike");
+
+ vpnConnection = new Site2SiteVpnConnectionVO(ACCOUNT_ID, DOMAIN_ID, VPN_GATEWAY_ID, CUSTOMER_GATEWAY_ID, false);
+ vpnConnection.setState(State.Pending);
+
+ when(_accountMgr.getAccount(ACCOUNT_ID)).thenReturn(account);
+ doNothing().when(_accountMgr).checkAccess(any(Account.class), nullable(SecurityChecker.AccessType.class), anyBoolean(), any());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions);
+ resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms);
+ resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms);
+ resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup);
+ resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions);
+ resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms);
+ resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms);
+ resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup);
+ CallContext.unregister();
+ }
+
+ private void setConfigKeyValue(ConfigKey<String> configKey, String value) {
+ try {
+ Field valueField = ConfigKey.class.getDeclaredField("_value");
+ valueField.setAccessible(true);
+ valueField.set(configKey, value);
+
+ Field dynamicField = ConfigKey.class.getDeclaredField("_isDynamic");
+ dynamicField.setAccessible(true);
+ dynamicField.setBoolean(configKey, false);
+ } catch (IllegalAccessException | NoSuchFieldException e) {
+ throw new RuntimeException("Failed to set ConfigKey value", e);
+ }
+ }
+
+ private void resetConfigKeyValue(ConfigKey<String> configKey) {
+ try {
+ Field valueField = ConfigKey.class.getDeclaredField("_value");
+ valueField.setAccessible(true);
+ valueField.set(configKey, null);
+
+ Field dynamicField = ConfigKey.class.getDeclaredField("_isDynamic");
+ dynamicField.setAccessible(true);
+ dynamicField.setBoolean(configKey, true);
+ } catch (IllegalAccessException | NoSuchFieldException e) {
+ throw new RuntimeException("Failed to reset ConfigKey value", e);
+ }
+ }
+
+ @Test
+ public void testCreateVpnGatewaySuccess() {
+ CreateVpnGatewayCmd cmd = mock(CreateVpnGatewayCmd.class);
+ when(cmd.getVpcId()).thenReturn(VPC_ID);
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+ when(cmd.isDisplay()).thenReturn(true);
+
+ when(_vpcDao.findById(VPC_ID)).thenReturn(vpc);
+ when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(null);
+ when(_ipAddressDao.listByAssociatedVpc(VPC_ID, true)).thenReturn(List.of(ipAddress));
+ when(_vpnGatewayDao.persist(any(Site2SiteVpnGatewayVO.class))).thenReturn(vpnGateway);
+
+ Site2SiteVpnGateway result = site2SiteVpnManager.createVpnGateway(cmd);
+
+ assertNotNull(result);
+ verify(_vpnGatewayDao).persist(any(Site2SiteVpnGatewayVO.class));
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateVpnGatewayInvalidVpc() {
+ CreateVpnGatewayCmd cmd = mock(CreateVpnGatewayCmd.class);
+ when(cmd.getVpcId()).thenReturn(VPC_ID);
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ when(_vpcDao.findById(VPC_ID)).thenReturn(null);
+
+ site2SiteVpnManager.createVpnGateway(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateVpnGatewayAlreadyExists() {
+ CreateVpnGatewayCmd cmd = mock(CreateVpnGatewayCmd.class);
+ when(cmd.getVpcId()).thenReturn(VPC_ID);
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ when(_vpcDao.findById(VPC_ID)).thenReturn(vpc);
+ when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(vpnGateway);
+
+ site2SiteVpnManager.createVpnGateway(cmd);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void testCreateVpnGatewayNoSourceNatIp() {
+ CreateVpnGatewayCmd cmd = mock(CreateVpnGatewayCmd.class);
+ when(cmd.getVpcId()).thenReturn(VPC_ID);
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ when(_vpcDao.findById(VPC_ID)).thenReturn(vpc);
+ when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(null);
+ when(_ipAddressDao.listByAssociatedVpc(VPC_ID, true)).thenReturn(new ArrayList<>());
+
+ site2SiteVpnManager.createVpnGateway(cmd);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayInvalidIp() {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getGatewayIp()).thenReturn("invalid-ip");
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isValidIp4("invalid-ip")).thenReturn(false);
+ netUtilsMock.when(() -> NetUtils.verifyDomainName("invalid-ip")).thenReturn(false);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayInvalidCidrList() {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getGatewayIp()).thenReturn("1.2.3.4");
+ when(cmd.getGuestCidrList()).thenReturn("invalid-cidr");
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidCidrList("invalid-cidr")).thenReturn(false);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayInvalidIkePolicy() {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getGatewayIp()).thenReturn("1.2.3.4");
+ when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24");
+ when(cmd.getIkePolicy()).thenReturn("invalid-policy");
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "invalid-policy")).thenReturn(false);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayInvalidEspPolicy() {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getGatewayIp()).thenReturn("1.2.3.4");
+ when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24");
+ when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEspPolicy()).thenReturn("invalid-policy");
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "invalid-policy")).thenReturn(false);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayWithExcludedParameters() throws Exception {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getName()).thenReturn("test-gateway");
+ when(cmd.getGatewayIp()).thenReturn("1.2.3.4");
+ when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24");
+ when(cmd.getIpsecPsk()).thenReturn("test-psk");
+ when(cmd.getIkePolicy()).thenReturn("3des-sha256;modp2048");
+ when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getIkeVersion()).thenReturn("ike");
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "3des");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, "");
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "3des-sha256;modp2048")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayDuplicateName() {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getName()).thenReturn("test-gateway");
+ when(cmd.getGatewayIp()).thenReturn("1.2.3.4");
+ when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24");
+ when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true);
+
+ when(_customerGatewayDao.findByNameAndAccountId("test-gateway", ACCOUNT_ID)).thenReturn(customerGateway);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayInvalidIkeLifetime() {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getGatewayIp()).thenReturn("1.2.3.4");
+ when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24");
+ when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getIkeLifetime()).thenReturn(86401L);
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayInvalidEspLifetime() {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getGatewayIp()).thenReturn("1.2.3.4");
+ when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24");
+ when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEspLifetime()).thenReturn(86401L);
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayTooManySubnets() {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getGatewayIp()).thenReturn("1.2.3.4");
+ String tooManyCidrs = "192.168.1.0/24,192.168.2.0/24,192.168.3.0/24,192.168.4.0/24,192.168.5.0/24," +
+ "192.168.6.0/24,192.168.7.0/24,192.168.8.0/24,192.168.9.0/24,192.168.10.0/24,192.168.11.0/24";
+ when(cmd.getGuestCidrList()).thenReturn(tooManyCidrs);
+ when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidCidrList(tooManyCidrs)).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.getCleanIp4CidrList(tooManyCidrs)).thenReturn(tooManyCidrs);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateCustomerGatewayOverlappingSubnets() {
+ CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class);
+ when(cmd.getGatewayIp()).thenReturn("1.2.3.4");
+ when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24,192.168.1.0/25");
+ when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ String cidrList = "192.168.1.0/24,192.168.1.0/25";
+ netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidCidrList(cidrList)).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.getCleanIp4CidrList(cidrList)).thenReturn(cidrList);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true);
+ netUtilsMock.when(() -> NetUtils.isNetworksOverlap("192.168.1.0/24", "192.168.1.0/25")).thenReturn(true);
+
+ site2SiteVpnManager.createCustomerGateway(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateVpnConnectionCidrOverlapWithVpc() {
+ CreateVpnConnectionCmd cmd = mock(CreateVpnConnectionCmd.class);
+ when(cmd.getVpnGatewayId()).thenReturn(VPN_GATEWAY_ID);
+ when(cmd.getCustomerGatewayId()).thenReturn(CUSTOMER_GATEWAY_ID);
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ Site2SiteCustomerGatewayVO customerGw = mock(Site2SiteCustomerGatewayVO.class);
+ when(customerGw.getGuestCidrList()).thenReturn("10.0.0.0/24");
+ when(customerGw.getAccountId()).thenReturn(ACCOUNT_ID);
+ when(customerGw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGw);
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+ when(_vpnConnectionDao.findByVpnGatewayIdAndCustomerGatewayId(VPN_GATEWAY_ID, CUSTOMER_GATEWAY_ID)).thenReturn(null);
+ when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(vpnGateway);
+ when(_vpcDao.findById(VPC_ID)).thenReturn(vpc);
+
+ try (MockedStatic<NetUtils> netUtilsMock = Mockito.mockStatic(NetUtils.class)) {
+ netUtilsMock.when(() -> NetUtils.isNetworksOverlap("10.0.0.0/16", "10.0.0.0/24")).thenReturn(true);
+
+ site2SiteVpnManager.createVpnConnection(cmd);
+ }
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testCreateVpnConnectionExceedsLimit() {
+ CreateVpnConnectionCmd cmd = mock(CreateVpnConnectionCmd.class);
+ when(cmd.getVpnGatewayId()).thenReturn(VPN_GATEWAY_ID);
+ when(cmd.getCustomerGatewayId()).thenReturn(CUSTOMER_GATEWAY_ID);
+ when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
+
+ when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGateway);
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+ when(_vpnConnectionDao.findByVpnGatewayIdAndCustomerGatewayId(VPN_GATEWAY_ID, CUSTOMER_GATEWAY_ID)).thenReturn(null);
+ when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(vpnGateway);
+ when(_vpcDao.findById(VPC_ID)).thenReturn(vpc);
+
+ List<Site2SiteVpnConnectionVO> existingConns = new ArrayList<>();
+ for (int i = 0; i < 4; i++) {
+ existingConns.add(mock(Site2SiteVpnConnectionVO.class));
+ }
+ when(_vpnConnectionDao.listByVpnGatewayId(VPN_GATEWAY_ID)).thenReturn(existingConns);
+
+ site2SiteVpnManager.createVpnConnection(cmd);
+ }
+
+ @Test
+ public void testDeleteCustomerGatewaySuccess() {
+ DeleteVpnCustomerGatewayCmd cmd = mock(DeleteVpnCustomerGatewayCmd.class);
+ when(cmd.getId()).thenReturn(CUSTOMER_GATEWAY_ID);
+
+ when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGateway);
+ when(_vpnConnectionDao.listByCustomerGatewayId(CUSTOMER_GATEWAY_ID)).thenReturn(new ArrayList<>());
+
+ boolean result = site2SiteVpnManager.deleteCustomerGateway(cmd);
+
+ assertTrue(result);
+ verify(_customerGatewayDao).remove(CUSTOMER_GATEWAY_ID);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testDeleteCustomerGatewayWithConnections() {
+ DeleteVpnCustomerGatewayCmd cmd = mock(DeleteVpnCustomerGatewayCmd.class);
+ when(cmd.getId()).thenReturn(CUSTOMER_GATEWAY_ID);
+
+ when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGateway);
+ when(_vpnConnectionDao.listByCustomerGatewayId(CUSTOMER_GATEWAY_ID)).thenReturn(List.of(vpnConnection));
+
+ site2SiteVpnManager.deleteCustomerGateway(cmd);
+ }
+
+ @Test
+ public void testDeleteVpnGatewaySuccess() {
+ DeleteVpnGatewayCmd cmd = mock(DeleteVpnGatewayCmd.class);
+ when(cmd.getId()).thenReturn(VPN_GATEWAY_ID);
+
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+ when(_vpnConnectionDao.listByVpnGatewayId(VPN_GATEWAY_ID)).thenReturn(new ArrayList<>());
+
+ boolean result = site2SiteVpnManager.deleteVpnGateway(cmd);
+
+ assertTrue(result);
+ verify(_vpnGatewayDao).remove(VPN_GATEWAY_ID);
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testDeleteVpnGatewayWithConnections() {
+ DeleteVpnGatewayCmd cmd = mock(DeleteVpnGatewayCmd.class);
+ when(cmd.getId()).thenReturn(VPN_GATEWAY_ID);
+
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+ when(_vpnConnectionDao.listByVpnGatewayId(VPN_GATEWAY_ID)).thenReturn(List.of(vpnConnection));
+
+ site2SiteVpnManager.deleteVpnGateway(cmd);
+ }
+
+ @Test
+ public void testDeleteVpnConnectionSuccess() throws ResourceUnavailableException {
+ DeleteVpnConnectionCmd cmd = mock(DeleteVpnConnectionCmd.class);
+ when(cmd.getId()).thenReturn(VPN_CONNECTION_ID);
+
+ when(_vpnConnectionDao.findById(VPN_CONNECTION_ID)).thenReturn(vpnConnection);
+ vpnConnection.setState(State.Pending);
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+ when(_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(anyLong(), anyBoolean())).thenReturn(true);
+
+ boolean result = site2SiteVpnManager.deleteVpnConnection(cmd);
+
+ assertTrue(result);
+ verify(_vpnConnectionDao).remove(VPN_CONNECTION_ID);
+ }
+
+ @Test
+ public void testStartVpnConnectionSuccess() throws ResourceUnavailableException {
+ when(_vpnConnectionDao.acquireInLockTable(VPN_CONNECTION_ID)).thenReturn(vpnConnection);
+ vpnConnection.setState(State.Pending);
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+ Site2SiteVpnServiceProvider provider = mock(Site2SiteVpnServiceProvider.class);
+ when(provider.startSite2SiteVpn(any(Site2SiteVpnConnection.class))).thenReturn(true);
+ when(_s2sProviders.iterator()).thenReturn(List.of(provider).iterator());
+ when(_vpnConnectionDao.persist(any(Site2SiteVpnConnectionVO.class))).thenReturn(vpnConnection);
+ when(_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(anyLong(), anyBoolean())).thenReturn(true);
+
+ Site2SiteVpnConnection result = site2SiteVpnManager.startVpnConnection(VPN_CONNECTION_ID);
+
+ assertNotNull(result);
+ verify(_vpnConnectionDao, org.mockito.Mockito.atLeastOnce()).persist(any(Site2SiteVpnConnectionVO.class));
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testStartVpnConnectionWrongState() throws ResourceUnavailableException {
+ when(_vpnConnectionDao.acquireInLockTable(VPN_CONNECTION_ID)).thenReturn(vpnConnection);
+ vpnConnection.setState(State.Connected);
+
+ site2SiteVpnManager.startVpnConnection(VPN_CONNECTION_ID);
+ }
+
+ @Test
+ public void testResetVpnConnectionSuccess() throws ResourceUnavailableException {
+ ResetVpnConnectionCmd cmd = mock(ResetVpnConnectionCmd.class);
+ when(cmd.getId()).thenReturn(VPN_CONNECTION_ID);
+
+ when(_vpnConnectionDao.findById(VPN_CONNECTION_ID)).thenReturn(vpnConnection);
+ vpnConnection.setState(State.Connected);
+ when(_vpnConnectionDao.acquireInLockTable(VPN_CONNECTION_ID)).thenReturn(vpnConnection);
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+ Site2SiteVpnServiceProvider provider = mock(Site2SiteVpnServiceProvider.class);
+ when(provider.stopSite2SiteVpn(any(Site2SiteVpnConnection.class))).thenReturn(true);
+ when(provider.startSite2SiteVpn(any(Site2SiteVpnConnection.class))).thenReturn(true);
+ when(_s2sProviders.iterator()).thenReturn(List.of(provider).iterator());
+ when(_vpnConnectionDao.persist(any(Site2SiteVpnConnectionVO.class))).thenReturn(vpnConnection);
+ when(_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(anyLong(), anyBoolean())).thenReturn(true);
+
+ Site2SiteVpnConnection result = site2SiteVpnManager.resetVpnConnection(cmd);
+
+ assertNotNull(result);
+ }
+
+ @Test
+ public void testCleanupVpnConnectionByVpc() {
+ when(_vpnConnectionDao.listByVpcId(VPC_ID)).thenReturn(List.of(vpnConnection));
+
+ boolean result = site2SiteVpnManager.cleanupVpnConnectionByVpc(VPC_ID);
+
+ assertTrue(result);
+ verify(_vpnConnectionDao).remove(vpnConnection.getId());
+ }
+
+ @Test
+ public void testCleanupVpnGatewayByVpc() {
+ when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(vpnGateway);
+ when(_vpnConnectionDao.listByVpnGatewayId(VPN_GATEWAY_ID)).thenReturn(new ArrayList<>());
+
+ boolean result = site2SiteVpnManager.cleanupVpnGatewayByVpc(VPC_ID);
+
+ assertTrue(result);
+ verify(_vpnGatewayDao).remove(VPN_GATEWAY_ID);
+ }
+
+ @Test
+ public void testCleanupVpnGatewayByVpcNotFound() {
+ when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(null);
+
+ boolean result = site2SiteVpnManager.cleanupVpnGatewayByVpc(VPC_ID);
+
+ assertTrue(result);
+ verify(_vpnGatewayDao, never()).remove(anyLong());
+ }
+
+ @Test
+ public void testGetConnectionsForRouter() {
+ DomainRouterVO router = mock(DomainRouterVO.class);
+ when(router.getVpcId()).thenReturn(VPC_ID);
+ when(_vpnConnectionDao.listByVpcId(VPC_ID)).thenReturn(List.of(vpnConnection));
+
+ List<Site2SiteVpnConnectionVO> result = site2SiteVpnManager.getConnectionsForRouter(router);
+
+ assertNotNull(result);
+ assertEquals(1, result.size());
+ }
+
+ @Test
+ public void testGetConnectionsForRouterNoVpc() {
+ DomainRouterVO router = mock(DomainRouterVO.class);
+ when(router.getVpcId()).thenReturn(null);
+
+ List<Site2SiteVpnConnectionVO> result = site2SiteVpnManager.getConnectionsForRouter(router);
+
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testDeleteCustomerGatewayByAccount() {
+ when(_customerGatewayDao.listByAccountId(ACCOUNT_ID)).thenReturn(List.of(customerGateway));
+ when(_vpnConnectionDao.listByCustomerGatewayId(CUSTOMER_GATEWAY_ID)).thenReturn(new ArrayList<>());
+
+ boolean result = site2SiteVpnManager.deleteCustomerGatewayByAccount(ACCOUNT_ID);
+
+ assertTrue(result);
+ verify(_customerGatewayDao).remove(CUSTOMER_GATEWAY_ID);
+ }
+
+ @Test
+ public void testReconnectDisconnectedVpnByVpc() throws ResourceUnavailableException {
+ Site2SiteVpnConnectionVO conn = mock(Site2SiteVpnConnectionVO.class);
+ when(conn.getId()).thenReturn(VPN_CONNECTION_ID);
+ when(conn.getState()).thenReturn(State.Disconnected);
+ when(conn.getCustomerGatewayId()).thenReturn(CUSTOMER_GATEWAY_ID);
+ when(conn.getVpnGatewayId()).thenReturn(VPN_GATEWAY_ID);
+ when(_vpnConnectionDao.listByVpcId(VPC_ID)).thenReturn(List.of(conn));
+ when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGateway);
+ when(_vpnConnectionDao.acquireInLockTable(VPN_CONNECTION_ID)).thenReturn(conn);
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+ Site2SiteVpnServiceProvider provider = mock(Site2SiteVpnServiceProvider.class);
+ when(provider.startSite2SiteVpn(any(Site2SiteVpnConnection.class))).thenReturn(true);
+ when(_s2sProviders.iterator()).thenReturn(List.of(provider).iterator());
+ when(_vpnConnectionDao.persist(any(Site2SiteVpnConnectionVO.class))).thenReturn(conn);
+ when(_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(anyLong(), anyBoolean())).thenReturn(true);
+
+ site2SiteVpnManager.reconnectDisconnectedVpnByVpc(VPC_ID);
+
+ verify(_vpnConnectionDao, org.mockito.Mockito.atLeastOnce()).persist(any(Site2SiteVpnConnectionVO.class));
+ }
+
+ @Test
+ public void testUpdateVpnConnection() {
+ when(_vpnConnectionDao.findById(VPN_CONNECTION_ID)).thenReturn(vpnConnection);
+ when(_vpnConnectionDao.update(anyLong(), any(Site2SiteVpnConnectionVO.class))).thenReturn(true);
+ when(_vpnConnectionDao.findById(VPN_CONNECTION_ID)).thenReturn(vpnConnection);
+
+ Site2SiteVpnConnection result = site2SiteVpnManager.updateVpnConnection(VPN_CONNECTION_ID, "custom-id", true);
+
+ assertNotNull(result);
+ }
+
+ @Test
+ public void testUpdateVpnGateway() {
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+ when(_vpnGatewayDao.update(anyLong(), any(Site2SiteVpnGatewayVO.class))).thenReturn(true);
+ when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway);
+
+ Site2SiteVpnGateway result = site2SiteVpnManager.updateVpnGateway(VPN_GATEWAY_ID, "custom-id", true);
+
+ assertNotNull(result);
+ }
+
+ @Test
+ public void testVpnGatewayContainsExcludedParametersWithExcludedIkeVersion() throws Exception {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ikev1");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, "ikev1");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw);
+ assertFalse("Should detect excluded IKE version", result.isEmpty());
+ assertEquals("Should detect excluded IKE version", "[ikev1]", result.toString());
+ }
+
+ @Test
+ public void testVpnGatewayContainsExcludedParametersWithExcludedEncryption() throws Exception {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("3des-sha256;modp2048");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "3des");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw);
+ assertFalse("Should detect excluded encryption algorithm", result.isEmpty());
+ assertEquals("Should detect excluded encryption algorithm", "[3des]", result.toString());
+ }
+
+ @Test
+ public void testVpnGatewayContainsExcludedParametersWithExcludedHashing() throws Exception {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-md5;modp2048");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "aes128");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, "md5");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw);
+ assertFalse("Should detect excluded algorithms", result.isEmpty());
+ assertEquals("Should detect excluded algorithms", "[aes128, md5]", result.toString());
+ }
+
+ @Test
+ public void testVpnGatewayContainsExcludedParametersWithExcludedDhGroup() {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp1024");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, "modp1024");
+
+ java.util.Set<String> result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw);
+ assertFalse("Should detect excluded DH group", result.isEmpty());
+ assertEquals("Should detect excluded DH group", "[modp1024]", result.toString());
+ }
+
+ @Test
+ public void testVpnGatewayContainsExcludedParametersNoExcludedParameters() {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw);
+ assertTrue("Should not detect excluded parameters when none are configured", result.isEmpty());
+ }
+
+ @Test
+ public void testVpnGatewayContainsExcludedParametersWithExcludedEspPolicy() {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getEspPolicy()).thenReturn("3des-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "3des");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw);
+ assertFalse("Should detect excluded encryption in ESP policy", result.isEmpty());
+ assertEquals("Should detect excluded encryption in ESP policy", "[3des]", result.toString());
+ }
+
+ @Test
+ public void testVpnGatewayContainsObsoleteParametersWithObsoleteIkeVersion() {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ikev1");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, "ikev1");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw);
+ assertFalse("Should detect obsolete IKE version", result.isEmpty());
+ assertEquals("Should detect obsolete IKE version", "[ikev1]", result.toString());
+ }
+
+ @Test
+ public void testVpnGatewayContainsObsoleteParametersWithObsoleteEncryption() {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("3des-sha256;modp2048");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, "3des");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw);
+ assertFalse("Should detect obsolete encryption algorithm", result.isEmpty());
+ assertEquals("Should detect obsolete encryption algorithm", "[3des]", result.toString());
+ }
+
+ @Test
+ public void testVpnGatewayContainsObsoleteParametersWithObsoleteHashing() {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-md5;modp2048");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, "md5");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw);
+ assertFalse("Should detect obsolete hashing algorithm", result.isEmpty());
+ assertEquals("Should detect obsolete hashing algorithm", "[md5]", result.toString());
+ }
+
+ @Test
+ public void testVpnGatewayContainsObsoleteParametersWithObsoleteDhGroup() {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp1024");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, "modp1024");
+
+ java.util.Set<String> result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw);
+ assertFalse("Should detect obsolete DH group", result.isEmpty());
+ assertEquals("Should detect obsolete DH group", "[modp1024]", result.toString());
+ }
+
+ @Test
+ public void testVpnGatewayContainsObsoleteParametersNoObsoleteParameters() {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw);
+ assertTrue("Should not detect obsolete parameters when none are configured", result.isEmpty());
+ }
+
+ @Test
+ public void testVpnGatewayContainsObsoleteParametersWithObsoleteEspPolicy() {
+ Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class);
+ when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048");
+ when(gw.getEspPolicy()).thenReturn("3des-sha256;modp2048");
+ when(gw.getIkeVersion()).thenReturn("ike");
+ when(gw.getDomainId()).thenReturn(DOMAIN_ID);
+
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, "3des");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, "");
+ setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, "");
+
+ java.util.Set<String> result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw);
+ assertFalse("Should detect obsolete encryption in ESP policy", result.isEmpty());
+ assertEquals("Should detect obsolete encryption in ESP policy", "[3des]", result.toString());
+ }
+}
diff --git a/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java b/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java
index 42022ce..84586bc 100644
--- a/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java
+++ b/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java
@@ -150,6 +150,7 @@
overrideDefaultConfigValue(ResourceLimitService.ResourceLimitStorageTags, "_defaultValue", StringUtils.join(storageTags, ","));
Account account = mock(Account.class);
+ when(account.getType()).thenReturn(Account.Type.ADMIN);
User user = mock(User.class);
CallContext.register(user, account);
}
diff --git a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
index 1ea78bf..4edafb3 100644
--- a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
+++ b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
@@ -40,8 +40,10 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
@@ -59,7 +61,6 @@
import java.util.TimeZone;
import java.util.UUID;
-import com.cloud.storage.dao.SnapshotPolicyDao;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.api.ApiCommandResourceType;
@@ -87,6 +88,7 @@
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
+import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.template.VnfTemplateManager;
@@ -116,6 +118,7 @@
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlanner;
import com.cloud.deploy.DeploymentPlanningManager;
+import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEventUtils;
@@ -141,9 +144,9 @@
import com.cloud.network.dao.LoadBalancerVMMapVO;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
-import com.cloud.network.element.UserDataServiceProvider;
import com.cloud.network.dao.PhysicalNetworkDao;
import com.cloud.network.dao.PhysicalNetworkVO;
+import com.cloud.network.element.UserDataServiceProvider;
import com.cloud.network.guru.NetworkGuru;
import com.cloud.network.rules.FirewallRuleVO;
import com.cloud.network.rules.PortForwardingRule;
@@ -171,6 +174,7 @@
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.SnapshotDao;
+import com.cloud.storage.dao.SnapshotPolicyDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.template.VirtualMachineTemplate;
@@ -466,6 +470,24 @@
Class<InvalidParameterValueException> expectedInvalidParameterValueException = InvalidParameterValueException.class;
Class<CloudRuntimeException> expectedCloudRuntimeException = CloudRuntimeException.class;
+ private Map<ConfigKey, Object> originalConfigValues = new HashMap<>();
+
+
+ private void updateDefaultConfigValue(final ConfigKey configKey, final Object o, boolean revert) {
+ try {
+ final String name = "_defaultValue";
+ Field f = ConfigKey.class.getDeclaredField(name);
+ f.setAccessible(true);
+ String stringVal = String.valueOf(o);
+ if (!revert) {
+ originalConfigValues.put(configKey, f.get(configKey));
+ }
+ f.set(configKey, stringVal);
+ } catch (IllegalAccessException | NoSuchFieldException e) {
+ Assert.fail("Failed to mock config " + configKey.key() + " value due to " + e.getMessage());
+ }
+ }
+
@Before
public void beforeTest() {
userVmManagerImpl.resourceLimitService = resourceLimitMgr;
@@ -495,6 +517,9 @@
public void afterTest() {
CallContext.unregister();
unmanagedVMsManagerMockedStatic.close();
+ for (Map.Entry<ConfigKey, Object> entry : originalConfigValues.entrySet()) {
+ updateDefaultConfigValue(entry.getKey(), entry.getValue(), true);
+ }
}
@Test
@@ -1135,7 +1160,7 @@
ReflectionTestUtils.setField(deployVMCmd, "serviceOfferingId", serviceOfferingId);
deployVMCmd._accountService = accountService;
- when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
+ when(accountService.finalizeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(_dcMock);
when(entityManager.findById(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOffering);
@@ -1152,7 +1177,7 @@
ReflectionTestUtils.setField(deployVMCmd, "serviceOfferingId", serviceOfferingId);
deployVMCmd._accountService = accountService;
- when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
+ when(accountService.finalizeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(_dcMock);
when(entityManager.findById(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOffering);
@@ -1408,7 +1433,7 @@
ReflectionTestUtils.setField(deployVMCmd, "serviceOfferingId", serviceOfferingId);
deployVMCmd._accountService = accountService;
- when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
+ when(accountService.finalizeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(_dcMock);
when(entityManager.findById(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOffering);
@@ -3107,7 +3132,7 @@
configureDoNothingForMethodsThatWeDoNotWantToTest();
- doThrow(PermissionDeniedException.class).when(accountManager).checkAccess(Mockito.any(Account.class), Mockito.any());
+ doThrow(PermissionDeniedException.class).when(accountManager).checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class));
Assert.assertThrows(PermissionDeniedException.class, () -> userVmManagerImpl.moveVmToUser(assignVmCmdMock));
}
@@ -3302,7 +3327,7 @@
CreateVMFromBackupCmd cmd = new CreateVMFromBackupCmd();
cmd._accountService = accountService;
cmd._entityMgr = entityManager;
- when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
+ when(accountService.finalizeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
ReflectionTestUtils.setField(cmd, "serviceOfferingId", serviceOfferingId);
@@ -3473,7 +3498,7 @@
CreateVMFromBackupCmd cmd = new CreateVMFromBackupCmd();
cmd._accountService = accountService;
cmd._entityMgr = entityManager;
- when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
+ when(accountService.finalizeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
ReflectionTestUtils.setField(cmd, "serviceOfferingId", serviceOfferingId);
@@ -3862,7 +3887,7 @@
ReflectionTestUtils.setField(deployVMCmd, "volumeId", volumeId);
deployVMCmd._accountService = accountService;
- when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
+ when(accountService.finalizeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(_dcMock);
when(entityManager.findById(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOffering);
@@ -3898,7 +3923,7 @@
ReflectionTestUtils.setField(deployVMCmd, "snapshotId", snashotId);
deployVMCmd._accountService = accountService;
- when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
+ when(accountService.finalizeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(_dcMock);
when(entityManager.findById(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOffering);
@@ -3936,7 +3961,7 @@
CreateVMFromBackupCmd cmd = new CreateVMFromBackupCmd();
cmd._accountService = accountService;
cmd._entityMgr = entityManager;
- when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
+ when(accountService.finalizeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
ReflectionTestUtils.setField(cmd, "serviceOfferingId", serviceOfferingId);
@@ -4002,7 +4027,7 @@
CreateVMFromBackupCmd cmd = new CreateVMFromBackupCmd();
cmd._accountService = accountService;
cmd._entityMgr = entityManager;
- when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
+ when(accountService.finalizeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
ReflectionTestUtils.setField(cmd, "serviceOfferingId", serviceOfferingId);
@@ -4177,4 +4202,49 @@
verify(userVmDao, times(1)).releaseFromLockTable(vmId);
}
+ @Test
+ public void updateVmExtraConfigCleansUpWhenCleanupFlagIsTrue() {
+ UserVmVO userVm = mock(UserVmVO.class);
+ when(userVm.getUuid()).thenReturn("test-uuid");
+ when(userVm.getId()).thenReturn(1L);
+
+ userVmManagerImpl.updateVmExtraConfig(userVm, "someConfig", true);
+
+ verify(vmInstanceDetailsDao, times(1)).removeDetailsWithPrefix(1L, ApiConstants.EXTRA_CONFIG);
+ verifyNoMoreInteractions(vmInstanceDetailsDao);
+ }
+
+ @Test
+ public void updateVmExtraConfigAddsConfigWhenValidAndEnabled() {
+ UserVmVO userVm = mock(UserVmVO.class);
+ when(userVm.getUuid()).thenReturn("test-uuid");
+ when(userVm.getAccountId()).thenReturn(1L);
+ when(userVm.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ doNothing().when(userVmManagerImpl).persistExtraConfigKvm(anyString(), eq(userVm));
+ updateDefaultConfigValue(UserVmManagerImpl.EnableAdditionalVmConfig, true, false);
+
+ userVmManagerImpl.updateVmExtraConfig(userVm, "validConfig", false);
+
+ verify(vmInstanceDetailsDao, never()).removeDetailsWithPrefix(anyLong(), anyString());
+ verify(userVmManagerImpl, times(1)).addExtraConfig(userVm, "validConfig");
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void updateVmExtraConfigThrowsExceptionWhenConfigDisabled() {
+ UserVmVO userVm = mock(UserVmVO.class);
+ when(userVm.getAccountId()).thenReturn(1L);
+ updateDefaultConfigValue(UserVmManagerImpl.EnableAdditionalVmConfig, false, false);
+
+ userVmManagerImpl.updateVmExtraConfig(userVm, "validConfig", false);
+ }
+
+ @Test
+ public void updateVmExtraConfigDoesNothingWhenExtraConfigIsBlank() {
+ UserVmVO userVm = mock(UserVmVO.class);
+
+ userVmManagerImpl.updateVmExtraConfig(userVm, "", false);
+
+ verify(vmInstanceDetailsDao, never()).removeDetailsWithPrefix(anyLong(), anyString());
+ verify(userVmManagerImpl, never()).addExtraConfig(any(UserVmVO.class), anyString());
+ }
}
diff --git a/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java b/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java
index a0f0998..b696d74 100644
--- a/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java
+++ b/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java
@@ -41,6 +41,7 @@
import com.cloud.storage.dao.VolumeDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.uservm.UserVm;
@@ -136,6 +137,8 @@
VMSnapshotDetailsDao _vmSnapshotDetailsDao;
@Mock
UserVmManager _userVmManager;
+ @Mock
+ private AccountVO accountVOMock;
private static final long TEST_VM_ID = 3L;
private static final long SERVICE_OFFERING_ID = 1L;
@@ -285,8 +288,12 @@
@SuppressWarnings("unchecked")
@Test(expected = CloudRuntimeException.class)
public void testAllocVMSnapshotF4() throws ResourceAllocationException {
+ long accountId = 1L;
List<VMSnapshotVO> mockList = mock(List.class);
when(mockList.size()).thenReturn(10);
+ when(_userVMDao.findById(TEST_VM_ID)).thenReturn(vmMock);
+ when(userVm.getAccountId()).thenReturn(accountId);
+ when(_accountMgr.getAccount(accountId)).thenReturn(accountVOMock);
when(_vmSnapshotDao.findByVm(TEST_VM_ID)).thenReturn(mockList);
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID, "", "", true);
}
@@ -295,8 +302,12 @@
@SuppressWarnings("unchecked")
@Test(expected = CloudRuntimeException.class)
public void testAllocVMSnapshotF5() throws ResourceAllocationException {
+ long accountId = 1L;
List<SnapshotVO> mockList = mock(List.class);
when(mockList.size()).thenReturn(1);
+ when(_userVMDao.findById(TEST_VM_ID)).thenReturn(vmMock);
+ when(userVm.getAccountId()).thenReturn(accountId);
+ when(_accountMgr.getAccount(accountId)).thenReturn(accountVOMock);
when(_snapshotDao.listByInstanceId(TEST_VM_ID, Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp)).thenReturn(mockList);
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID, "", "", true);
}
@@ -304,6 +315,10 @@
// successful creation case
@Test
public void testCreateVMSnapshot() throws AgentUnavailableException, OperationTimedoutException, ResourceAllocationException, NoTransitionException {
+ long accountId = 1L;
+ when(_userVMDao.findById(TEST_VM_ID)).thenReturn(vmMock);
+ when(userVm.getAccountId()).thenReturn(accountId);
+ when(_accountMgr.getAccount(accountId)).thenReturn(accountVOMock);
when(vmMock.getState()).thenReturn(State.Running);
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID, "", "", true);
}
diff --git a/server/src/test/java/com/cloud/vpc/MockSite2SiteVpnManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockSite2SiteVpnManagerImpl.java
index 3558eed..af6c1c5 100644
--- a/server/src/test/java/com/cloud/vpc/MockSite2SiteVpnManagerImpl.java
+++ b/server/src/test/java/com/cloud/vpc/MockSite2SiteVpnManagerImpl.java
@@ -23,7 +23,6 @@
import com.cloud.network.Site2SiteVpnGateway;
import com.cloud.network.dao.Site2SiteVpnConnectionVO;
import com.cloud.network.vpn.Site2SiteVpnManager;
-import com.cloud.network.vpn.Site2SiteVpnService;
import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase;
import com.cloud.vm.DomainRouterVO;
@@ -41,11 +40,13 @@
import org.springframework.stereotype.Component;
import javax.naming.ConfigurationException;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
@Component
-public class MockSite2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager, Site2SiteVpnService {
+public class MockSite2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager {
/* (non-Javadoc)
* @see com.cloud.network.vpn.Site2SiteVpnService#createVpnGateway(org.apache.cloudstack.api.commands.CreateVpnGatewayCmd)
@@ -275,4 +276,16 @@
return null;
}
+ @Override
+ public Set<String> getExcludedVpnGatewayParameters(Site2SiteCustomerGateway customerGw) {
+ // TODO Auto-generated method stub
+ return new HashSet<>();
+ }
+
+ @Override
+ public Set<String> getObsoleteVpnGatewayParameters(Site2SiteCustomerGateway customerGw) {
+ // TODO Auto-generated method stub
+ return new HashSet<>();
+ }
+
}
diff --git a/server/src/test/java/com/cloud/vpc/Site2SiteVpnTest.java b/server/src/test/java/com/cloud/vpc/Site2SiteVpnTest.java
deleted file mode 100644
index f8a42df..0000000
--- a/server/src/test/java/com/cloud/vpc/Site2SiteVpnTest.java
+++ /dev/null
@@ -1,75 +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.
-package com.cloud.vpc;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-
-@RunWith(SpringJUnit4ClassRunner.class)
-@ContextConfiguration(locations = "classpath:/VpcTestContext.xml")
-public class Site2SiteVpnTest {
-
-// private static void addDaos(MockComponentLocator locator) {
-// locator.addDao("AccountDao", AccountDaoImpl.class);
-// locator.addDao("Site2SiteCustomerGatewayDao", Site2SiteCustomerGatewayDaoImpl.class);
-// locator.addDao("Site2SiteVpnGatewayDao", Site2SiteVpnGatewayDaoImpl.class);
-// locator.addDao("Site2SiteVpnConnectionDao", Site2SiteVpnConnectionDaoImpl.class);
-//
-// locator.addDao("IPAddressDao", IPAddressDaoImpl.class);
-// locator.addDao("VpcDao", VpcDaoImpl.class);
-// locator.addDao("ConfiguratioDao", MockConfigurationDaoImpl.class);
-//
-// }
-//
-// private static void addManagers(MockComponentLocator locator) {
-// locator.addManager("AccountManager", MockAccountManagerImpl.class);
-// locator.addManager("VpcManager", MockVpcManagerImpl.class);
-// }
-
- @Before
- public void setUp() {
-// locator = new MockComponentLocator("management-server");
-// addDaos(locator);
-// addManagers(locator);
-// logger.info("Finished setUp");
- }
-
- @After
- public void tearDown() throws Exception {
- }
-
- @Test
- public void testInjected() throws Exception {
-// List<Pair<String, Class<? extends Site2SiteVpnServiceProvider>>> list =
-// new ArrayList<Pair<String, Class<? extends Site2SiteVpnServiceProvider>>>();
-// list.add(new Pair<String, Class<? extends Site2SiteVpnServiceProvider>>("Site2SiteVpnServiceProvider", MockSite2SiteVpnServiceProvider.class));
-// locator.addAdapterChain(Site2SiteVpnServiceProvider.class, list);
-// logger.info("Finished add adapter");
-// locator.makeActive(new DefaultInterceptorLibrary());
-// logger.info("Finished make active");
-// Site2SiteVpnManagerImpl vpnMgr = ComponentLocator.inject(Site2SiteVpnManagerImpl.class);
-// logger.info("Finished inject");
-// Assert.assertTrue(vpnMgr.configure("Site2SiteVpnMgr",new HashMap<String, Object>()) );
-// Assert.assertTrue(vpnMgr.start());
-
- }
-
-}
diff --git a/server/src/test/java/com/cloud/vpc/VpcTestConfiguration.java b/server/src/test/java/com/cloud/vpc/VpcTestConfiguration.java
index 22c0b47..0d45d50 100644
--- a/server/src/test/java/com/cloud/vpc/VpcTestConfiguration.java
+++ b/server/src/test/java/com/cloud/vpc/VpcTestConfiguration.java
@@ -176,11 +176,6 @@
return Mockito.mock(RemoteAccessVpnService.class);
}
-// @Bean
-// public VpcDao vpcDao() {
-// return Mockito.mock(VpcDao.class);
-// }
-
@Bean
public NetworkDao networkDao() {
return Mockito.mock(NetworkDao.class);
diff --git a/server/src/test/java/org/apache/cloudstack/affinity/AffinityApiUnitTest.java b/server/src/test/java/org/apache/cloudstack/affinity/AffinityApiUnitTest.java
index e27d961..e8cc05c 100644
--- a/server/src/test/java/org/apache/cloudstack/affinity/AffinityApiUnitTest.java
+++ b/server/src/test/java/org/apache/cloudstack/affinity/AffinityApiUnitTest.java
@@ -190,7 +190,7 @@
@Test(expected = InvalidParameterValueException.class)
public void deleteAffinityGroupInvalidIdName() throws ResourceInUseException {
- when(_acctMgr.finalyzeAccountId("user", domainId, null, true)).thenReturn(200L);
+ when(_acctMgr.finalizeAccountId("user", domainId, null, true)).thenReturn(200L);
when(_groupDao.findByAccountAndName(200L, "group1")).thenReturn(null);
_affinityService.deleteAffinityGroup(null, "user", null, domainId, "group1");
}
diff --git a/server/src/test/java/org/apache/cloudstack/affinity/AffinityGroupServiceImplTest.java b/server/src/test/java/org/apache/cloudstack/affinity/AffinityGroupServiceImplTest.java
index 5657bd1..4955614 100644
--- a/server/src/test/java/org/apache/cloudstack/affinity/AffinityGroupServiceImplTest.java
+++ b/server/src/test/java/org/apache/cloudstack/affinity/AffinityGroupServiceImplTest.java
@@ -253,7 +253,7 @@
@Test(expected = InvalidParameterValueException.class)
public void deleteAffinityGroupInvalidIdName() throws ResourceInUseException {
when(_acctMgr.finalizeOwner((Account)any(), anyString(), anyLong(), anyLong())).thenReturn(acct);
- when(_acctMgr.finalyzeAccountId(ACCOUNT_NAME, DOMAIN_ID, null, true)).thenReturn(200L);
+ when(_acctMgr.finalizeAccountId(ACCOUNT_NAME, DOMAIN_ID, null, true)).thenReturn(200L);
when(_groupDao.findByAccountAndName(200L, AFFINITY_GROUP_NAME)).thenReturn(null);
_affinityService.deleteAffinityGroup(null, ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME);
}
diff --git a/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java b/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java
index 8b13fd4..a9c0832 100644
--- a/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java
+++ b/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java
@@ -60,6 +60,7 @@
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.DateUtil;
+import com.cloud.utils.DomainHelper;
import com.cloud.utils.Pair;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@@ -80,11 +81,13 @@
import org.apache.cloudstack.api.command.user.backup.CreateBackupCmd;
import org.apache.cloudstack.api.command.user.backup.CreateBackupScheduleCmd;
import org.apache.cloudstack.api.command.user.backup.DeleteBackupScheduleCmd;
+import org.apache.cloudstack.api.command.user.backup.ListBackupOfferingsCmd;
import org.apache.cloudstack.api.command.user.backup.ListBackupScheduleCmd;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.dao.BackupDetailsDao;
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
+import org.apache.cloudstack.backup.dao.BackupOfferingDetailsDao;
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
@@ -241,6 +244,12 @@
@Mock
private GuestOSDao _guestOSDao;
+ @Mock
+ private BackupOfferingDetailsDao backupOfferingDetailsDao;
+
+ @Mock
+ DomainHelper domainHelper;
+
private Gson gson;
private String[] hostPossibleValues = {"127.0.0.1", "hostname"};
@@ -352,6 +361,7 @@
when(cmd.getName()).thenReturn("New name");
when(cmd.getDescription()).thenReturn("New description");
when(cmd.getAllowUserDrivenBackups()).thenReturn(true);
+ when(backupOfferingDetailsDao.findDomainIds(id)).thenReturn(Collections.emptyList());
BackupOffering updated = backupManager.updateBackupOffering(cmd);
assertEquals("New name", updated.getName());
@@ -1081,7 +1091,7 @@
assertEquals("root-disk-offering-uuid", VmDiskInfo.getDiskOffering().getUuid());
assertEquals(Long.valueOf(5), VmDiskInfo.getSize());
- assertEquals(null, VmDiskInfo.getDeviceId());
+ assertNull(VmDiskInfo.getDeviceId());
}
@Test
@@ -1106,7 +1116,7 @@
assertEquals("Test Offering", result.getName());
assertEquals("Test Description", result.getDescription());
- assertEquals(true, result.isUserDrivenBackupAllowed());
+ assertTrue(result.isUserDrivenBackupAllowed());
assertEquals("external-id", result.getExternalId());
assertEquals("testbackupprovider", result.getProvider());
}
@@ -1149,6 +1159,8 @@
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vm.getId()).thenReturn(vmId);
BackupOfferingVO offering = mock(BackupOfferingVO.class);
+ Account owner = mock(Account.class);
+
overrideBackupFrameworkConfigValue();
@@ -1159,6 +1171,8 @@
when(vm.getBackupOfferingId()).thenReturn(null);
when(offering.getProvider()).thenReturn("testbackupprovider");
when(backupProvider.assignVMToBackupOffering(vm, offering)).thenReturn(true);
+ when(vm.getAccountId()).thenReturn(3L);
+ when(accountManager.getAccount(vm.getAccountId())).thenReturn(owner);
when(vmInstanceDao.update(1L, vm)).thenReturn(true);
try (MockedStatic<UsageEventUtils> ignored2 = Mockito.mockStatic(UsageEventUtils.class)) {
@@ -2156,4 +2170,352 @@
verify(vmInstanceDao, times(1)).findByIdIncludingRemoved(vmId);
verify(volumeDao, times(1)).findByInstance(vmId);
}
+
+ @Test
+ public void getBackupOfferingDomainsTestOfferingNotFound() {
+ Long offeringId = 1L;
+ when(backupOfferingDao.findById(offeringId)).thenReturn(null);
+
+ InvalidParameterValueException exception = Assert.assertThrows(InvalidParameterValueException.class,
+ () -> backupManager.getBackupOfferingDomains(offeringId));
+ assertEquals("Unable to find backup offering for id: " + offeringId, exception.getMessage());
+ }
+
+ @Test
+ public void getBackupOfferingDomainsTestReturnsDomains() {
+ Long offeringId = 1L;
+ BackupOfferingVO offering = Mockito.mock(BackupOfferingVO.class);
+ when(backupOfferingDao.findById(offeringId)).thenReturn(offering);
+ when(backupOfferingDetailsDao.findDomainIds(offeringId)).thenReturn(List.of(10L, 20L));
+
+ List<Long> result = backupManager.getBackupOfferingDomains(offeringId);
+
+ assertEquals(2, result.size());
+ assertTrue(result.contains(10L));
+ assertTrue(result.contains(20L));
+ }
+
+ @Test
+ public void testUpdateBackupOfferingThrowsWhenDomainIdInvalid() {
+ Long id = 1234L;
+ UpdateBackupOfferingCmd cmd = Mockito.spy(UpdateBackupOfferingCmd.class);
+ when(cmd.getId()).thenReturn(id);
+ when(cmd.getDomainIds()).thenReturn(List.of(99L));
+
+ when(domainDao.findById(99L)).thenReturn(null);
+
+ InvalidParameterValueException exception = Assert.assertThrows(InvalidParameterValueException.class,
+ () -> backupManager.updateBackupOffering(cmd));
+ assertEquals("Please specify a valid domain id", exception.getMessage());
+ }
+
+ @Test
+ public void testUpdateBackupOfferingPersistsDomainDetailsWhenProvided() {
+ Long id = 1234L;
+ Long domainId = 11L;
+ UpdateBackupOfferingCmd cmd = Mockito.spy(UpdateBackupOfferingCmd.class);
+ when(cmd.getId()).thenReturn(id);
+ when(cmd.getDomainIds()).thenReturn(List.of(domainId));
+
+ DomainVO domain = Mockito.mock(DomainVO.class);
+ when(domainDao.findById(domainId)).thenReturn(domain);
+
+ when(domainHelper.filterChildSubDomains(List.of(domainId))).thenReturn(new ArrayList<>(List.of(domainId)));
+ when(backupOfferingDetailsDao.findDomainIds(id)).thenReturn(new ArrayList<>());
+
+ BackupOfferingVO offering = Mockito.mock(BackupOfferingVO.class);
+ BackupOfferingVO offeringUpdate = Mockito.mock(BackupOfferingVO.class);
+ when(backupOfferingDao.findById(id)).thenReturn(offering);
+ when(backupOfferingDao.createForUpdate(id)).thenReturn(offeringUpdate);
+ when(backupOfferingDao.update(id, offeringUpdate)).thenReturn(true);
+
+ BackupOffering updated = backupManager.updateBackupOffering(cmd);
+
+ verify(backupOfferingDetailsDao, times(1)).updateBackupOfferingDomainIdsDetail(id, List.of(domainId));
+ }
+
+ @Test
+ public void testListBackupOfferingsWithDomainFilteringIncludesGlobalOfferings() {
+ Long requestedDomainId = 3L;
+
+ ListBackupOfferingsCmd cmd =
+ Mockito.mock(ListBackupOfferingsCmd.class);
+ when(cmd.getOfferingId()).thenReturn(null);
+ when(cmd.getDomainId()).thenReturn(requestedDomainId);
+ when(cmd.getStartIndex()).thenReturn(0L);
+ when(cmd.getPageSizeVal()).thenReturn(20L);
+
+ BackupOfferingVO globalOffering = createMockOffering(1L, "Global Offering");
+ BackupOfferingVO domainOffering = createMockOffering(2L, "Domain Offering");
+
+ List<BackupOfferingVO> allOfferings = List.of(globalOffering, domainOffering);
+
+ SearchBuilder<BackupOfferingVO> sb = Mockito.mock(SearchBuilder.class);
+ SearchCriteria<BackupOfferingVO> sc = Mockito.mock(SearchCriteria.class);
+ BackupOfferingVO entityMock = Mockito.mock(BackupOfferingVO.class);
+ when(backupOfferingDao.createSearchBuilder()).thenReturn(sb);
+ when(sb.entity()).thenReturn(entityMock);
+ when(sb.and(Mockito.anyString(), Mockito.any(), Mockito.any(SearchCriteria.Op.class))).thenReturn(sb);
+ when(sb.create()).thenReturn(sc);
+ when(backupOfferingDao.searchAndCount(Mockito.any(), Mockito.any()))
+ .thenReturn(new Pair<>(allOfferings, allOfferings.size()));
+
+ when(backupOfferingDetailsDao.findDomainIds(1L)).thenReturn(Collections.emptyList());
+ when(backupOfferingDetailsDao.findDomainIds(2L)).thenReturn(List.of(2L));
+
+ Account account = Mockito.mock(Account.class);
+ when(account.getType()).thenReturn(Account.Type.NORMAL);
+
+ try (MockedStatic<CallContext> mockedCallContext = Mockito.mockStatic(CallContext.class)) {
+ CallContext contextMock = Mockito.mock(CallContext.class);
+ mockedCallContext.when(CallContext::current).thenReturn(contextMock);
+ when(contextMock.getCallingAccount()).thenReturn(account);
+
+ Pair<List<BackupOffering>, Integer> result = backupManager.listBackupOfferings(cmd);
+
+ assertEquals(1, result.first().size());
+ assertEquals("Global Offering", result.first().get(0).getName());
+ }
+ }
+
+ @Test
+ public void testListBackupOfferingsWithDomainFilteringIncludesDirectDomainMapping() {
+ Long requestedDomainId = 3L;
+
+ ListBackupOfferingsCmd cmd =
+ Mockito.mock(ListBackupOfferingsCmd.class);
+ when(cmd.getOfferingId()).thenReturn(null);
+ when(cmd.getDomainId()).thenReturn(requestedDomainId);
+ when(cmd.getStartIndex()).thenReturn(0L);
+ when(cmd.getPageSizeVal()).thenReturn(20L);
+
+ BackupOfferingVO directDomainOffering = createMockOffering(1L, "Direct Domain Offering");
+ BackupOfferingVO otherDomainOffering = createMockOffering(2L, "Other Domain Offering");
+
+ List<BackupOfferingVO> allOfferings = List.of(directDomainOffering, otherDomainOffering);
+
+ SearchBuilder<BackupOfferingVO> sb = Mockito.mock(SearchBuilder.class);
+ SearchCriteria<BackupOfferingVO> sc = Mockito.mock(SearchCriteria.class);
+ BackupOfferingVO entityMock = Mockito.mock(BackupOfferingVO.class);
+ when(backupOfferingDao.createSearchBuilder()).thenReturn(sb);
+ when(sb.entity()).thenReturn(entityMock);
+ when(sb.and(Mockito.anyString(), Mockito.any(), Mockito.any(SearchCriteria.Op.class))).thenReturn(sb);
+ when(sb.create()).thenReturn(sc);
+ when(backupOfferingDao.searchAndCount(Mockito.any(), Mockito.any()))
+ .thenReturn(new Pair<>(allOfferings, allOfferings.size()));
+
+ when(backupOfferingDetailsDao.findDomainIds(1L)).thenReturn(List.of(requestedDomainId));
+ when(backupOfferingDetailsDao.findDomainIds(2L)).thenReturn(List.of(5L));
+
+ Account account = Mockito.mock(Account.class);
+ when(account.getType()).thenReturn(Account.Type.NORMAL);
+
+ try (MockedStatic<CallContext> mockedCallContext = Mockito.mockStatic(CallContext.class)) {
+ CallContext contextMock = Mockito.mock(CallContext.class);
+ mockedCallContext.when(CallContext::current).thenReturn(contextMock);
+ when(contextMock.getCallingAccount()).thenReturn(account);
+
+ Pair<List<BackupOffering>, Integer> result = backupManager.listBackupOfferings(cmd);
+
+ assertEquals(1, result.first().size());
+ assertEquals("Direct Domain Offering", result.first().get(0).getName());
+ }
+ }
+
+ @Test
+ public void testListBackupOfferingsWithDomainFilteringIncludesParentDomainOfferings() {
+ Long parentDomainId = 1L;
+ Long childDomainId = 3L;
+
+ ListBackupOfferingsCmd cmd =
+ Mockito.mock(ListBackupOfferingsCmd.class);
+ when(cmd.getOfferingId()).thenReturn(null);
+ when(cmd.getDomainId()).thenReturn(childDomainId);
+ when(cmd.getStartIndex()).thenReturn(0L);
+ when(cmd.getPageSizeVal()).thenReturn(20L);
+
+ BackupOfferingVO parentDomainOffering = createMockOffering(1L, "Parent Domain Offering");
+ BackupOfferingVO siblingDomainOffering = createMockOffering(2L, "Sibling Domain Offering");
+
+ List<BackupOfferingVO> allOfferings = List.of(parentDomainOffering, siblingDomainOffering);
+
+ SearchBuilder<BackupOfferingVO> sb = Mockito.mock(SearchBuilder.class);
+ SearchCriteria<BackupOfferingVO> sc = Mockito.mock(SearchCriteria.class);
+ BackupOfferingVO entityMock = Mockito.mock(BackupOfferingVO.class);
+ when(backupOfferingDao.createSearchBuilder()).thenReturn(sb);
+ when(sb.entity()).thenReturn(entityMock);
+ when(sb.and(Mockito.anyString(), Mockito.any(), Mockito.any(SearchCriteria.Op.class))).thenReturn(sb);
+ when(sb.create()).thenReturn(sc);
+ when(backupOfferingDao.searchAndCount(Mockito.any(), Mockito.any()))
+ .thenReturn(new Pair<>(allOfferings, allOfferings.size()));
+
+ when(backupOfferingDetailsDao.findDomainIds(1L)).thenReturn(List.of(parentDomainId));
+ when(backupOfferingDetailsDao.findDomainIds(2L)).thenReturn(List.of(4L));
+
+ when(domainDao.isChildDomain(parentDomainId, childDomainId)).thenReturn(true);
+ when(domainDao.isChildDomain(4L, childDomainId)).thenReturn(false);
+
+ Account account = Mockito.mock(Account.class);
+ when(account.getType()).thenReturn(Account.Type.NORMAL);
+
+ try (MockedStatic<CallContext> mockedCallContext = Mockito.mockStatic(CallContext.class)) {
+ CallContext contextMock = Mockito.mock(CallContext.class);
+ mockedCallContext.when(CallContext::current).thenReturn(contextMock);
+ when(contextMock.getCallingAccount()).thenReturn(account);
+
+ Pair<List<BackupOffering>, Integer> result = backupManager.listBackupOfferings(cmd);
+
+ assertEquals(1, result.first().size());
+ assertEquals("Parent Domain Offering", result.first().get(0).getName());
+ }
+ }
+
+ @Test
+ public void testListBackupOfferingsWithDomainFilteringExcludesSiblingDomainOfferings() {
+ Long requestedDomainId = 3L;
+ Long siblingDomainId = 4L;
+
+ ListBackupOfferingsCmd cmd =
+ Mockito.mock(ListBackupOfferingsCmd.class);
+ when(cmd.getOfferingId()).thenReturn(null);
+ when(cmd.getDomainId()).thenReturn(requestedDomainId);
+ when(cmd.getStartIndex()).thenReturn(0L);
+ when(cmd.getPageSizeVal()).thenReturn(20L);
+
+ BackupOfferingVO siblingOffering = createMockOffering(1L, "Sibling Domain Offering");
+ List<BackupOfferingVO> allOfferings = List.of(siblingOffering);
+
+ SearchBuilder<BackupOfferingVO> sb = Mockito.mock(SearchBuilder.class);
+ SearchCriteria<BackupOfferingVO> sc = Mockito.mock(SearchCriteria.class);
+ BackupOfferingVO entityMock = Mockito.mock(BackupOfferingVO.class);
+ when(backupOfferingDao.createSearchBuilder()).thenReturn(sb);
+ when(sb.entity()).thenReturn(entityMock);
+ when(sb.and(Mockito.anyString(), Mockito.any(), Mockito.any(SearchCriteria.Op.class))).thenReturn(sb);
+ when(sb.create()).thenReturn(sc);
+ when(backupOfferingDao.searchAndCount(Mockito.any(), Mockito.any()))
+ .thenReturn(new Pair<>(allOfferings, allOfferings.size()));
+
+ when(backupOfferingDetailsDao.findDomainIds(1L)).thenReturn(List.of(siblingDomainId));
+ when(domainDao.isChildDomain(siblingDomainId, requestedDomainId)).thenReturn(false);
+
+ Account account = Mockito.mock(Account.class);
+ when(account.getType()).thenReturn(Account.Type.NORMAL);
+
+ try (MockedStatic<CallContext> mockedCallContext = Mockito.mockStatic(CallContext.class)) {
+ CallContext contextMock = Mockito.mock(CallContext.class);
+ mockedCallContext.when(CallContext::current).thenReturn(contextMock);
+ when(contextMock.getCallingAccount()).thenReturn(account);
+
+ Pair<List<BackupOffering>, Integer> result = backupManager.listBackupOfferings(cmd);
+
+ assertEquals(0, result.first().size());
+ }
+ }
+
+ @Test
+ public void testListBackupOfferingsWithDomainFilteringMultipleDomainMappings() {
+ Long requestedDomainId = 5L;
+ Long parentDomainId1 = 1L;
+ Long parentDomainId2 = 2L;
+ Long unrelatedDomainId = 8L;
+
+ ListBackupOfferingsCmd cmd =
+ Mockito.mock(ListBackupOfferingsCmd.class);
+ when(cmd.getOfferingId()).thenReturn(null);
+ when(cmd.getDomainId()).thenReturn(requestedDomainId);
+ when(cmd.getStartIndex()).thenReturn(0L);
+ when(cmd.getPageSizeVal()).thenReturn(20L);
+
+ BackupOfferingVO multiDomainOffering = createMockOffering(1L, "Multi-Domain Offering");
+ List<BackupOfferingVO> allOfferings = List.of(multiDomainOffering);
+
+ SearchBuilder<BackupOfferingVO> sb = Mockito.mock(SearchBuilder.class);
+ SearchCriteria<BackupOfferingVO> sc = Mockito.mock(SearchCriteria.class);
+ BackupOfferingVO entityMock = Mockito.mock(BackupOfferingVO.class);
+ when(backupOfferingDao.createSearchBuilder()).thenReturn(sb);
+ when(sb.entity()).thenReturn(entityMock);
+ when(sb.and(Mockito.anyString(), Mockito.any(), Mockito.any(SearchCriteria.Op.class))).thenReturn(sb);
+ when(sb.create()).thenReturn(sc);
+ when(backupOfferingDao.searchAndCount(Mockito.any(), Mockito.any()))
+ .thenReturn(new Pair<>(allOfferings, allOfferings.size()));
+
+ when(backupOfferingDetailsDao.findDomainIds(1L))
+ .thenReturn(List.of(parentDomainId1, unrelatedDomainId, parentDomainId2));
+
+ when(domainDao.isChildDomain(parentDomainId1, requestedDomainId)).thenReturn(false);
+ when(domainDao.isChildDomain(unrelatedDomainId, requestedDomainId)).thenReturn(false);
+ when(domainDao.isChildDomain(parentDomainId2, requestedDomainId)).thenReturn(true);
+
+ Account account = Mockito.mock(Account.class);
+ when(account.getType()).thenReturn(Account.Type.NORMAL);
+
+ try (MockedStatic<CallContext> mockedCallContext = Mockito.mockStatic(CallContext.class)) {
+ CallContext contextMock = Mockito.mock(CallContext.class);
+ mockedCallContext.when(CallContext::current).thenReturn(contextMock);
+ when(contextMock.getCallingAccount()).thenReturn(account);
+
+ Pair<List<BackupOffering>, Integer> result = backupManager.listBackupOfferings(cmd);
+
+ assertEquals(1, result.first().size());
+ assertEquals("Multi-Domain Offering", result.first().get(0).getName());
+ }
+ }
+
+ @Test
+ public void testListBackupOfferingsNormalUserDefaultsToDomainFiltering() {
+ Long userDomainId = 7L;
+
+ ListBackupOfferingsCmd cmd =
+ Mockito.mock(ListBackupOfferingsCmd.class);
+ when(cmd.getOfferingId()).thenReturn(null);
+ when(cmd.getDomainId()).thenReturn(null); // User didn't pass domain filter
+ when(cmd.getStartIndex()).thenReturn(0L);
+ when(cmd.getPageSizeVal()).thenReturn(20L);
+
+ BackupOfferingVO globalOffering = createMockOffering(1L, "Global Offering");
+ BackupOfferingVO userDomainOffering = createMockOffering(2L, "User Domain Offering");
+ BackupOfferingVO otherDomainOffering = createMockOffering(3L, "Other Domain Offering");
+
+ List<BackupOfferingVO> allOfferings = List.of(globalOffering, userDomainOffering, otherDomainOffering);
+
+ SearchBuilder<BackupOfferingVO> sb = Mockito.mock(SearchBuilder.class);
+ SearchCriteria<BackupOfferingVO> sc = Mockito.mock(SearchCriteria.class);
+ BackupOfferingVO entityMock = Mockito.mock(BackupOfferingVO.class);
+ when(backupOfferingDao.createSearchBuilder()).thenReturn(sb);
+ when(sb.entity()).thenReturn(entityMock);
+ when(sb.and(Mockito.anyString(), Mockito.any(), Mockito.any(SearchCriteria.Op.class))).thenReturn(sb);
+ when(sb.create()).thenReturn(sc);
+ when(backupOfferingDao.searchAndCount(Mockito.any(), Mockito.any()))
+ .thenReturn(new Pair<>(allOfferings, allOfferings.size()));
+
+ when(backupOfferingDetailsDao.findDomainIds(1L)).thenReturn(Collections.emptyList()); // Global
+ when(backupOfferingDetailsDao.findDomainIds(2L)).thenReturn(List.of(userDomainId)); // User's domain
+ when(backupOfferingDetailsDao.findDomainIds(3L)).thenReturn(List.of(99L)); // Other domain
+
+ when(domainDao.isChildDomain(99L, userDomainId)).thenReturn(false);
+
+ Account account = Mockito.mock(Account.class);
+ when(account.getType()).thenReturn(Account.Type.NORMAL);
+ when(account.getDomainId()).thenReturn(userDomainId);
+
+ try (MockedStatic<CallContext> mockedCallContext = Mockito.mockStatic(CallContext.class)) {
+ CallContext contextMock = Mockito.mock(CallContext.class);
+ mockedCallContext.when(CallContext::current).thenReturn(contextMock);
+ when(contextMock.getCallingAccount()).thenReturn(account);
+
+ Pair<List<BackupOffering>, Integer> result = backupManager.listBackupOfferings(cmd);
+
+ assertEquals(2, result.first().size());
+ assertTrue(result.first().stream().anyMatch(o -> o.getName().equals("Global Offering")));
+ assertTrue(result.first().stream().anyMatch(o -> o.getName().equals("User Domain Offering")));
+ }
+ }
+
+ private BackupOfferingVO createMockOffering(Long id, String name) {
+ BackupOfferingVO offering = Mockito.mock(BackupOfferingVO.class);
+ when(offering.getId()).thenReturn(id);
+ when(offering.getName()).thenReturn(name);
+ return offering;
+ }
+
}
diff --git a/server/src/test/java/org/apache/cloudstack/network/RoutedIpv4ManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/network/RoutedIpv4ManagerImplTest.java
index 81110dd..737273e 100644
--- a/server/src/test/java/org/apache/cloudstack/network/RoutedIpv4ManagerImplTest.java
+++ b/server/src/test/java/org/apache/cloudstack/network/RoutedIpv4ManagerImplTest.java
@@ -340,7 +340,7 @@
when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
- when(accountManager.finalyzeAccountId(accountName, domainId, null, false)).thenReturn(accountId);
+ when(accountManager.finalizeAccountId(accountName, domainId, null, false)).thenReturn(accountId);
when(accountManager.getAccount(accountId)).thenReturn(account);
when(account.getDomainId()).thenReturn(domainId);
when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
@@ -911,7 +911,7 @@
ReflectionTestUtils.setField(cmd,"projectId", null);
when(bgpPeerDao.findById(bgpPeerId)).thenReturn(bgpPeer);
- when(accountManager.finalyzeAccountId(accountName, domainId, null, false)).thenReturn(accountId);
+ when(accountManager.finalizeAccountId(accountName, domainId, null, false)).thenReturn(accountId);
when(accountManager.getAccount(accountId)).thenReturn(account);
when(account.getDomainId()).thenReturn(domainId);
diff --git a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java
index eab5d3e..f175c56 100644
--- a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java
+++ b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java
@@ -27,6 +27,7 @@
import javax.inject.Inject;
+import com.cloud.utils.DomainHelper;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -99,6 +100,9 @@
LoadBalancerVMMapDao _loadBalancerVMMapDao;
@Mock
+ DomainHelper domainHelper;
+
+ @Mock
AnnotationDao annotationDao;
@Inject
VlanDetailsDao vlanDetailsDao;
@@ -225,7 +229,6 @@
NetworkOfferingVO off =
configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false,
Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null, false, null, null, false);
- // System.out.println("Creating Vpc Network Offering");
assertNotNull("Vpc Isolated network offering with Vpc provider ", off);
}
@@ -245,7 +248,6 @@
NetworkOfferingVO off =
configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false,
Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null, false, null, null, false);
- // System.out.println("Creating Vpc Network Offering");
assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off);
}
}
diff --git a/services/console-proxy/pom.xml b/services/console-proxy/pom.xml
index 43d32fd..31a5a13 100644
--- a/services/console-proxy/pom.xml
+++ b/services/console-proxy/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-services</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/services/console-proxy/rdpconsole/pom.xml b/services/console-proxy/rdpconsole/pom.xml
index 5416488..058ea89 100644
--- a/services/console-proxy/rdpconsole/pom.xml
+++ b/services/console-proxy/rdpconsole/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-console-proxy</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/services/console-proxy/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java b/services/console-proxy/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
index f3a73d70..b60dccf 100644
--- a/services/console-proxy/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
+++ b/services/console-proxy/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
@@ -70,7 +70,6 @@
default:
throw new RuntimeException("Order is not implemented: " + buf + ".");
- // break;
}
buf.unref();
@@ -93,8 +92,6 @@
Graphics2D g = (Graphics2D)image.getGraphics();
for (BitmapRectangle rectangle : order.rectangles) {
- // *DEBUG*/System.out.println("["+this+"] DEBUG: Rectangle: " +
- // rectangle.toString());
int x = rectangle.x;
int y = rectangle.y;
@@ -148,9 +145,6 @@
* Example.
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
- // System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
ByteBuffer packet = new ByteBuffer(new byte[] {0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x10, 0x00,
0x01, 0x04, 0x0a, 0x00, 0x0c, (byte)0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/RdpClient.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/RdpClient.java
index 3dd7cf9..767ca36 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/RdpClient.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/RdpClient.java
@@ -96,15 +96,6 @@
assembleRDPPipeline(serverHostName, domain, userName, password, pcb, screen, canvas, sslState);
}
- // /* DEBUG */
-// @Override
-// protected HashMap<String, streamer.Element> initElementMap(String id) {
-// HashMap<String, streamer.Element> map = new HashMap<String, streamer.Element>();
-// map.put("IN", new ServerPacketSniffer("server <"));
-// map.put("OUT", new ClientPacketSniffer("> client"));
-// return map;
-// }
-
/**
* Assemble connection sequence and main pipeline.
*
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/clip/ClipboardDataFormat.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/clip/ClipboardDataFormat.java
index 3a16536..29afc52 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/clip/ClipboardDataFormat.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/clip/ClipboardDataFormat.java
@@ -40,11 +40,6 @@
// Names
HTML_FORMAT,
-
- // RTF_AS_TEXT,
- // RICH_TEXT_FORMAT_WITHOUT_OBJECTS,
- // RICH_TEXT_FORMAT,
-
};
public final int id;
@@ -115,15 +110,6 @@
if (HTML_FORMAT.equals(name))
return buf.readVariableString(RdpConstants.CHARSET_8); // TODO: verify
- // if (RTF_AS_TEXT.equals(name))
- // return buf.readVariableString(RdpConstants.CHARSET_8); // TODO: verify
- //
- // if (RICH_TEXT_FORMAT_WITHOUT_OBJECTS.equals(name))
- // return buf.readVariableString(RdpConstants.CHARSET_8); // TODO: verify
- //
- // if (RICH_TEXT_FORMAT.equals(name))
- // return buf.readVariableString(RdpConstants.CHARSET_8); // TODO: verify
-
return null;
}
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/ntlmssp/asn1/TSRequest.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/ntlmssp/asn1/TSRequest.java
index c5ba5d6..11aee53 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/ntlmssp/asn1/TSRequest.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/ntlmssp/asn1/TSRequest.java
@@ -180,14 +180,8 @@
TSRequest request = new TSRequest("TSRequest");
// Read request from buffer
- // System.out.println("Request BER tree before parsing: " + request);
ByteBuffer toReadBuf = new ByteBuffer(packet);
request.readTag(toReadBuf);
- // System.out.println("Request BER tree after parsing: " + request);
-
- // System.out.println("version value: " + request.version.value);
- // System.out.println("negoToken value: " + ((NegoItem)
- // request.negoTokens.tags[0]).negoToken.value);
// Write request to buffer and compare with original
ByteBuffer toWriteBuf = new ByteBuffer(packet.length + 100, true);
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientConfirmActivePDU.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientConfirmActivePDU.java
index b77f201..bee26a6 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientConfirmActivePDU.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientConfirmActivePDU.java
@@ -27,7 +27,7 @@
import common.ScreenDescription;
/**
- * @see http://msdn.microsoft.com/en-us/library/cc240488.aspx
+ * @see <a href="http://msdn.microsoft.com/en-us/library/cc240488.aspx">microsoft msdn explanation</a>
*/
public class ClientConfirmActivePDU extends BaseElement {
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSAttachUserRequest.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSAttachUserRequest.java
index 47a07da..df57547 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSAttachUserRequest.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSAttachUserRequest.java
@@ -60,9 +60,7 @@
* Example.
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
/* @formatter:off */
byte[] packet = new byte[] {
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs.java
index 8213b74..92c7291 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs.java
@@ -57,7 +57,6 @@
// Parse channel confirm response
int typeAndFlags = buf.readUnsignedByte();
int type = typeAndFlags >> 2;
- // int flags = typeAndFlags & 0x3;
if (type != MCS_CHANNEL_CONFIRM_PDU)
throw new RuntimeException("[" + this + "] ERROR: Incorrect type of MCS AttachUserConfirm PDU. Expected value: 15, actual value: " + type + ", data: " + buf + ".");
@@ -74,11 +73,9 @@
// Channel Join Request PDU the connection SHOULD be dropped.
// Initiator: 1007 (6+1001)
- // int initiator=buf.readUnsignedShort();
buf.skipBytes(2);
// Requested channel
- // int requestedChannel=buf.readUnsignedShort();
buf.skipBytes(2);
// Actual channel
@@ -123,9 +120,7 @@
* @see http://msdn.microsoft.com/en-us/library/cc240834.aspx
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
/* @formatter:off */
byte[] clientRequestPacket = new byte[] {
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientSynchronizePDU.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientSynchronizePDU.java
index b7b52f0..5390fbf 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientSynchronizePDU.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ClientSynchronizePDU.java
@@ -105,9 +105,7 @@
* @see http://msdn.microsoft.com/en-us/library/cc240841.aspx
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
/* @formatter:off */
byte[] packet = new byte[] {
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerBitmapUpdate.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerBitmapUpdate.java
index 6accc16..39553c9 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerBitmapUpdate.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerBitmapUpdate.java
@@ -142,7 +142,6 @@
// flag is not.
// Note: Even when compression header is enabled, server sends nothing.
- // rectangle.compressedBitmapHeader = buf.readBytes(8);
}
// (variable): A variable-length array of bytes describing a bitmap image.
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerDemandActivePDU.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerDemandActivePDU.java
index d11a26b..9b95b0c 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerDemandActivePDU.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerDemandActivePDU.java
@@ -28,8 +28,8 @@
import common.ScreenDescription;
/**
- * @see http://msdn.microsoft.com/en-us/library/cc240669.aspx
- * @see http://msdn.microsoft.com/en-us/library/cc240484.aspx
+ * @see <a href="http://msdn.microsoft.com/en-us/library/cc240669.aspx">msdn cc240669</a>
+ * @see <a href="http://msdn.microsoft.com/en-us/library/cc240484.aspx">msdn cc240484</a>
*/
public class ServerDemandActivePDU extends BaseElement {
@@ -83,7 +83,6 @@
// (variable): A variable-length array of bytes containing a source
// descriptor,
- // ByteBuffer sourceDescriptor = buf.readBytes(lengthSourceDescriptor);
buf.skipBytes(lengthSourceDescriptor);
// (variable): An array of Capability Set (section 2.2.1.13.1.1.1)
@@ -216,7 +215,7 @@
public static final int CAPSSETTYPE_FRAME_ACKNOWLEDGE = 0x001E;
/**
- * @see http://msdn.microsoft.com/en-us/library/cc240486.aspx
+ * @see <a href="http://msdn.microsoft.com/en-us/library/cc240486.aspx">msdn cc240486</a>
*/
protected void handleCapabiltySets(ByteBuffer buf) {
// (2 bytes): A 16-bit, unsigned integer. The number of capability sets
@@ -312,7 +311,7 @@
}
/**
- * @see http://msdn.microsoft.com/en-us/library/cc240554.aspx
+ * @see <a href="http://msdn.microsoft.com/en-us/library/cc240554.aspx">msdn cc240554</a>
*/
protected void handleBitmapCapabilities(ByteBuffer buf) {
@@ -388,9 +387,7 @@
*
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
/* @formatter:off */
byte[] packet = new byte[] {
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerIOChannelRouter.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerIOChannelRouter.java
index 59613bb..20d5f00 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerIOChannelRouter.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerIOChannelRouter.java
@@ -73,7 +73,6 @@
{
// It is ServerErrorAlert-ValidClient
// Ignore it
- //throw new RuntimeException("[" + this + "] ERROR: Incorrect PDU length: " + length + ", data: " + buf + ".");
}
int type = buf.readUnsignedShortLE() & 0xf;
@@ -88,14 +87,12 @@
case PDUTYPE_CONFIRMACTIVEPDU:
throw new RuntimeException("Unexpected client CONFIRM ACTIVE PDU. Data: " + buf + ".");
case PDUTYPE_DEACTIVATEALLPDU:
- // pushDataToPad("deactivate_all", buf);
/* ignore */buf.unref();
break;
case PDUTYPE_DATAPDU:
handleDataPdu(buf);
break;
case PDUTYPE_SERVER_REDIR_PKT:
- // pushDataToPad("server_redir", buf);
/* ignore */buf.unref();
break;
default:
@@ -253,7 +250,6 @@
long shareId = buf.readUnsignedIntLE();
if (shareId != state.serverShareId)
throw new RuntimeException("Unexpected share ID: " + shareId + ".");
-// buf.skipBytes(4);
// Padding.
buf.skipBytes(1);
@@ -461,9 +457,7 @@
*
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
byte[] packet = new byte[] {
// TPKT
diff --git a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSPDU.java b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSPDU.java
index d28d0a0..71afe45 100644
--- a/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSPDU.java
+++ b/services/console-proxy/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSPDU.java
@@ -42,7 +42,6 @@
switch (type) {
// Expected type: send data indication: 26 (0x1a, top 6 bits, or 0x68)
case 0x1a: {
- // int userId = buf.readUnsignedShort() + 1001; // User ID: 1002 (1001+1)
buf.skipBytes(2); // Ignore user ID
int channelId = buf.readUnsignedShort(); // Channel ID: 1003
@@ -78,9 +77,6 @@
*
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
- // System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
byte[] packet = new byte[] {
// TPKT
diff --git a/services/console-proxy/rdpconsole/src/main/java/streamer/BaseElement.java b/services/console-proxy/rdpconsole/src/main/java/streamer/BaseElement.java
index 15e1a87..5f97da2 100644
--- a/services/console-proxy/rdpconsole/src/main/java/streamer/BaseElement.java
+++ b/services/console-proxy/rdpconsole/src/main/java/streamer/BaseElement.java
@@ -187,7 +187,6 @@
if (buf == null)
throw new NullPointerException();
- //return;
if (outputPads.size() == 0)
throw new RuntimeException("Number of outgoing connection is zero. Cannot send data to output. Data: " + buf + ".");
diff --git a/services/console-proxy/rdpconsole/src/main/java/streamer/PipelineImpl.java b/services/console-proxy/rdpconsole/src/main/java/streamer/PipelineImpl.java
index 84ed514..df2652e 100644
--- a/services/console-proxy/rdpconsole/src/main/java/streamer/PipelineImpl.java
+++ b/services/console-proxy/rdpconsole/src/main/java/streamer/PipelineImpl.java
@@ -307,9 +307,6 @@
* Example.
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
- // System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
Pipeline pipeline = new PipelineImpl("main");
diff --git a/services/console-proxy/rdpconsole/src/main/java/streamer/Queue.java b/services/console-proxy/rdpconsole/src/main/java/streamer/Queue.java
index ea64b32..be4ed29 100644
--- a/services/console-proxy/rdpconsole/src/main/java/streamer/Queue.java
+++ b/services/console-proxy/rdpconsole/src/main/java/streamer/Queue.java
@@ -101,7 +101,6 @@
* Example.
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
Element source1 = new FakeSource("source1") {
diff --git a/services/console-proxy/rdpconsole/src/main/java/streamer/debug/MockSource.java b/services/console-proxy/rdpconsole/src/main/java/streamer/debug/MockSource.java
index a77f1d4..31ef816 100644
--- a/services/console-proxy/rdpconsole/src/main/java/streamer/debug/MockSource.java
+++ b/services/console-proxy/rdpconsole/src/main/java/streamer/debug/MockSource.java
@@ -75,7 +75,6 @@
new ByteBuffer(new byte[] {3, 1, 2, 3}), new ByteBuffer(new byte[] {4, 1, 2}), new ByteBuffer(new byte[] {5, 1})};
verbose = true;
delay = 100;
- // this.numBuffers = this.bufs.length;
}
};
diff --git a/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/Vnc33Authentication.java b/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/Vnc33Authentication.java
index 4aa834d..8d0f917 100644
--- a/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/Vnc33Authentication.java
+++ b/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/Vnc33Authentication.java
@@ -256,9 +256,7 @@
* Example.
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
final String password = "test";
diff --git a/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/Vnc33Hello.java b/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/Vnc33Hello.java
index 812c6a8..d677aba 100644
--- a/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/Vnc33Hello.java
+++ b/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/Vnc33Hello.java
@@ -82,9 +82,7 @@
* Example.
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
InputStream is = new ByteArrayInputStream("RFB 003.007\ntest".getBytes(RfbConstants.US_ASCII_CHARSET));
ByteArrayOutputStream initOS = new ByteArrayOutputStream();
diff --git a/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/VncInitializer.java b/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/VncInitializer.java
index 0b96c73..4f4d96d 100644
--- a/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/VncInitializer.java
+++ b/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/VncInitializer.java
@@ -158,9 +158,7 @@
* Example.
*/
public static void main(String args[]) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
final String desktopName = "test";
diff --git a/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/VncMessageHandler.java b/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/VncMessageHandler.java
index 5914cb3..e9b8933 100644
--- a/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/VncMessageHandler.java
+++ b/services/console-proxy/rdpconsole/src/main/java/vncclient/vnc/VncMessageHandler.java
@@ -330,9 +330,7 @@
*/
public static void main(String[] args) {
- // System.setProperty("streamer.Link.debug", "true");
System.setProperty("streamer.Element.debug", "true");
- // System.setProperty("streamer.Pipeline.debug", "true");
Element source = new MockSource("source") {
{
diff --git a/services/console-proxy/server/pom.xml b/services/console-proxy/server/pom.xml
index cff9ae3..3f5b9db 100644
--- a/services/console-proxy/server/pom.xml
+++ b/services/console-proxy/server/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-console-proxy</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxy.java b/services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxy.java
index a25abac..e75ccea 100644
--- a/services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxy.java
+++ b/services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxy.java
@@ -113,7 +113,6 @@
} catch (URISyntaxException e) {
System.out.println("Unable to convert log4j configuration Url to URI");
}
- // DOMConfigurator.configure(configUrl);
} else {
System.out.println("Configure log4j with default properties");
}
diff --git a/services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java b/services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java
index e2ec7df..703fed7 100644
--- a/services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java
+++ b/services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java
@@ -197,7 +197,7 @@
startx = 0;
g.drawString(text, startx, h / 2);
} catch (Throwable e) {
- logger.warn("Problem in generating text to thumnail image, return blank image");
+ logger.warn("Problem in generating text to thumbnail image, return blank image");
}
return img;
}
diff --git a/services/pom.xml b/services/pom.xml
index 2205e46..b6a456b 100644
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/services/secondary-storage/controller/pom.xml b/services/secondary-storage/controller/pom.xml
index e3847e2..d8934bb 100644
--- a/services/secondary-storage/controller/pom.xml
+++ b/services/secondary-storage/controller/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-secondary-storage</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
index e26091f..9d4c731 100644
--- a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
+++ b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
@@ -1252,7 +1252,7 @@
logger.debug(String.format("Boot args for machine profile [%s]: [%s].", profile.toString(), bootArgs));
}
- boolean useHttpsToUpload = BooleanUtils.toBooleanDefaultIfNull(VolumeApiService.UseHttpsToUpload.value(), true);
+ boolean useHttpsToUpload = VolumeApiService.UseHttpsToUpload.valueIn(dc.getId());
logger.debug(String.format("Setting UseHttpsToUpload config on cmdline with [%s] value.", useHttpsToUpload));
buf.append(" useHttpsToUpload=").append(useHttpsToUpload);
diff --git a/services/secondary-storage/pom.xml b/services/secondary-storage/pom.xml
index c1d3f90..0cc0115 100644
--- a/services/secondary-storage/pom.xml
+++ b/services/secondary-storage/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-services</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/services/secondary-storage/server/pom.xml b/services/secondary-storage/server/pom.xml
index ca878ce..e6aec8a 100644
--- a/services/secondary-storage/server/pom.xml
+++ b/services/secondary-storage/server/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-secondary-storage</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
index 7861227..8dd2fa2 100644
--- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
+++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
@@ -2225,8 +2225,6 @@
Map<String, TemplateProp> tmpltInfos = new HashMap<String, TemplateProp>();
for (S3ObjectSummary objectSummary : objectSummaries) {
String key = objectSummary.getKey();
- // String installPath = StringUtils.substringBeforeLast(key,
- // S3Utils.SEPARATOR);
String uniqueName = determineS3TemplateNameFromKey(key);
// TODO: isPublic value, where to get?
TemplateProp tInfo = new TemplateProp(uniqueName, key, objectSummary.getSize(), objectSummary.getSize(), true, false);
@@ -2246,8 +2244,6 @@
Map<Long, TemplateProp> tmpltInfos = new HashMap<Long, TemplateProp>();
for (S3ObjectSummary objectSummary : objectSummaries) {
String key = objectSummary.getKey();
- // String installPath = StringUtils.substringBeforeLast(key,
- // S3Utils.SEPARATOR);
Long id = determineS3VolumeIdFromKey(key);
// TODO: how to get volume template name
TemplateProp tInfo = new TemplateProp(id.toString(), key, objectSummary.getSize(), objectSummary.getSize(), true, false);
diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
index 6791a93..23ad676 100644
--- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
+++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
@@ -1058,7 +1058,6 @@
try {
if (!loc.load()) {
logger.warn("Post download installation was not completed for " + path);
- // loc.purge();
_storage.cleanup(path, templateDir);
continue;
}
@@ -1104,7 +1103,6 @@
try {
if (!loc.load()) {
logger.warn("Post download installation was not completed for " + path);
- // loc.purge();
_storage.cleanup(path, volumeDir);
continue;
}
diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java
index ae02d7e..abddc3a 100644
--- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java
+++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java
@@ -415,7 +415,6 @@
if (inSystemVM != null && "true".equalsIgnoreCase(inSystemVM)) {
logger.info("UploadManager: starting additional services since we are inside system vm");
startAdditionalServices();
- //blockOutgoingOnPrivate();
}
value = (String)params.get("install.numthreads");
diff --git a/services/secondary-storage/server/src/test/java/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResourceTest.java b/services/secondary-storage/server/src/test/java/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResourceTest.java
index 3d62bc1..e79d013 100644
--- a/services/secondary-storage/server/src/test/java/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResourceTest.java
+++ b/services/secondary-storage/server/src/test/java/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResourceTest.java
@@ -71,7 +71,6 @@
}
System.setProperty("paths.script", "/Users/edison/develop/asf-master/script");
- //resource.configure("test", new HashMap<String, Object>());
}
@Test
diff --git a/setup/dev/s3.cfg b/setup/dev/s3.cfg
index de28e5b..ce414f5 100644
--- a/setup/dev/s3.cfg
+++ b/setup/dev/s3.cfg
@@ -1,20 +1,19 @@
-# 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
+# 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
+# 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.
-#
+# 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.
# TODO: Change ACCESS_KEY/ SECRET_KEY to your credentials on the object store
diff --git a/systemvm/agent/conf/environment.properties b/systemvm/agent/conf/environment.properties
index 269acad..20ca1a2 100644
--- a/systemvm/agent/conf/environment.properties
+++ b/systemvm/agent/conf/environment.properties
@@ -1,2 +1,19 @@
+# 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.
+
paths.script=../../scripts/storage/secondary/
paths.pid=.
diff --git a/systemvm/agent/scripts/run-proxy.sh b/systemvm/agent/scripts/run-proxy.sh
index f26f54b..40e7c8f 100755
--- a/systemvm/agent/scripts/run-proxy.sh
+++ b/systemvm/agent/scripts/run-proxy.sh
@@ -33,16 +33,4 @@
CP=${CP}:$file
done
-#CMDLINE=$(cat /proc/cmdline)
-#for i in $CMDLINE
-# do
-# KEY=$(echo $i | cut -d= -f1)
-# VALUE=$(echo $i | cut -d= -f2)
-# case $KEY in
-# mgmt_host)
-# MGMT_HOST=$VALUE
-# ;;
-# esac
-# done
-
java -mx700m -cp $CP:./conf com.cloud.consoleproxy.ConsoleProxy $@
diff --git a/systemvm/agent/scripts/ssvm-check.sh b/systemvm/agent/scripts/ssvm-check.sh
index f5d69cb..86cecb7 100755
--- a/systemvm/agent/scripts/ssvm-check.sh
+++ b/systemvm/agent/scripts/ssvm-check.sh
@@ -41,7 +41,7 @@
# ping dns server
echo ================================================
-DNSSERVER=`egrep '^nameserver' /etc/resolv.conf | awk '{print $2}'| head -1`
+DNSSERVER=`grep -E '^nameserver' /etc/resolv.conf | awk '{print $2}'| head -1`
echo "First DNS server is " $DNSSERVER
ping -c 2 $DNSSERVER
if [ $? -eq 0 ]
diff --git a/systemvm/debian/etc/haproxy/haproxy.cfg b/systemvm/debian/etc/haproxy/haproxy.cfg
index 21964f2..68a4cd7 100644
--- a/systemvm/debian/etc/haproxy/haproxy.cfg
+++ b/systemvm/debian/etc/haproxy/haproxy.cfg
@@ -1,3 +1,20 @@
+# 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.
+
global
log 127.0.0.1:3914 local0 info
chroot /var/lib/haproxy
diff --git a/systemvm/debian/opt/cloud/bin/baremetal_snat.sh b/systemvm/debian/opt/cloud/bin/baremetal_snat.sh
index 2092ded..5952eec 100755
--- a/systemvm/debian/opt/cloud/bin/baremetal_snat.sh
+++ b/systemvm/debian/opt/cloud/bin/baremetal_snat.sh
@@ -1,21 +1,21 @@
#!/bin/bash
-#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
+# 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
+# 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.
+# 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.
set +u
diff --git a/systemvm/debian/opt/cloud/bin/dnsmasq.sh b/systemvm/debian/opt/cloud/bin/dnsmasq.sh
index d675e08..8cba9c5 100755
--- a/systemvm/debian/opt/cloud/bin/dnsmasq.sh
+++ b/systemvm/debian/opt/cloud/bin/dnsmasq.sh
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
+
# 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
@@ -10,6 +11,7 @@
# 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
diff --git a/systemvm/debian/opt/cloud/bin/loadbalancer.sh b/systemvm/debian/opt/cloud/bin/loadbalancer.sh
index 6a2dc6c..c527f0b 100755
--- a/systemvm/debian/opt/cloud/bin/loadbalancer.sh
+++ b/systemvm/debian/opt/cloud/bin/loadbalancer.sh
@@ -144,7 +144,7 @@
local lb_vif_list=$(get_lb_vif_list)
for vif in $lb_vif_list; do
-#TODO : The below delete will be used only when we upgrade the from older version to the newer one , the below delete become obsolute in the future.
+#TODO : The below delete will be used only when we upgrade the from older version to the newer one, the below delete become obsolete in the future.
sudo iptables -D INPUT -i $vif -p tcp -d $pubIp --dport $dport -j ACCEPT 2> /dev/null
sudo iptables -A load_balancer_$vif -p tcp -d $pubIp --dport $dport -j ACCEPT
@@ -161,7 +161,7 @@
sudo iptables -A lb_stats -s $cidrs -p tcp -m state --state NEW -d $pubIp --dport $dport -j ACCEPT
-#TODO : The below delete in the for-loop will be used only when we upgrade the from older version to the newer one , the below delete become obsolute in the future.
+#TODO : The below delete in the for-loop will be used only when we upgrade the from older version to the newer one, the below delete become obsolete in the future.
for i in $r
do
local pubIp=$(echo $i | cut -d: -f1)
diff --git a/systemvm/debian/opt/cloud/bin/prepare_pxe.sh b/systemvm/debian/opt/cloud/bin/prepare_pxe.sh
index 9c4c18e..6da309b 100755
--- a/systemvm/debian/opt/cloud/bin/prepare_pxe.sh
+++ b/systemvm/debian/opt/cloud/bin/prepare_pxe.sh
@@ -1,9 +1,9 @@
#!/bin/sh
-#
+
# 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
+# 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
@@ -16,7 +16,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
set +u
diff --git a/systemvm/debian/opt/cloud/bin/update_interface_config.sh b/systemvm/debian/opt/cloud/bin/update_interface_config.sh
index 53d81f7..427d5d9 100755
--- a/systemvm/debian/opt/cloud/bin/update_interface_config.sh
+++ b/systemvm/debian/opt/cloud/bin/update_interface_config.sh
@@ -31,7 +31,7 @@
for i in `seq 1 $(($timeout))`
do
#inf=$(ip route list ${1}/${2} | awk '{print $3}')
- inf=$(ip addr show|egrep '^ *inet'|grep ${1}/${2} |grep brd|awk -- '{ print $NF; }')
+ inf=$(ip addr show|grep -E '^ *inet'|grep ${1}/${2} |grep brd|awk -- '{ print $NF; }')
if [ ! -z $inf ]; then
echo $inf
break
diff --git a/systemvm/pom.xml b/systemvm/pom.xml
index e2a0315..9bffc45 100644
--- a/systemvm/pom.xml
+++ b/systemvm/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
diff --git a/test/integration/component/test_base_image_updation.py b/test/integration/component/test_base_image_updation.py
index 2a0a4e6..9398f88 100644
--- a/test/integration/component/test_base_image_updation.py
+++ b/test/integration/component/test_base_image_updation.py
@@ -575,7 +575,7 @@
)
sleep_seconds = (self.services["recurring_snapshot"]["schedule"]) * 3600 + 600
sleep_minutes = sleep_seconds/60
- self.debug("Sleeping for %s minutes till the volume is snapshoted" %sleep_minutes)
+ self.debug("Sleeping for %s minutes till the volume is snapshotted" %sleep_minutes)
time.sleep(sleep_seconds)
retriesCount = self.services["retriesCount"]
diff --git a/test/integration/component/test_egress_rules.py b/test/integration/component/test_egress_rules.py
index 32f1dca..014303f 100644
--- a/test/integration/component/test_egress_rules.py
+++ b/test/integration/component/test_egress_rules.py
@@ -1165,8 +1165,8 @@
return
@attr(tags = ["sg", "eip", "advancedsg"])
- def test_invalid_account_authroize(self):
- """Test invalid account authroize
+ def test_invalid_account_authorize(self):
+ """Test invalid account authorize
"""
diff --git a/test/integration/component/test_escalations_ipaddresses.py b/test/integration/component/test_escalations_ipaddresses.py
index fbcff2a..b91b67c 100644
--- a/test/integration/component/test_escalations_ipaddresses.py
+++ b/test/integration/component/test_escalations_ipaddresses.py
@@ -4341,7 +4341,7 @@
vmgroup_disabled,
"Failed to disable Autoscale VM group"
)
- # Verifyign the state of the VM Group afte renabling
+ # Verifying the state of the VM Group after renabling
self.assertEqual(
"disabled",
vmgroup_disabled.state,
@@ -4375,7 +4375,7 @@
vmgroup_enabled,
"Failed to enable Autoscale VM group"
)
- # Verifyign the state of the VM Group afte renabling
+ # Verifying the state of the VM Group after renabling
self.assertEqual(
"enabled",
vmgroup_enabled.state,
diff --git a/test/integration/component/test_multiple_subnets_in_isolated_network.py b/test/integration/component/test_multiple_subnets_in_isolated_network.py
index 278728b..f5efd9a 100644
--- a/test/integration/component/test_multiple_subnets_in_isolated_network.py
+++ b/test/integration/component/test_multiple_subnets_in_isolated_network.py
@@ -210,9 +210,9 @@
self.logger.debug("Skip as redundant_state is %s" % redundant_state)
return
elif redundant_state == "PRIMARY":
- command = 'ip link show |grep BROADCAST | egrep "%s" |grep "state DOWN" |wc -l' % publicNics
+ command = 'ip link show |grep BROADCAST | grep -E "%s" |grep "state DOWN" |wc -l' % publicNics
elif redundant_state == "BACKUP":
- command = 'ip link show |grep BROADCAST | egrep "%s" |grep "state UP" |wc -l' % publicNics
+ command = 'ip link show |grep BROADCAST | grep -E "%s" |grep "state UP" |wc -l' % publicNics
result = get_process_status(
host.ipaddress,
host.port,
diff --git a/test/integration/component/test_multiple_subnets_in_isolated_network_rvr.py b/test/integration/component/test_multiple_subnets_in_isolated_network_rvr.py
index d83571f..b6c6434 100644
--- a/test/integration/component/test_multiple_subnets_in_isolated_network_rvr.py
+++ b/test/integration/component/test_multiple_subnets_in_isolated_network_rvr.py
@@ -210,9 +210,9 @@
self.logger.debug("Skip as redundant_state is %s" % redundant_state)
return
elif redundant_state == "PRIMARY":
- command = 'ip link show |grep BROADCAST | egrep "%s" |grep "state DOWN" |wc -l' % publicNics
+ command = 'ip link show |grep BROADCAST | grep -E "%s" |grep "state DOWN" |wc -l' % publicNics
elif redundant_state == "BACKUP":
- command = 'ip link show |grep BROADCAST | egrep "%s" |grep "state UP" |wc -l' % publicNics
+ command = 'ip link show |grep BROADCAST | grep -E "%s" |grep "state UP" |wc -l' % publicNics
result = get_process_status(
host.ipaddress,
host.port,
diff --git a/test/integration/component/test_multiple_subnets_in_vpc.py b/test/integration/component/test_multiple_subnets_in_vpc.py
index 9167f15..0206659 100644
--- a/test/integration/component/test_multiple_subnets_in_vpc.py
+++ b/test/integration/component/test_multiple_subnets_in_vpc.py
@@ -214,9 +214,9 @@
self.logger.debug("Skip as redundant_state is %s" % redundant_state)
return
elif redundant_state == "PRIMARY":
- command = 'ip link show |grep BROADCAST | egrep "%s" |grep "state DOWN" |wc -l' % publicNics
+ command = 'ip link show |grep BROADCAST | grep -E "%s" |grep "state DOWN" |wc -l' % publicNics
elif redundant_state == "BACKUP":
- command = 'ip link show |grep BROADCAST | egrep "%s" |grep "state UP" |wc -l' % publicNics
+ command = 'ip link show |grep BROADCAST | grep -E "%s" |grep "state UP" |wc -l' % publicNics
result = get_process_status(
host.ipaddress,
host.port,
diff --git a/test/integration/component/test_multiple_subnets_in_vpc_rvr.py b/test/integration/component/test_multiple_subnets_in_vpc_rvr.py
index 7c71273..e8963f1 100644
--- a/test/integration/component/test_multiple_subnets_in_vpc_rvr.py
+++ b/test/integration/component/test_multiple_subnets_in_vpc_rvr.py
@@ -214,9 +214,9 @@
self.logger.debug("Skip as redundant_state is %s" % redundant_state)
return
elif redundant_state == "PRIMARY":
- command = 'ip link show |grep BROADCAST | egrep "%s" |grep "state DOWN" |wc -l' % publicNics
+ command = 'ip link show |grep BROADCAST | grep -E "%s" |grep "state DOWN" |wc -l' % publicNics
elif redundant_state == "BACKUP":
- command = 'ip link show |grep BROADCAST | egrep "%s" |grep "state UP" |wc -l' % publicNics
+ command = 'ip link show |grep BROADCAST | grep -E "%s" |grep "state UP" |wc -l' % publicNics
result = get_process_status(
host.ipaddress,
host.port,
diff --git a/test/integration/component/test_netscaler_nw_off.py b/test/integration/component/test_netscaler_nw_off.py
index d9f6c97..627c4a0 100644
--- a/test/integration/component/test_netscaler_nw_off.py
+++ b/test/integration/component/test_netscaler_nw_off.py
@@ -802,7 +802,7 @@
# Validate the following
# 1. Add another netscaler device and spawn a new VM again
- # 2. VM deployement should be successful
+ # 2. VM deployment should be successful
self.debug("Adding another netscaler device: %s" %
self.services["netscaler_2"]["ipaddress"])
@@ -1672,7 +1672,7 @@
# LB rules
# 5. Deploy instance with dedicated network offering in account 3.
# Create Lb rules.
- # 6. Configure another instace of netscaler in dedicated mode
+ # 6. Configure another instance of netscaler in dedicated mode
# 7. upgrade networkj for user 1 to dedicated network offering.
# Create LB rules. LB rule creation should be successful
@@ -2063,7 +2063,7 @@
# LB rules
# 5. Deploy instance with dedicated network offering in account 3.
# Create Lb rules.
- # 6. Configure another instace of netscaler in dedicated mode
+ # 6. Configure another instance of netscaler in dedicated mode
# 7. upgrade networkj for user 1 to dedicated network offering.
# Create LB rules. LB rule creation should be successful
diff --git a/test/integration/component/test_stopped_vm.py b/test/integration/component/test_stopped_vm.py
index b7fe4b0..4e6fa1e 100644
--- a/test/integration/component/test_stopped_vm.py
+++ b/test/integration/component/test_stopped_vm.py
@@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
-""" P1 for stopped Virtual Maschine life cycle
+""" P1 for stopped Virtual Machine life cycle
"""
# Import Local Modules
from nose.plugins.attrib import attr
diff --git a/test/integration/component/test_vpc_vm_life_cycle.py b/test/integration/component/test_vpc_vm_life_cycle.py
index abe6d19..d487a7f 100644
--- a/test/integration/component/test_vpc_vm_life_cycle.py
+++ b/test/integration/component/test_vpc_vm_life_cycle.py
@@ -1274,7 +1274,7 @@
except Exception as e:
self.fail("Failed to deploy the virtual instance: %s" % e)
- self.debug("Verify the deployment of virtual instace")
+ self.debug("Verify the deployment of virtual instance")
vms = VirtualMachine.list(
self.apiclient,
id=vm.id,
diff --git a/test/integration/plugins/storpool/MigrateVolumeToStorPool.py b/test/integration/plugins/storpool/MigrateVolumeToStorPool.py
index 4fc94d2..8581790 100644
--- a/test/integration/plugins/storpool/MigrateVolumeToStorPool.py
+++ b/test/integration/plugins/storpool/MigrateVolumeToStorPool.py
@@ -440,5 +440,5 @@
self.assertEqual(
self.random_data_0,
result[0],
- "Check the random data is equal with the ramdom file!"
+ "Check the random data is equal with the random file!"
)
diff --git a/test/integration/plugins/storpool/TestEncryptedVolumes.py b/test/integration/plugins/storpool/TestEncryptedVolumes.py
index ac049fb..e77cd0b 100644
--- a/test/integration/plugins/storpool/TestEncryptedVolumes.py
+++ b/test/integration/plugins/storpool/TestEncryptedVolumes.py
@@ -472,7 +472,7 @@
self.assertEqual(
self.random_data_0,
result[0],
- "Check the random data is equal with the ramdom file!"
+ "Check the random data is equal with the random file!"
)
# Delete VM snapshot
diff --git a/test/integration/plugins/storpool/TestStorPoolVolumes.py b/test/integration/plugins/storpool/TestStorPoolVolumes.py
index 150fe83..a6b8121 100644
--- a/test/integration/plugins/storpool/TestStorPoolVolumes.py
+++ b/test/integration/plugins/storpool/TestStorPoolVolumes.py
@@ -1136,7 +1136,7 @@
self.assertEqual(
self.random_data_0,
result[0],
- "Check the random data is equal with the ramdom file!"
+ "Check the random data is equal with the random file!"
)
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="true")
diff --git a/test/integration/plugins/storpool/TestTagsOnStorPool.py b/test/integration/plugins/storpool/TestTagsOnStorPool.py
index b813cd3..33ad41a 100644
--- a/test/integration/plugins/storpool/TestTagsOnStorPool.py
+++ b/test/integration/plugins/storpool/TestTagsOnStorPool.py
@@ -465,7 +465,7 @@
self.assertEqual(
self.random_data_0,
result[0],
- "Check the random data is equal with the ramdom file!"
+ "Check the random data is equal with the random file!"
)
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="true")
diff --git a/test/integration/plugins/storpool/TestVmSnapshots.py b/test/integration/plugins/storpool/TestVmSnapshots.py
index 749e534..b0f8192 100644
--- a/test/integration/plugins/storpool/TestVmSnapshots.py
+++ b/test/integration/plugins/storpool/TestVmSnapshots.py
@@ -336,7 +336,7 @@
self.assertEqual(
self.random_data_0,
result[0],
- "Check the random data is equal with the ramdom file!"
+ "Check the random data is equal with the random file!"
)
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="true")
diff --git a/test/integration/smoke/test_human_readable_logs.py b/test/integration/smoke/test_human_readable_logs.py
index fb97251..c2478bf 100644
--- a/test/integration/smoke/test_human_readable_logs.py
+++ b/test/integration/smoke/test_human_readable_logs.py
@@ -48,9 +48,9 @@
sshClient.execute(command)
# CapacityChecker runs as soon as management server is up
- # Check if "usedMem: (" is printed out within 60 seconds while server is starting
- command = "timeout 60 tail -f /var/log/cloudstack/management/management-server.log | grep 'usedMem: ('"
- sshClient.timeout = 60
+ # Check if "usedMem: (" is printed out within 120 seconds while server is starting
+ command = "timeout 120 tail -f /var/log/cloudstack/management/management-server.log | grep 'usedMem: ('"
+ sshClient.timeout = 120
result = sshClient.runCommand(command)
self.assertTrue(result['status'] == "FAILED")
@@ -70,7 +70,7 @@
sshClient.execute(command)
# CapacityChecker runs as soon as management server is up
- # Check if "usedMem: (" is printed out within 60 seconds while server is restarting
+ # Check if "usedMem: (" is printed out within 120 seconds while server is restarting
command = "timeout 120 tail -f /var/log/cloudstack/management/management-server.log | grep 'usedMem: ('"
sshClient.timeout = 120
result = sshClient.runCommand(command)
diff --git a/test/integration/smoke/test_network_traffic_type_api.py b/test/integration/smoke/test_network_traffic_type_api.py
new file mode 100644
index 0000000..10e9df4
--- /dev/null
+++ b/test/integration/smoke/test_network_traffic_type_api.py
@@ -0,0 +1,73 @@
+# 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.
+
+# Import Local Modules
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.base import (
+ TrafficType,
+ PhysicalNetwork,
+ Zone,
+)
+from nose.plugins.attrib import attr
+
+
+class TestTrafficTypeApi(cloudstackTestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.test_client = super(TestTrafficTypeApi, cls).getClsTestClient()
+ cls.api_client = cls.testClient.getApiClient()
+ cls.services = cls.testClient.getParsedTestDataConfig()
+ cls._cleanup = []
+ cls.services["advanced_sg"]["zone"]["name"] = "TestTrafficTypeApi-zone"
+ cls.zone = Zone.create(cls.api_client, cls.services["advanced_sg"]["zone"])
+ cls._cleanup.append(cls.zone)
+
+ cls.physical_network = PhysicalNetwork.create(
+ cls.api_client,
+ cls.services["l2-network"],
+ isolationmethods="VLAN",
+ zoneid=cls.zone.id,
+ )
+ cls._cleanup.append(cls.physical_network)
+
+ @classmethod
+ def tearDownClass(cls):
+ super(TestTrafficTypeApi, cls).tearDownClass()
+
+
+ @attr(tags=["advanced"], required_hardware="false")
+ def test_list_api_fields(self):
+ traffic_type = TrafficType.add(
+ self.api_client,
+ physicalnetworkid=self.physical_network.id,
+ kvmnetworklabel="kvm",
+ traffictype="Public",
+ vlan="100",
+ ).traffictype
+
+ traffic_types = TrafficType.list(
+ self.api_client,
+ physicalnetworkid=self.physical_network.id
+ )
+
+ assert len(traffic_types) == 1
+ response = traffic_types[0]
+ self.assertEqual(response.id, traffic_type.id)
+ self.assertEqual(response.kvmnetworklabel, "kvm")
+ self.assertEqual(response.traffictype, "Public")
+ self.assertEqual(response.vlan, "100")
+ self.assertEqual(response.isolationmethods, "VLAN")
diff --git a/test/integration/smoke/test_vm_snapshots.py b/test/integration/smoke/test_vm_snapshots.py
index 8c106f0..c64de12 100644
--- a/test/integration/smoke/test_vm_snapshots.py
+++ b/test/integration/smoke/test_vm_snapshots.py
@@ -262,7 +262,7 @@
self.assertEqual(
self.random_data_0,
result[0],
- "Check the random data is equal with the ramdom file!"
+ "Check the random data is equal with the random file!"
)
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="true")
diff --git a/test/integration/smoke/test_volumes.py b/test/integration/smoke/test_volumes.py
index 6cf3f08..ad1c359 100644
--- a/test/integration/smoke/test_volumes.py
+++ b/test/integration/smoke/test_volumes.py
@@ -988,7 +988,7 @@
return True, list_volume_response[0]
return False, None
- # sleep interval is 1s, retries is 360, this will sleep atmost 360 seconds, or 6 mins
+ # sleep interval is 1s, retries is 360, this will sleep at most 360 seconds, or 6 mins
res, response = wait_until(1, 360, checkVolumeResponse)
if not res:
self.fail("Failed to return root volume response")
diff --git a/test/integration/smoke/test_webhook_lifecycle.py b/test/integration/smoke/test_webhook_lifecycle.py
index 2d1f322..55947d7 100644
--- a/test/integration/smoke/test_webhook_lifecycle.py
+++ b/test/integration/smoke/test_webhook_lifecycle.py
@@ -283,7 +283,7 @@
description=description,
secretkey=secretkey,
state=state
- )['webhook']
+ )
self.assertNotEqual(
updated_webhook,
None,
diff --git a/test/integration/testpaths/testpath_storage_migration.py b/test/integration/testpaths/testpath_storage_migration.py
index 5b821bc..c63cdfc 100644
--- a/test/integration/testpaths/testpath_storage_migration.py
+++ b/test/integration/testpaths/testpath_storage_migration.py
@@ -2809,7 +2809,7 @@
disk=root_volume_cluster,
disk_type="rootdiskdevice")
- # Get Destnation Pool
+ # Get Destination Pool
# Avoid storage Pool on which ROOT disk exists
storagePools_to_avoid = [root_volume_cluster.storage]
@@ -2840,7 +2840,7 @@
disk=data_volume_1_cluster,
disk_type="datadiskdevice_1")
- # Get Destnation Pool
+ # Get Destination Pool
# Avoid storage Pool allocated for ROOT disk, and Pool on which DATA
# disk1 exists
storagePools_to_avoid = [
@@ -3021,7 +3021,7 @@
disk=root_volume_cluster,
disk_type="rootdiskdevice")
- # Get Destnation Pool
+ # Get Destination Pool
# Avoid storage Pool on which ROOT disk exists
storagePools_to_avoid = [root_volume_cluster.storage]
@@ -3052,7 +3052,7 @@
disk=data_volume_1_cluster,
disk_type="datadiskdevice_1")
- # Get Destnation Pool
+ # Get Destination Pool
# Avoid storage Pool allocated for ROOT disk, and Pool on which DATA
# disk1 exists
diff --git a/test/pom.xml b/test/pom.xml
index dd1bdf4..7f315bb 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/test/scripts/deploycluster.sh b/test/scripts/deploycluster.sh
index dbd2c7b..f012efc 100755
--- a/test/scripts/deploycluster.sh
+++ b/test/scripts/deploycluster.sh
@@ -60,7 +60,7 @@
if [ $? -gt 0 ]; then echo "failed to setup db.properties file on remote $1"; return 2; fi
#ssh root@$1 "cd /root/cloudstack-oss && nohup ant run &"
- #if [ $? -gt 0 ]; then echo "failed to start the softare on remote $1"; return 2; fi
+ #if [ $? -gt 0 ]; then echo "failed to start the software on remote $1"; return 2; fi
echo "Remote management server is deployed as a part of cluster setup; you have to start it manually by logging in remotely"
}
diff --git a/tools/apidoc/pom.xml b/tools/apidoc/pom.xml
index e9b81ee..b0e081d 100644
--- a/tools/apidoc/pom.xml
+++ b/tools/apidoc/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-tools</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
diff --git a/tools/checkstyle/pom.xml b/tools/checkstyle/pom.xml
index 0fb0efa..63f840d 100644
--- a/tools/checkstyle/pom.xml
+++ b/tools/checkstyle/pom.xml
@@ -22,7 +22,7 @@
<name>Apache CloudStack Developer Tools - Checkstyle Configuration</name>
<groupId>org.apache.cloudstack</groupId>
<artifactId>checkstyle</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/tools/devcloud-kvm/devcloud-kvm-advanced-fusion.cfg b/tools/devcloud-kvm/devcloud-kvm-advanced-fusion.cfg
index b1a3418..ce3ec91 100644
--- a/tools/devcloud-kvm/devcloud-kvm-advanced-fusion.cfg
+++ b/tools/devcloud-kvm/devcloud-kvm-advanced-fusion.cfg
@@ -1,21 +1,19 @@
-# 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
+# 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
+# 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.
-#
-
+# 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.
{
"zones": [
diff --git a/tools/devcloud-kvm/devcloud-kvm-advanced.cfg b/tools/devcloud-kvm/devcloud-kvm-advanced.cfg
index a3a41da..60ad8b5 100644
--- a/tools/devcloud-kvm/devcloud-kvm-advanced.cfg
+++ b/tools/devcloud-kvm/devcloud-kvm-advanced.cfg
@@ -1,21 +1,19 @@
-# 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
+# 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
+# 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.
-#
-
+# 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.
{
"zones": [
diff --git a/tools/devcloud-kvm/devcloud-kvm.cfg b/tools/devcloud-kvm/devcloud-kvm.cfg
index ffd2350..5ac417a 100644
--- a/tools/devcloud-kvm/devcloud-kvm.cfg
+++ b/tools/devcloud-kvm/devcloud-kvm.cfg
@@ -1,20 +1,20 @@
-# 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
+# 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
+# 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.
-#
+# 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.
+
# This is a stock devcloud config converted from the file
# tools/devcloud/devcloud.cfg.
diff --git a/tools/devcloud-kvm/pom.xml b/tools/devcloud-kvm/pom.xml
index 4990f0a..35cf828 100644
--- a/tools/devcloud-kvm/pom.xml
+++ b/tools/devcloud-kvm/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-tools</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -56,7 +56,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
- <version>1.0-alpha-2</version>
+ <version>1.2.1</version>
<executions>
<execution>
<phase>initialize</phase>
diff --git a/tools/devcloud4/advanced/marvin.cfg b/tools/devcloud4/advanced/marvin.cfg
index 222dc65..7b6e656 100644
--- a/tools/devcloud4/advanced/marvin.cfg
+++ b/tools/devcloud4/advanced/marvin.cfg
@@ -1,21 +1,19 @@
+# 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
#
-# 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
#
-# 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.
-#
+# 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.
{
"zones": [
diff --git a/tools/devcloud4/basic/marvin.cfg b/tools/devcloud4/basic/marvin.cfg
index 1c8ee54..9b7d73c 100644
--- a/tools/devcloud4/basic/marvin.cfg
+++ b/tools/devcloud4/basic/marvin.cfg
@@ -1,21 +1,19 @@
+# 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
#
-# 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
#
-# 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.
-#
+# 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.
{
"zones": [
diff --git a/tools/devcloud4/common/configure-network.sh b/tools/devcloud4/common/configure-network.sh
index bcab660..06d67d8 100755
--- a/tools/devcloud4/common/configure-network.sh
+++ b/tools/devcloud4/common/configure-network.sh
@@ -1,23 +1,23 @@
#!/bin/bash
+
+# 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.
+
# Usage ./reset-network.sh interface ip netmask
-#
-# 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.
-#
[ $# -lt 3 ] && { echo -e "Missing arguments\nUsage: ./reset-network interface ip netmask label"; exit 1; }
diff --git a/tools/devcloud4/pom.xml b/tools/devcloud4/pom.xml
index 1aa48c4..385b49a 100644
--- a/tools/devcloud4/pom.xml
+++ b/tools/devcloud4/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-tools</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -56,7 +56,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
- <version>1.0-alpha-2</version>
+ <version>1.2.1</version>
<executions>
<execution>
<phase>initialize</phase>
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile
index 67a986e..fd813e0 100644
--- a/tools/docker/Dockerfile
+++ b/tools/docker/Dockerfile
@@ -19,7 +19,7 @@
FROM ubuntu:22.04
-LABEL Vendor="Apache.org" License="ApacheV2" Version="4.22.1.0-SNAPSHOT" Author="Apache CloudStack <dev@cloudstack.apache.org>"
+LABEL Vendor="Apache.org" License="ApacheV2" Version="4.23.0.0-SNAPSHOT" Author="Apache CloudStack <dev@cloudstack.apache.org>"
ARG DEBIAN_FRONTEND=noninteractive
diff --git a/tools/docker/Dockerfile.marvin b/tools/docker/Dockerfile.marvin
index d615a78..f0a5510 100644
--- a/tools/docker/Dockerfile.marvin
+++ b/tools/docker/Dockerfile.marvin
@@ -19,11 +19,11 @@
# build for cloudstack_home_dir not this folder
FROM python:2
-LABEL Vendor="Apache.org" License="ApacheV2" Version="4.22.1.0-SNAPSHOT" Author="Apache CloudStack <dev@cloudstack.apache.org>"
+LABEL Vendor="Apache.org" License="ApacheV2" Version="4.23.0.0-SNAPSHOT" Author="Apache CloudStack <dev@cloudstack.apache.org>"
ENV WORK_DIR=/marvin
-ENV PKG_URL=https://builds.cloudstack.org/job/build-master-marvin/lastSuccessfulBuild/artifact/tools/marvin/dist/Marvin-4.22.1.0-SNAPSHOT.tar.gz
+ENV PKG_URL=https://builds.cloudstack.org/job/build-master-marvin/lastSuccessfulBuild/artifact/tools/marvin/dist/Marvin-4.23.0.0-SNAPSHOT.tar.gz
RUN apt-get update && apt-get install -y vim
RUN pip install --upgrade paramiko nose requests
diff --git a/tools/docker/Dockerfile.s390x b/tools/docker/Dockerfile.s390x
new file mode 100644
index 0000000..7e8c49f
--- /dev/null
+++ b/tools/docker/Dockerfile.s390x
@@ -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.
+#
+# CloudStack-simulator build
+
+FROM ubuntu:22.04
+
+LABEL Vendor="Apache.org" License="ApacheV2" Version="4.23.0.0-SNAPSHOT" Author="Apache CloudStack <dev@cloudstack.apache.org>"
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get -y update && apt-get install -y \
+ genisoimage \
+ libffi-dev \
+ libssl-dev \
+ curl \
+ gcc-10 \
+ git \
+ sudo \
+ ipmitool \
+ iproute2 \
+ maven \
+ openjdk-11-jdk \
+ python3-dev \
+ python-is-python3 \
+ python3-setuptools \
+ python3-pip \
+ python3-mysql.connector \
+ # Required on s390x as pre-built wheels for bcrypt, cryptography, and cffi are unavailable, necessitating source builds.
+ python3-bcrypt \
+ python3-cryptography \
+ python3-cffi \
+ supervisor
+
+RUN apt-get install -qqy mysql-server && \
+ apt-get clean all && \
+ mkdir -p /var/run/mysqld; \
+ chown mysql /var/run/mysqld
+
+RUN echo '''sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"''' >> /etc/mysql/mysql.conf.d/mysqld.cnf
+
+COPY tools/docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
+COPY . ./root
+WORKDIR /root
+
+RUN mvn -Pdeveloper -Dsimulator -DskipTests clean install
+
+RUN find /var/lib/mysql -type f -exec touch {} \; && \
+ (/usr/bin/mysqld_safe &) && \
+ sleep 5; \
+ mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password by ''" --connect-expired-password; \
+ mvn -Pdeveloper -pl developer -Ddeploydb; \
+ mvn -Pdeveloper -pl developer -Ddeploydb-simulator; \
+ MARVIN_FILE=`find /root/tools/marvin/dist/ -name "Marvin*.tar.gz"`; \
+ rm -rf /usr/bin/s390x-linux-gnu-gcc && \
+ ln -s /usr/bin/gcc-10 /usr/bin/s390x-linux-gnu-gcc && \
+ pip3 install maturin && \
+ pip3 install $MARVIN_FILE
+
+RUN apt-get install -y nodejs npm build-essential python3 g++ make
+
+RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.4/install.sh | bash && \
+ . /root/.nvm/nvm.sh && \
+ nvm install 16 && \
+ nvm use 16 && \
+ NVM_BIN="$(dirname "$(nvm which node)")" && \
+ ln -sf "$NVM_BIN/node" /usr/local/bin/node && \
+ ln -sf "$NVM_BIN/npm" /usr/local/bin/npm && \
+ cd ui && npm rebuild node-sass && npm install
+
+
+VOLUME /var/lib/mysql
+
+EXPOSE 8080 8096 5050
+
+CMD ["/usr/bin/supervisord"]
diff --git a/tools/docker/docker-compose.yml b/tools/docker/docker-compose.yml
index 86934f6..8179be2 100644
--- a/tools/docker/docker-compose.yml
+++ b/tools/docker/docker-compose.yml
@@ -5,9 +5,9 @@
# 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
@@ -24,7 +24,7 @@
- db:/var/lib/mysql
environment:
MYSQL_DATABASE: cloud
-# MYSQL_ROOT_PASSWORD: root
+ # MYSQL_ROOT_PASSWORD: root
MYSQL_ALLOW_EMPTY_PASSWORD: 1
MYSQL_USER: cloud
MYSQL_PASSWORD: cloud
diff --git a/tools/marvin/README.md b/tools/marvin/README.md
new file mode 100644
index 0000000..0d43605
--- /dev/null
+++ b/tools/marvin/README.md
@@ -0,0 +1,29 @@
+<!--
+ 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.
+ -->
+# Marvin
+
+Marvin is the Apache CloudStack Python client written for running smoke tests.
+
+## Overview
+
+Marvin provides a Python-based client for Apache CloudStack. It offers utilities for testing and interacting with CloudStack deployments.
+
+## License
+
+Licensed under the Apache License, Version 2.0. See the LICENSE.txt file for details.
diff --git a/tools/marvin/marvin/misc/build/configure.py b/tools/marvin/marvin/misc/build/configure.py
index c88a0c1..e5ab5c5 100644
--- a/tools/marvin/marvin/misc/build/configure.py
+++ b/tools/marvin/marvin/misc/build/configure.py
@@ -164,7 +164,7 @@
def seedSecondaryStorage(cscfg, hypervisor):
"""
erase secondary store and seed system VM template via puppet. The
- secseeder.sh script is executed on mgmt server bootup which will mount and
+ secseeder.sh script is executed on mgmt server boot up which will mount and
place the system VM templates on the NFS
"""
mgmt_server = cscfg.mgtSvr[0].mgtSvrIp
diff --git a/tools/marvin/mvn-setup.py b/tools/marvin/mvn-setup.py
index cabcf0d..0eab949 100755
--- a/tools/marvin/mvn-setup.py
+++ b/tools/marvin/mvn-setup.py
@@ -33,7 +33,7 @@
"""replace VERSION in setup.py"""
with open(fname, 'r') as f:
content = f.read()
- needle = '\nVERSION\s*=\s*[\'"][^\'"]*[\'"]'
+ needle = r'\nVERSION\s*=\s*[\'"][^\'"]*[\'"]'
# Ensure the version is PEP440 compliant
version = version.replace('-', '+', 1)
replacement = '\nVERSION = "%s"' % version
diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml
index 907e993..8e81a39 100644
--- a/tools/marvin/pom.xml
+++ b/tools/marvin/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-tools</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py
index ad0f245..4694cec 100644
--- a/tools/marvin/setup.py
+++ b/tools/marvin/setup.py
@@ -27,7 +27,7 @@
raise RuntimeError("python setuptools is required to build Marvin")
-VERSION = "4.22.1.0-SNAPSHOT"
+VERSION = "4.23.0.0"
setup(name="Marvin",
version=VERSION,
@@ -38,7 +38,7 @@
maintainer_email="dev@cloudstack.apache.org",
long_description="Marvin is the Apache CloudStack python "
"client written around the unittest framework",
- platforms=("Any",),
+ platforms=["Any"],
url="https://builds.apache.org/job/cloudstack-marvin/",
packages=["marvin", "marvin.cloudstackAPI",
"marvin.lib", "marvin.config", "marvin.sandbox",
diff --git a/tools/ngui/precache.py b/tools/ngui/precache.py
index e8f2301..fe63fdc 100644
--- a/tools/ngui/precache.py
+++ b/tools/ngui/precache.py
@@ -16,4 +16,4 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-apicache = {u'authorize': {u'securitygroupingress': {u'name': u'authorizeSecurityGroupIngress', u'related': [u'authorizeSecurityGroupEgress'], u'isasync': True, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the security group. If the account parameter is used, domainId must also be used.'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'start port for this ingress rule'}, {u'name': u'securitygroupid', u'required': False, u'related': [u'createSecurityGroup', u'listSecurityGroups'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the security group. Mutually exclusive with securityGroupName parameter'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list associated'}, {u'name': u'usersecuritygrouplist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'user to security group mapping'}, {u'name': u'securitygroupname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The name of the security group. Mutually exclusive with securityGroupName parameter'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the security group. Must be used with domainId.'}, {u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'protocol', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'TCP is default. UDP is the other supported protocol'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'an optional project of the security group'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'end port for this ingress rule'}], u'requiredparams': [], u'description': u'Authorizes a particular ingress rule for this security group'}, u'securitygroupegress': {u'name': u'authorizeSecurityGroupEgress', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the security group. Must be used with domainId.'}, {u'name': u'securitygroupname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The name of the security group. Mutually exclusive with securityGroupName parameter'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the security group. If the account parameter is used, domainId must also be used.'}, {u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'securitygroupid', u'required': False, u'related': [u'createSecurityGroup', u'listSecurityGroups'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the security group. Mutually exclusive with securityGroupName parameter'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}, {u'name': u'protocol', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'TCP is default. UDP is the other supported protocol'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'an optional project of the security group'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'end port for this egress rule'}, {u'name': u'usersecuritygrouplist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'user to security group mapping'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'start port for this egress rule'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list associated'}], u'requiredparams': [], u'description': u'Authorizes a particular egress rule for this security group'}}, u'restore': {u'virtualmachine': {u'name': u'restoreVirtualMachine', u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine'], u'isasync': True, u'params': [{u'name': u'virtualmachineid', u'required': True, u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Virtual Machine ID'}], u'requiredparams': [u'virtualmachineid'], u'description': u'Restore a VM to original template or specific snapshot'}}, u'suspend': {u'project': {u'name': u'suspendProject', u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to be suspended'}], u'requiredparams': [u'id'], u'description': u'Suspends a project'}}, u'revoke': {u'securitygroupingress': {u'name': u'revokeSecurityGroupIngress', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The ID of the ingress rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a particular ingress rule from this security group'}, u'securitygroupegress': {u'name': u'revokeSecurityGroupEgress', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The ID of the egress rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a particular egress rule from this security group'}}, u'disassociate': {u'ipaddress': {u'name': u'disassociateIpAddress', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the id of the public ip address to disassociate'}], u'requiredparams': [u'id'], u'description': u'Disassociates an ip address from the account.'}}, u'migrate': {u'volume': {u'name': u'migrateVolume', u'related': [u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'isasync': True, u'params': [{u'name': u'volumeid', u'required': True, u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the volume'}, {u'name': u'storageid', u'required': True, u'related': [u'cancelStorageMaintenance', u'enableStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'length': 255, u'type': u'uuid', u'description': u'destination storage pool ID to migrate the volume to'}], u'requiredparams': [u'volumeid', u'storageid'], u'description': u'Migrate volume'}, u'systemvm': {u'name': u'migrateSystemVm', u'related': [], u'isasync': True, u'params': [{u'name': u'virtualmachineid', u'required': True, u'related': [u'rebootSystemVm', u'listSystemVms'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'hostid', u'required': True, u'related': [u'addHost', u'updateHost', u'listHosts', u'listExternalLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'destination Host ID to migrate VM to'}], u'requiredparams': [u'virtualmachineid', u'hostid'], u'description': u'Attempts Migration of a system virtual machine to the host specified.'}, u'virtualmachine': {u'name': u'migrateVirtualMachine', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'deployVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'storageid', u'required': False, u'related': [u'cancelStorageMaintenance'], u'length': 255, u'type': u'long', u'description': u'Destination storage pool ID to migrate VM volumes to. Required for migrating the root disk volume'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'hostid', u'required': False, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'Destination Host ID to migrate VM to. Required for live migrating a VM from host to host'}], u'requiredparams': [u'virtualmachineid'], u'description': u'Attempts Migration of a VM to a different host or Root volume of the vm to a different storage pool'}}, u'lock': {u'account': {u'name': u'lockAccount', u'related': [u'markDefaultZoneForAccount'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Locks the specified account on this domain.'}, {u'name': u'account', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Locks the specified account.'}], u'requiredparams': [u'domainid', u'account'], u'description': u'Locks an account'}, u'user': {u'name': u'lockUser', u'related': [u'listUsers'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'lockUser', u'listUsers'], u'length': 255, u'type': u'uuid', u'description': u'Locks user by user ID.'}], u'requiredparams': [u'id'], u'description': u'Locks a user account'}}, u'dissociate': {u'lun': {u'name': u'dissociateLun', u'related': [], u'isasync': False, u'params': [{u'name': u'iqn', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Guest IQN.'}, {u'name': u'path', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'LUN path.'}], u'requiredparams': [u'iqn', u'path'], u'description': u'Dissociate a LUN'}}, u'activate': {u'project': {u'name': u'activateProject', u'related': [u'createProject', u'listProjectAccounts'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to be modified'}], u'requiredparams': [u'id'], u'description': u'Activates a project'}}, u'reconnect': {u'host': {u'name': u'reconnectHost', u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'reconnectHost', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}], u'requiredparams': [u'id'], u'description': u'Reconnects a host.'}}, u'cancel': {u'hostmaintenance': {u'name': u'cancelHostMaintenance', u'related': [u'listSwifts', u'addHost', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}], u'requiredparams': [u'id'], u'description': u'Cancels host maintenance.'}, u'storagemaintenance': {u'name': u'cancelStorageMaintenance', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'cancelStorageMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'the primary storage ID'}], u'requiredparams': [u'id'], u'description': u'Cancels maintenance for primary storage'}}, u'query': {u'asyncjobresult': {u'name': u'queryAsyncJobResult', u'related': [], u'isasync': False, u'params': [{u'name': u'jobid', u'required': True, u'related': [u'queryAsyncJobResult'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the asynchronous job'}], u'requiredparams': [u'jobid'], u'description': u'Retrieves the current status of asynchronous job.'}}, u'recover': {u'virtualmachine': {u'name': u'recoverVirtualMachine', u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Recovers a virtual machine.'}}, u'extract': {u'volume': {u'name': u'extractVolume', u'related': [u'extractTemplate', u'extractIso'], u'isasync': True, u'params': [{u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the url to which the volume would be extracted'}, {u'name': u'id', u'required': True, u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'listVolumes', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the volume'}, {u'name': u'mode', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the mode of extraction - HTTP_DOWNLOAD or FTP_UPLOAD'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone where the volume is located'}], u'requiredparams': [u'id', u'mode', u'zoneid'], u'description': u'Extracts volume'}, u'iso': {u'name': u'extractIso', u'related': [u'extractTemplate'], u'isasync': True, u'params': [{u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone where the ISO is originally located'}, {u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the url to which the ISO would be extracted'}, {u'name': u'mode', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the mode of extraction - HTTP_DOWNLOAD or FTP_UPLOAD'}, {u'name': u'id', u'required': True, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the ISO file'}], u'requiredparams': [u'mode', u'id'], u'description': u'Extracts an ISO'}, u'template': {u'name': u'extractTemplate', u'related': [], u'isasync': True, u'params': [{u'name': u'mode', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the mode of extraction - HTTP_DOWNLOAD or FTP_UPLOAD'}, {u'name': u'id', u'required': True, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the template'}, {u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the url to which the ISO would be extracted'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone where the ISO is originally located'}], u'requiredparams': [u'mode', u'id'], u'description': u'Extracts a template'}}, u'copy': {u'iso': {u'name': u'copyIso', u'related': [u'updateIso', u'listIsos'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'Template ID.'}, {u'name': u'destzoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'ID of the zone the template is being copied to.'}, {u'name': u'sourcezoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'ID of the zone the template is currently hosted on.'}], u'requiredparams': [u'id', u'destzoneid', u'sourcezoneid'], u'description': u'Copies an iso from one zone to another.'}, u'template': {u'name': u'copyTemplate', u'related': [u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'registerTemplate', u'copyIso', u'updateIso', u'listIsos'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'copyTemplate', u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'registerTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'Template ID.'}, {u'name': u'destzoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'ID of the zone the template is being copied to.'}, {u'name': u'sourcezoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'ID of the zone the template is currently hosted on.'}], u'requiredparams': [u'id', u'destzoneid', u'sourcezoneid'], u'description': u'Copies a template from one zone to another.'}}, u'prepare': {u'hostformaintenance': {u'name': u'prepareHostForMaintenance', u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}], u'requiredparams': [u'id'], u'description': u'Prepares a host for maintenance.'}, u'template': {u'name': u'prepareTemplate', u'related': [u'registerIso', u'updateTemplate', u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'zone ID of the template to be prepared in primary storage(s).'}, {u'name': u'templateid', u'required': True, u'related': [u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'template ID of the template to be prepared in primary storage(s).'}], u'requiredparams': [u'zoneid', u'templateid'], u'description': u'load template into primary storage'}}, u'attach': {u'volume': {u'name': u'attachVolume', u'related': [u'detachVolume', u'resizeVolume', u'uploadVolume', u'createVolume'], u'isasync': True, u'params': [{u'name': u'deviceid', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the ID of the device to map the volume to within the guest OS. If no deviceId is passed in, the next available deviceId will be chosen. Possible values for a Linux OS are:* 1 - /dev/xvdb* 2 - /dev/xvdc* 4 - /dev/xvde* 5 - /dev/xvdf* 6 - /dev/xvdg* 7 - /dev/xvdh* 8 - /dev/xvdi* 9 - /dev/xvdj'}, {u'name': u'id', u'required': True, u'related': [u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u' the ID of the virtual machine'}], u'requiredparams': [u'id', u'virtualmachineid'], u'description': u'Attaches a disk volume to a virtual machine.'}, u'iso': {u'name': u'attachIso', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'id', u'required': True, u'related': [u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the ISO file'}], u'requiredparams': [u'virtualmachineid', u'id'], u'description': u'Attaches an ISO to a virtual machine.'}}, u'create': {u'loadbalancerrule': {u'name': u'createLoadBalancerRule', u'related': [u'updateLoadBalancerRule'], u'isasync': True, u'params': [{u'name': u'openfirewall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, firewall rule for source/end public port is automatically created; if false - firewall rule has to be created explicitely. If not specified 1) defaulted to false when LB rule is being created for VPC guest network 2) in all other cases defaulted to true'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the load balancer. Must be used with the domainId parameter.'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the load balancer'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'zone where the load balancer is going to be created. This parameter is required when LB service provider is ElasticLoadBalancerVm'}, {u'name': u'publicipid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'public ip address id from where the network traffic will be load balanced from'}, {u'name': u'algorithm', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'load balancer algorithm (source, roundrobin, leastconn)'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the load balancer rule'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}, {u'name': u'publicport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the public port from where the network traffic will be load balanced from'}, {u'name': u'description', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the description of the load balancer rule'}, {u'name': u'privateport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the private port of the private ip address/virtual machine where the network traffic will be load balanced to'}, {u'name': u'networkid', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The guest network this rule will be created for. Required when public Ip address is not associated with any Guest network yet (VPC case)'}], u'requiredparams': [u'algorithm', u'name', u'publicport', u'privateport'], u'description': u'Creates a load balancer rule'}, u'domain': {u'name': u'createDomain', u'related': [], u'isasync': False, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'creates domain with this name'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Domain UUID, required for adding domain from another Region'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network domain for networks in the domain'}, {u'name': u'parentdomainid', u'required': False, u'related': [u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'assigns new domain a parent domain by domain ID of the parent. If no parent domain is specied, the ROOT domain is assumed.'}], u'requiredparams': [u'name'], u'description': u'Creates a domain'}, u'snapshotpolicy': {u'name': u'createSnapshotPolicy', u'related': [u'listSnapshotPolicies'], u'isasync': False, u'params': [{u'name': u'intervaltype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'valid values are HOURLY, DAILY, WEEKLY, and MONTHLY'}, {u'name': u'maxsnaps', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'maximum number of snapshots to retain'}, {u'name': u'schedule', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'time the snapshot is scheduled to be taken. Format is:* if HOURLY, MM* if DAILY, MM:HH* if WEEKLY, MM:HH:DD (1-7)* if MONTHLY, MM:HH:DD (1-28)'}, {u'name': u'timezone', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.'}, {u'name': u'volumeid', u'required': True, u'related': [u'detachVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}], u'requiredparams': [u'intervaltype', u'maxsnaps', u'schedule', u'timezone', u'volumeid'], u'description': u'Creates a snapshot policy for the account.'}, u'diskoffering': {u'name': u'createDiskOffering', u'related': [u'listDiskOfferings'], u'isasync': False, u'params': [{u'name': u'customized', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'whether disk offering is custom or not'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 4096, u'type': u'string', u'description': u'alternate display text of the disk offering'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the containing domain, null for public offerings'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the disk offering'}, {u'name': u'disksize', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'size of the disk offering in GB'}, {u'name': u'storagetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the storage type of the disk offering. Values are local and shared.'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'tags for the disk offering'}], u'requiredparams': [u'displaytext', u'name'], u'description': u'Creates a disk offering.'}, u'securitygroup': {u'name': u'createSecurityGroup', u'related': [u'listSecurityGroups'], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the security group. Must be used with domainId.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the security group. If the account parameter is used, domainId must also be used.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the security group'}, {u'name': u'description', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the description of the security group'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Deploy vm for the project'}], u'requiredparams': [u'name'], u'description': u'Creates a security group'}, u'portforwardingrule': {u'name': u'createPortForwardingRule', u'related': [u'listIpForwardingRules'], u'isasync': True, u'params': [{u'name': u'privateport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u"the starting port of port forwarding rule's private port range"}, {u'name': u'ipaddressid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the IP address id of the port forwarding rule'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the port fowarding rule. Valid values are TCP or UDP.'}, {u'name': u'openfirewall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. If not specified 1) defaulted to false when PF rule is being created for VPC guest network 2) in all other cases defaulted to true'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine for the port forwarding rule'}, {u'name': u'privateendport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u"the ending port of port forwarding rule's private port range"}, {u'name': u'networkid', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The network of the vm the Port Forwarding rule will be created for. Required when public Ip address is not associated with any Guest network yet (VPC case)'}, {u'name': u'publicendport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u"the ending port of port forwarding rule's private port range"}, {u'name': u'publicport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u"the starting port of port forwarding rule's public port range"}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}], u'requiredparams': [u'privateport', u'ipaddressid', u'protocol', u'virtualmachineid', u'publicport'], u'description': u'Creates a port forwarding rule'}, u'pod': {u'name': u'createPod', u'related': [u'updatePod', u'listPods'], u'isasync': False, u'params': [{u'name': u'startip', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the starting IP address for the Pod'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the Pod'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID in which the Pod will be created'}, {u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address for the Pod'}, {u'name': u'netmask', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask for the Pod'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this Pod for allocation of new resources'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway for the Pod'}], u'requiredparams': [u'startip', u'name', u'zoneid', u'netmask', u'gateway'], u'description': u'Creates a new Pod.'}, u'ipforwardingrule': {u'name': u'createIpForwardingRule', u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'listPortForwardingRules', u'createPortForwardingRule'], u'isasync': True, u'params': [{u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the end port for the rule'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}, {u'name': u'ipaddressid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the public IP address id of the forwarding rule, already associated via associateIp'}, {u'name': u'openfirewall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default'}, {u'name': u'startport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the start port for the rule'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the rule. Valid values are TCP or UDP.'}], u'requiredparams': [u'ipaddressid', u'startport', u'protocol'], u'description': u'Creates an ip forwarding rule'}, u'vpnconnection': {u'name': u'createVpnConnection', u'related': [u'listVpnConnections', u'resetVpnConnection'], u'isasync': True, u'params': [{u'name': u's2svpngatewayid', u'required': True, u'related': [u'createVpnGateway', u'listVpnGateways'], u'length': 255, u'type': u'uuid', u'description': u'id of the vpn gateway'}, {u'name': u's2scustomergatewayid', u'required': True, u'related': [u'updateVpnCustomerGateway', u'createVpnCustomerGateway', u'listVpnCustomerGateways'], u'length': 255, u'type': u'uuid', u'description': u'id of the customer gateway'}], u'requiredparams': [u's2svpngatewayid', u's2scustomergatewayid'], u'description': u'Create site to site vpn connection'}, u'vpncustomergateway': {u'name': u'createVpnCustomerGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the gateway. If used with the account parameter returns the gateway associated with the account for the specified domain.'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'public ip address id of the customer gateway'}, {u'name': u'esplifetime', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lifetime of phase 2 VPN connection to the customer gateway, in seconds'}, {u'name': u'esppolicy', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'ESP policy of the customer gateway'}, {u'name': u'ikepolicy', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'IKE policy of the customer gateway'}, {u'name': u'cidrlist', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'guest cidr list of the customer gateway'}, {u'name': u'dpd', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'If DPD is enabled for VPN connection'}, {u'name': u'ipsecpsk', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'IPsec Preshared-Key of the customer gateway'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the gateway. Must be used with the domainId parameter.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of this customer gateway'}, {u'name': u'ikelifetime', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lifetime of phase 1 VPN connection to the customer gateway, in seconds'}], u'requiredparams': [u'gateway', u'esppolicy', u'ikepolicy', u'cidrlist', u'ipsecpsk'], u'description': u'Creates site to site vpn customer gateway'}, u'lbstickinesspolicy': {u'name': u'createLBStickinessPolicy', u'related': [], u'isasync': True, u'params': [{u'name': u'lbruleid', u'required': True, u'related': [u'listIpForwardingRules'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the LB Stickiness policy'}, {u'name': u'methodname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the LB Stickiness policy method, possible values can be obtained from ListNetworks API '}, {u'name': u'description', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the description of the LB Stickiness policy'}, {u'name': u'param', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'param list. Example: param[0].name=cookiename¶m[0].value=LBCookie '}], u'requiredparams': [u'lbruleid', u'name', u'methodname'], u'description': u'Creates a Load Balancer stickiness policy '}, u'vpcoffering': {u'name': u'createVPCOffering', u'related': [u'listVPCOfferings'], u'isasync': True, u'params': [{u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the vpc offering'}, {u'name': u'supportedservices', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'services supported by the vpc offering'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the vpc offering'}], u'requiredparams': [u'displaytext', u'supportedservices', u'name'], u'description': u'Creates VPC offering'}, u'network': {u'name': u'createNetwork', u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'isasync': False, u'params': [{u'name': u'endipv6', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IPv6 address in the IPv6 network range'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'an optional project for the ssh key'}, {u'name': u'ip6cidr', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the CIDR of IPv6 network, must be at least /64'}, {u'name': u'acltype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Access control type; supported values are account and domain. In 3.0 all shared networks should have aclType=Domain, and all Isolated networks - Account. Account means that only the account owner can use the network, domain - all accouns in the domain can use the network'}, {u'name': u'gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the network. Required for Shared networks and Isolated networks when it belongs to VPC'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the network'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID the network belongs to'}, {u'name': u'subdomainaccess', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Defines whether to allow subdomains to use networks dedicated to their parent domain(s). Should be used with aclType=Domain, defaulted to allow.subdomain.network.access global config if not specified'}, {u'name': u'startip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IP address in the network IP range'}, {u'name': u'netmask', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask of the network. Required for Shared networks and Isolated networks when it belongs to VPC'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'domain ID of the account owning a network'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'network domain'}, {u'name': u'ip6gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the IPv6 network. Required for Shared networks and Isolated networks when it belongs to VPC'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'account who will own the network'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the network'}, {u'name': u'startipv6', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IPv6 address in the IPv6 network range'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the network'}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'the VPC network belongs to'}, {u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address in the network IP range. If not specified, will be defaulted to startIP'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ID or VID of the network'}, {u'name': u'networkofferingid', u'required': True, u'related': [u'createNetworkOffering', u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'the network offering id'}], u'requiredparams': [u'displaytext', u'zoneid', u'name', u'networkofferingid'], u'description': u'Creates a network'}, u'zone': {u'name': u'createZone', u'related': [u'listZones'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the containing domain, null for public zones'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the Zone'}, {u'name': u'ip6dns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second DNS for IPv6 network in the Zone'}, {u'name': u'domain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network domain name for the networks in the zone'}, {u'name': u'internaldns1', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first internal DNS for the Zone'}, {u'name': u'localstorageenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if local storage offering enabled, false otherwise'}, {u'name': u'securitygroupenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network is security group enabled, false otherwise'}, {u'name': u'networktype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'network type of the zone, can be Basic or Advanced'}, {u'name': u'internaldns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second internal DNS for the Zone'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this Zone for allocation of new resources'}, {u'name': u'guestcidraddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the guest CIDR address for the Zone'}, {u'name': u'dns1', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first DNS for the Zone'}, {u'name': u'ip6dns1', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first DNS for IPv6 network in the Zone'}, {u'name': u'dns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second DNS for the Zone'}], u'requiredparams': [u'name', u'internaldns1', u'networktype', u'dns1'], u'description': u'Creates a Zone.'}, u'remoteaccessvpn': {u'name': u'createRemoteAccessVpn', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the VPN. Must be used with domainId.'}, {u'name': u'openfirewall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default'}, {u'name': u'publicipid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'public ip address id of the vpn server'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the VPN. If the account parameter is used, domainId must also be used.'}, {u'name': u'iprange', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the range of ip addresses to allocate to vpn clients. The first ip in the range will be taken by the vpn server'}], u'requiredparams': [u'publicipid'], u'description': u'Creates a l2tp/ipsec remote access vpn'}, u'instancegroup': {u'name': u'createInstanceGroup', u'related': [], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account of the instance group. The account parameter must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The project of the instance group'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the instance group'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID of account owning the instance group'}], u'requiredparams': [u'name'], u'description': u'Creates a vm group'}, u'autoscalepolicy': {u'name': u'createAutoScalePolicy', u'related': [u'updateAutoScalePolicy'], u'isasync': True, u'params': [{u'name': u'action', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the action to be executed if all the conditions evaluate to true for the specified duration.'}, {u'name': u'quiettime', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the cool down period for which the policy should not be evaluated after the action has been taken'}, {u'name': u'conditionids', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'the list of IDs of the conditions that are being evaluated on every interval'}, {u'name': u'duration', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the duration for which the conditions have to be true before action is taken'}], u'requiredparams': [u'action', u'conditionids', u'duration'], u'description': u'Creates an autoscale policy for a provision or deprovision action, the action is taken when the all the conditions evaluates to true for the specified duration. The policy is in effect once it is attached to a autscale vm group.'}, u'tags': {u'name': u'createTags', u'related': [], u'isasync': True, u'params': [{u'name': u'tags', u'required': True, u'related': [], u'length': 255, u'type': u'map', u'description': u'Map of tags (key/value pairs)'}, {u'name': u'resourcetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of the resource'}, {u'name': u'customer', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"identifies client specific tag. When the value is not null, the tag can't be used by cloudStack code internally"}, {u'name': u'resourceids', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of resources to create the tags for'}], u'requiredparams': [u'tags', u'resourcetype', u'resourceids'], u'description': u'Creates resource tag(s)'}, u'serviceoffering': {u'name': u'createServiceOffering', u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'isasync': False, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the service offering'}, {u'name': u'storagetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the storage type of the service offering. Values are local and shared.'}, {u'name': u'issystem', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'is this a system vm offering'}, {u'name': u'cpunumber', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'the CPU number of the service offering'}, {u'name': u'systemvmtype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the system VM type. Possible types are "domainrouter", "consoleproxy" and "secondarystoragevm".'}, {u'name': u'limitcpuuse', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'restrict the CPU usage to committed service offering'}, {u'name': u'hosttags', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the host tag for this service offering.'}, {u'name': u'offerha', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the HA for the service offering'}, {u'name': u'memory', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'the total memory of the service offering in MB'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the containing domain, null for public offerings'}, {u'name': u'cpuspeed', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'the CPU speed of the service offering in MHz.'}, {u'name': u'networkrate', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'data transfer rate in megabits per second allowed. Supported only for non-System offering and system offerings having "domainrouter" systemvmtype'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the service offering'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the tags for this service offering.'}], u'requiredparams': [u'name', u'cpunumber', u'memory', u'cpuspeed', u'displaytext'], u'description': u'Creates a service offering.'}, u'condition': {u'name': u'createCondition', u'related': [], u'isasync': True, u'params': [{u'name': u'threshold', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'Threshold value.'}, {u'name': u'counterid', u'required': True, u'related': [u'listConditions', u'listCounters', u'createCounter'], u'length': 255, u'type': u'uuid', u'description': u'ID of the Counter.'}, {u'name': u'relationaloperator', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Relational Operator to be used with threshold.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account of the condition. Must be used with the domainId parameter.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID of the account.'}], u'requiredparams': [u'threshold', u'counterid', u'relationaloperator'], u'description': u'Creates a condition'}, u'storagepool': {u'name': u'createStoragePool', u'related': [u'cancelStorageMaintenance', u'listStoragePools'], u'isasync': False, u'params': [{u'name': u'clusterid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID for the storage pool'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the storage pool'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name for the storage pool'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the tags for the storage pool'}, {u'name': u'podid', u'required': True, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the storage pool'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL of the storage pool'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'the details for the storage pool'}], u'requiredparams': [u'clusterid', u'zoneid', u'name', u'podid', u'url'], u'description': u'Creates a storage pool.'}, u'vpngateway': {u'name': u'createVpnGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'vpcid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'public ip address id of the vpn gateway'}], u'requiredparams': [u'vpcid'], u'description': u'Creates site to site vpn local gateway'}, u'autoscalevmgroup': {u'name': u'createAutoScaleVmGroup', u'related': [u'updateAutoScaleVmGroup'], u'isasync': True, u'params': [{u'name': u'vmprofileid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the autoscale profile that contains information about the vms in the vm group.'}, {u'name': u'scaledownpolicyids', u'required': True, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'list', u'description': u'list of scaledown autoscale policies'}, {u'name': u'scaleuppolicyids', u'required': True, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'list', u'description': u'list of scaleup autoscale policies'}, {u'name': u'interval', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the frequency at which the conditions have to be evaluated'}, {u'name': u'minmembers', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the minimum number of members in the vmgroup, the number of instances in the vm group will be equal to or more than this number.'}, {u'name': u'maxmembers', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the maximum number of members in the vmgroup, The number of instances in the vm group will be equal to or less than this number.'}, {u'name': u'lbruleid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}], u'requiredparams': [u'vmprofileid', u'scaledownpolicyids', u'scaleuppolicyids', u'minmembers', u'maxmembers', u'lbruleid'], u'description': u'Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.'}, u'networkacl': {u'name': u'createNetworkACL', u'related': [], u'isasync': True, u'params': [{u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the ending port of ACL'}, {u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the traffic type for the ACL,can be Ingress or Egress, defaulted to Ingress if not specified'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to allow traffic from/to'}, {u'name': u'networkid', u'required': True, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The network of the vm the ACL will be created for'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the ACL rule. Valid values are TCP/UDP/ICMP.'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the starting port of ACL'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}], u'requiredparams': [u'networkid', u'protocol'], u'description': u'Creates a ACL rule the given network (the network has to belong to VPC)'}, u'template': {u'name': u'createTemplate', u'related': [u'cancelStorageMaintenance', u'enableStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'isasync': True, u'params': [{u'name': u'ostypeid', u'required': True, u'related': [u'listOsTypes'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS Type that best represents the OS of this template.'}, {u'name': u'templatetag', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the tag for this template.'}, {u'name': u'bits', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'32 or 64 bit'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this template is a public template, false otherwise'}, {u'name': u'volumeid', u'required': False, u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume the template is being created from. Either this parameter, or snapshotId has to be passed in'}, {u'name': u'passwordenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template supports the password reset feature; default is false'}, {u'name': u'snapshotid', u'required': False, u'related': [u'createSnapshot', u'listSnapshots'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the snapshot the template is being created from. Either this parameter, or volumeId has to be passed in'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Optional, VM ID. If this presents, it is going to create a baremetal template for VM this ID refers to. This is only for VM whose hypervisor type is BareMetal'}, {u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Optional, only for baremetal hypervisor. The directory name where template stored on CIFS server'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the template. This is usually used for display purposes.'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'Template details in key/value pairs.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the template'}, {u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this template is a featured template, false otherwise'}, {u'name': u'requireshvm', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template requires HVM, false otherwise'}], u'requiredparams': [u'ostypeid', u'displaytext', u'name'], u'description': u'Creates a template of a virtual machine. The virtual machine must be in a STOPPED state. A template created from this command is automatically designated as a private template visible to the account that created it.'}, u'privategateway': {u'name': u'createPrivateGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'vlan', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the Vlan for the private gateway'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the Private gateway'}, {u'name': u'netmask', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask of the Private gateway'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID the network belongs to'}, {u'name': u'vpcid', u'required': True, u'related': [u'restartVPC'], u'length': 255, u'type': u'uuid', u'description': u'the VPC network belongs to'}, {u'name': u'ipaddress', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the IP address of the Private gateaway'}], u'requiredparams': [u'vlan', u'gateway', u'netmask', u'vpcid', u'ipaddress'], u'description': u'Creates a private gateway'}, u'volumeonfiler': {u'name': u'createVolumeOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'volumename', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'volume name.'}, {u'name': u'aggregatename', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'aggregate name.'}, {u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}, {u'name': u'snapshotpolicy', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'snapshot policy.'}, {u'name': u'ipaddress', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'ip address.'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'password.'}, {u'name': u'size', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'volume size.'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'user name.'}, {u'name': u'snapshotreservation', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'snapshot reservation.'}], u'requiredparams': [u'volumename', u'aggregatename', u'poolname', u'ipaddress', u'password', u'size', u'username'], u'description': u'Create a volume'}, u'staticroute': {u'name': u'createStaticRoute', u'related': [], u'isasync': True, u'params': [{u'name': u'gatewayid', u'required': True, u'related': [u'createPrivateGateway'], u'length': 255, u'type': u'uuid', u'description': u'the gateway id we are creating static route for'}, {u'name': u'cidr', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'static route cidr'}], u'requiredparams': [u'gatewayid', u'cidr'], u'description': u'Creates a static route'}, u'volume': {u'name': u'createVolume', u'related': [u'detachVolume', u'uploadVolume'], u'isasync': True, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the disk volume'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the availability zone'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'the project associated with the volume. Mutually exclusive with account parameter'}, {u'name': u'diskofferingid', u'required': False, u'related': [u'updateDiskOffering', u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk offering. Either diskOfferingId or snapshotId must be passed in.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the disk volume. Must be used with the domainId parameter.'}, {u'name': u'size', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Arbitrary volume size'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the disk offering. If used with the account parameter returns the disk volume associated with the account for the specified domain.'}, {u'name': u'snapshotid', u'required': False, u'related': [u'createSnapshot', u'listSnapshots'], u'length': 255, u'type': u'uuid', u'description': u'the snapshot ID for the disk volume. Either diskOfferingId or snapshotId must be passed in.'}], u'requiredparams': [u'name'], u'description': u'Creates a disk volume from a disk offering. This disk volume must still be attached to a virtual machine to make use of it.'}, u'user': {u'name': u'createUser', u'related': [u'lockUser', u'listUsers'], u'isasync': False, u'params': [{u'name': u'account', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Creates the user under the specified account. If no account is specified, the username will be used as the account name.'}, {u'name': u'userid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'User UUID, required for adding account from external provisioning system'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Unique username.'}, {u'name': u'timezone', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Creates the user under the specified domain. Has to be accompanied with the account parameter'}, {u'name': u'email', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'email'}, {u'name': u'lastname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'lastname'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.'}, {u'name': u'firstname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'firstname'}], u'requiredparams': [u'account', u'username', u'email', u'lastname', u'password', u'firstname'], u'description': u'Creates a user for an account that already exists'}, u'vpc': {u'name': u'createVPC', u'related': [u'updateVPC', u'restartVPC', u'listVPCs'], u'isasync': True, u'params': [{u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the VPC'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the availability zone'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the VPC'}, {u'name': u'vpcofferingid', u'required': True, u'related': [u'listVPCOfferings', u'createVPCOffering'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the VPC offering'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'VPC network domain. All networks inside the VPC will belong to this domain'}, {u'name': u'cidr', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u"the cidr of the VPC. All VPC guest networks' cidrs should be within this CIDR"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the VPC. Must be used with the domainId parameter.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the VPC. If used with the account parameter returns the VPC associated with the account for the specified domain.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'create VPC for the project'}], u'requiredparams': [u'displaytext', u'zoneid', u'name', u'vpcofferingid', u'cidr'], u'description': u'Creates a VPC'}, u'storagenetworkiprange': {u'name': u'createStorageNetworkIpRange', u'related': [u'listStorageNetworkIpRange', u'updateStorageNetworkIpRange'], u'isasync': True, u'params': [{u'name': u'startip', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IP address'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Optional. The vlan the ip range sits on, default to Null when it is not specified which means you network is not on any Vlan. This is mainly for Vmware as other hypervisors can directly reterive bridge from pyhsical network traffic type table'}, {u'name': u'podid', u'required': True, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'UUID of pod where the ip range belongs to'}, {u'name': u'netmask', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask for storage network'}, {u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway for storage network'}], u'requiredparams': [u'startip', u'podid', u'netmask', u'gateway'], u'description': u'Creates a Storage network IP range.'}, u'pool': {u'name': u'createPool', u'related': [], u'isasync': False, u'params': [{u'name': u'algorithm', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'algorithm.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'algorithm', u'name'], u'description': u'Create a pool'}, u'autoscalevmprofile': {u'name': u'createAutoScaleVmProfile', u'related': [u'updateAutoScaleVmProfile', u'listAutoScaleVmProfiles'], u'isasync': True, u'params': [{u'name': u'otherdeployparams', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'parameters other than zoneId/serviceOfferringId/templateId of the auto deployed virtual machine'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'availability zone for the auto deployed virtual machine'}, {u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering', u'updateServiceOffering'], u'length': 255, u'type': u'uuid', u'description': u'the service offering of the auto deployed virtual machine'}, {u'name': u'expungevmgraceperiod', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the time allowed for existing connections to get closed before a vm is destroyed'}, {u'name': u'counterparam', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'counterparam list. Example: counterparam[0].name=snmpcommunity&counterparam[0].value=public&counterparam[1].name=snmpport&counterparam[1].value=161'}, {u'name': u'templateid', u'required': True, u'related': [u'registerIso', u'updateTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template of the auto deployed virtual machine'}, {u'name': u'autoscaleuserid', u'required': False, u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser', u'updateUser'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the user used to launch and destroy the VMs'}], u'requiredparams': [u'zoneid', u'serviceofferingid', u'templateid'], u'description': u'Creates a profile that contains information about the virtual machine which will be provisioned automatically by autoscale feature.'}, u'account': {u'name': u'createAccount', u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser', u'getUser', u'updateUser'], u'isasync': False, u'params': [{u'name': u'lastname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'lastname'}, {u'name': u'accounttype', u'required': True, u'related': [], u'length': 255, u'type': u'short', u'description': u'Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Unique username.'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.'}, {u'name': u'firstname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'firstname'}, {u'name': u'userid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'User UUID, required for adding account from external provisioning system'}, {u'name': u'timezone', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Creates the user under the specified account. If no account is specified, the username will be used as the account name.'}, {u'name': u'accountdetails', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'details for account used to store specific parameters'}, {u'name': u'email', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'email'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"Network domain for the account's networks"}, {u'name': u'accountid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Account UUID, required for adding account from external provisioning system'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'Creates the user under the specified domain.'}], u'requiredparams': [u'lastname', u'accounttype', u'username', u'password', u'firstname', u'email'], u'description': u'Creates an account'}, u'firewallrule': {u'name': u'createFirewallRule', u'related': [u'listEgressFirewallRules'], u'isasync': True, u'params': [{u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the firewall rule. Valid values are TCP/UDP/ICMP.'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of firewallrule: system/user'}, {u'name': u'ipaddressid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the IP address id of the port forwarding rule'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the starting port of firewall rule'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}, {u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the ending port of firewall rule'}], u'requiredparams': [u'protocol', u'ipaddressid'], u'description': u'Creates a firewall rule for a given ip address'}, u'networkoffering': {u'name': u'createNetworkOffering', u'related': [u'updateNetworkOffering'], u'isasync': False, u'params': [{u'name': u'serviceproviderlist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'provider to service mapping. If not specified, the provider for the service will be mapped to the default provider on the physical network'}, {u'name': u'serviceofferingid', u'required': False, u'related': [u'updateHypervisorCapabilities'], u'length': 255, u'type': u'uuid', u'description': u'the service offering ID used by virtual router provider'}, {u'name': u'supportedservices', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'services supported by the network offering'}, {u'name': u'networkrate', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'data transfer rate in megabits per second allowed'}, {u'name': u'ispersistent', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network offering supports persistent networks; defaulted to false if not specified'}, {u'name': u'servicecapabilitylist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'desired service capabilities as part of network offering'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the network offering'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the tags for the network offering.'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the network offering'}, {u'name': u'conservemode', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the network offering is IP conserve mode enabled'}, {u'name': u'guestiptype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'guest type of the network offering: Shared or Isolated'}, {u'name': u'traffictype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the traffic type for the network offering. Supported type in current release is GUEST only'}, {u'name': u'specifyvlan', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network offering supports vlans'}, {u'name': u'availability', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the availability of network offering. Default value is Optional'}, {u'name': u'specifyipranges', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network offering supports specifying ip ranges; defaulted to false if not specified'}], u'requiredparams': [u'supportedservices', u'name', u'displaytext', u'guestiptype', u'traffictype'], u'description': u'Creates a network offering.'}, u'vlaniprange': {u'name': u'createVlanIpRange', u'related': [u'listVlanIpRanges'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'domain ID of the account owning a VLAN'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'project who will own the VLAN. If VLAN is Zone wide, this parameter should be ommited'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ID or VID of the VLAN. If not specified, will be defaulted to the vlan of the network or if vlan of the network is null - to Untagged'}, {u'name': u'networkid', u'required': False, u'related': [u'createNetwork', u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the network id'}, {u'name': u'forvirtualnetwork', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if VLAN is of Virtual type, false if Direct'}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'optional parameter. Have to be specified for Direct Untagged vlan only.'}, {u'name': u'ip6cidr', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the CIDR of IPv6 network, must be at least /64'}, {u'name': u'endipv6', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IPv6 address in the IPv6 network range'}, {u'name': u'startip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IP address in the VLAN IP range'}, {u'name': u'startipv6', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IPv6 address in the IPv6 network range'}, {u'name': u'gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the VLAN IP range'}, {u'name': u'netmask', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask of the VLAN IP range'}, {u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address in the VLAN IP range'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'account who will own the VLAN. If VLAN is Zone wide, this parameter should be ommited'}, {u'name': u'ip6gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the IPv6 network. Required for Shared networks and Isolated networks when it belongs to VPC'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the physical network id'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the VLAN IP range'}], u'requiredparams': [], u'description': u'Creates a VLAN IP range.'}, u'counter': {u'name': u'createCounter', u'related': [u'listCounters'], u'isasync': True, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the counter.'}, {u'name': u'source', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Source of the counter.'}, {u'name': u'value', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Value of the counter e.g. oid in case of snmp.'}], u'requiredparams': [u'name', u'source', u'value'], u'description': u'Adds metric counter'}, u'lunonfiler': {u'name': u'createLunOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'size', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'LUN size.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'size', u'name'], u'description': u'Create a LUN from a pool'}, u'project': {u'name': u'createProject', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'account who will be Admin for the project'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the project'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'domain ID of the account owning a project'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'display text of the project'}], u'requiredparams': [u'name', u'displaytext'], u'description': u'Creates a project'}, u'physicalnetwork': {u'name': u'createPhysicalNetwork', u'related': [u'listPhysicalNetworks'], u'isasync': True, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the physical network'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the physical network'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'Tag the physical network'}, {u'name': u'networkspeed', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the speed for the physical network[1G/10G]'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the VLAN for the physical network'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'domain ID of the account owning a physical network'}, {u'name': u'broadcastdomainrange', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the broadcast domain range for the physical network[Pod or Zone]. In Acton release it can be Zone only in Advance zone, and Pod in Basic'}, {u'name': u'isolationmethods', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the isolation method for the physical network[VLAN/L3/GRE]'}], u'requiredparams': [u'name', u'zoneid'], u'description': u'Creates a physical network'}, u'snapshot': {u'name': u'createSnapshot', u'related': [u'listSnapshots'], u'isasync': True, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The domain ID of the snapshot. If used with the account parameter, specifies a domain for the account associated with the disk volume.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The account of the snapshot. The account parameter must be used with the domainId parameter.'}, {u'name': u'volumeid', u'required': True, u'related': [u'detachVolume'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the disk volume'}, {u'name': u'policyid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'policy id of the snapshot, if this is null, then use MANUAL_POLICY.'}], u'requiredparams': [u'volumeid'], u'description': u'Creates an instant snapshot of a volume.'}, u'virtualrouterelement': {u'name': u'createVirtualRouterElement', u'related': [], u'isasync': True, u'params': [{u'name': u'nspid', u'required': True, u'related': [u'updateNetworkServiceProvider'], u'length': 255, u'type': u'uuid', u'description': u'the network service provider ID of the virtual router element'}], u'requiredparams': [u'nspid'], u'description': u'Create a virtual router element.'}, u'egressfirewallrule': {u'name': u'createEgressFirewallRule', u'related': [u'createFirewallRule', u'listEgressFirewallRules'], u'isasync': True, u'params': [{u'name': u'networkid', u'required': True, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the network id of the port forwarding rule'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the starting port of firewall rule'}, {u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of firewallrule: system/user'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the firewall rule. Valid values are TCP/UDP/ICMP.'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the ending port of firewall rule'}], u'requiredparams': [u'networkid', u'protocol'], u'description': u'Creates a egress firewall rule for a given network '}, u'sshkeypair': {u'name': u'createSSHKeyPair', u'related': [u'listSSHKeyPairs'], u'isasync': False, u'params': [{u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'an optional project for the ssh key'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the ssh key. If the account parameter is used, domainId must also be used.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the keypair'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the ssh key. Must be used with domainId.'}], u'requiredparams': [u'name'], u'description': u'Create a new keypair and returns the private key'}}, u'deploy': {u'virtualmachine': {u'name': u'deployVirtualMachine', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'keypair', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the ssh key pair used to login to the virtual machine'}, {u'name': u'userdata', u'required': False, u'related': [], u'length': 2048, u'type': u'string', u'description': u'an optional binary data that can be sent to the virtual machine upon a successful deployment. This binary data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. Using HTTP GET (via querystring), you can send up to 2KB of data after base64 encoding.'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the hypervisor on which to deploy the virtual machine'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.'}, {u'name': u'size', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId'}, {u'name': u'diskofferingid', u'required': False, u'related': [u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk offering for the virtual machine. If the template is of ISO format, the diskOfferingId is for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk volume. If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk Volume created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT Disk Volume created.'}, {u'name': u'securitygroupids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma separated list of security groups id that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupnames parameter'}, {u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the service offering for the virtual machine'}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"the ip address for default vm's network"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the virtual machine. Must be used with domainId.'}, {u'name': u'hostid', u'required': False, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'destination Host ID to deploy the VM to - parameter available for root admin only'}, {u'name': u'iptonetworklist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u"ip to network mapping. Can't be specified with networkIds parameter. Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].ipv6=fc00:1234:5678::abcd&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid"}, {u'name': u'ip6address', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"the ipv6 address for default vm's network"}, {u'name': u'keyboard', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'Deploy vm for the project'}, {u'name': u'networkids', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'list', u'description': u"list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter"}, {u'name': u'displayname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional user generated name for the virtual machine'}, {u'name': u'securitygroupnames', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma separated list of security groups names that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupids parameter'}, {u'name': u'templateid', u'required': True, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the template for the virtual machine'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'availability zone for the virtual machine'}, {u'name': u'group', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional group for the virtual machine'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'host name for the virtual machine'}, {u'name': u'startvm', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network offering supports specifying ip ranges; defaulted to true if not specified'}], u'requiredparams': [u'serviceofferingid', u'templateid', u'zoneid'], u'description': u'Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.'}}, u'restart': {u'network': {u'name': u'restartNetwork', u'related': [u'associateIpAddress'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The id of the network to restart.'}, {u'name': u'cleanup', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'If cleanup old network elements'}], u'requiredparams': [u'id'], u'description': u'Restarts the network; includes 1) restarting network elements - virtual routers, dhcp servers 2) reapplying all public ips 3) reapplying loadBalancing/portForwarding rules'}, u'vpc': {u'name': u'restartVPC', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': False, u'related': [u'restartVPC'], u'length': 255, u'type': u'uuid', u'description': u'the id of the VPC'}], u'requiredparams': [], u'description': u'Restarts a VPC'}}, u'reboot': {u'systemvm': {u'name': u'rebootSystemVm', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'rebootSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system virtual machine'}], u'requiredparams': [u'id'], u'description': u'Reboots a system VM.'}, u'router': {u'name': u'rebootRouter', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'rebootRouter'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the router'}], u'requiredparams': [u'id'], u'description': u'Starts a router.'}, u'virtualmachine': {u'name': u'rebootVirtualMachine', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Reboots a virtual machine.'}}, u'mark': {u'defaultzoneforaccount': {u'name': u'markDefaultZoneForAccount', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': True, u'related': [u'markDefaultZoneForAccount'], u'length': 255, u'type': u'string', u'description': u'Name of the account that is to be marked.'}, {u'name': u'domainid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Marks the account that belongs to the specified domain.'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The Zone ID with which the account is to be marked.'}], u'requiredparams': [u'account', u'domainid', u'zoneid'], u'description': u'Marks a default zone for this account'}}, u'start': {u'systemvm': {u'name': u'startSystemVm', u'related': [u'rebootSystemVm', u'listSystemVms', u'changeServiceForSystemVm'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startSystemVm', u'rebootSystemVm', u'listSystemVms', u'changeServiceForSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system virtual machine'}], u'requiredparams': [u'id'], u'description': u'Starts a system virtual machine.'}, u'router': {u'name': u'startRouter', u'related': [u'destroyRouter', u'rebootRouter'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'destroyRouter', u'rebootRouter', u'startRouter'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the router'}], u'requiredparams': [u'id'], u'description': u'Starts a router.'}, u'virtualmachine': {u'name': u'startVirtualMachine', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'hostid', u'required': False, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'destination Host ID to deploy the VM to - parameter available for root admin only'}], u'requiredparams': [u'id'], u'description': u'Starts a virtual machine.'}}, u'add': {u'trafficmonitor': {u'name': u'addTrafficMonitor', u'related': [u'listTrafficMonitors'], u'isasync': False, u'params': [{u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the traffic monitor Host'}, {u'name': u'includezones', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Traffic going into the listed zones will be metered'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'Zone in which to add the external firewall appliance.'}, {u'name': u'excludezones', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Traffic going into the listed zones will not be metered'}], u'requiredparams': [u'url', u'zoneid'], u'description': u'Adds Traffic Monitor Host for Direct Network Usage'}, u'secondarystorage': {u'name': u'addSecondaryStorage', u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the secondary storage'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL for the secondary storage'}], u'requiredparams': [u'url'], u'description': u'Adds secondary storage.'}, u'nictovirtualmachine': {u'name': u'addNicToVirtualMachine', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'networkid', u'required': True, u'related': [u'createNetwork', u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'Network ID'}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'IP Address for the new network'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'addNicToVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Virtual Machine ID'}], u'requiredparams': [u'networkid', u'virtualmachineid'], u'description': u'Adds VM to specified network by creating a NIC'}, u'netscalerloadbalancer': {u'name': u'addNetscalerLoadBalancer', u'related': [u'listNetscalerLoadBalancers', u'configureNetscalerLoadBalancer'], u'isasync': True, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach netscaler load balancer device'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach netscaler load balancer device'}, {u'name': u'networkdevicetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Netscaler device type supports NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the netscaler load balancer appliance.'}], u'requiredparams': [u'password', u'physicalnetworkid', u'username', u'networkdevicetype', u'url'], u'description': u'Adds a netscaler load balancer device'}, u'cluster': {u'name': u'addCluster', u'related': [u'listClusters', u'updateCluster'], u'isasync': False, u'params': [{u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this cluster for allocation of new resources'}, {u'name': u'vsmpassword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the password for the VSM associated with this cluster'}, {u'name': u'podid', u'required': True, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the host'}, {u'name': u'vsmipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ipaddress of the VSM associated with this cluster'}, {u'name': u'hypervisor', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the cluster: XenServer,KVM,VMware,Hyperv,BareMetal,Simulator'}, {u'name': u'vsmusername', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the VSM associated with this cluster'}, {u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the cluster'}, {u'name': u'clustertype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of the cluster: CloudManaged, ExternalManaged'}, {u'name': u'clustername', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the cluster name'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the cluster'}, {u'name': u'password', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the password for the host'}], u'requiredparams': [u'podid', u'hypervisor', u'clustertype', u'clustername', u'zoneid'], u'description': u'Adds a new cluster'}, u's3': {u'name': u'addS3', u'related': [], u'isasync': False, u'params': [{u'name': u'connectiontimeout', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'connection timeout (milliseconds)'}, {u'name': u'accesskey', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'S3 access key'}, {u'name': u'bucket', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the template storage bucket'}, {u'name': u'endpoint', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'S3 host name'}, {u'name': u'secretkey', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'S3 secret key'}, {u'name': u'sockettimeout', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'socket timeout (milliseconds)'}, {u'name': u'maxerrorretry', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'maximum number of times to retry on error'}, {u'name': u'usehttps', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'connect to the S3 endpoint via HTTPS?'}], u'requiredparams': [u'accesskey', u'bucket', u'secretkey'], u'description': u'Adds S3'}, u'accounttoproject': {u'name': u'addAccountToProject', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the account to be added to the project'}, {u'name': u'email', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'email to which invitation to the project is going to be sent'}, {u'name': u'projectid', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to add the account to'}], u'requiredparams': [u'projectid'], u'description': u'Adds acoount to a project'}, u'region': {u'name': u'addRegion', u'related': [], u'isasync': False, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the region'}, {u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Id of the Region'}, {u'name': u'endpoint', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Region service endpoint'}], u'requiredparams': [u'name', u'id', u'endpoint'], u'description': u'Adds a Region'}, u'externalloadbalancer': {u'name': u'addExternalLoadBalancer', u'related': [], u'isasync': False, u'params': [{u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Username of the external load balancer appliance.'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the external load balancer appliance.'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Password of the external load balancer appliance.'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'Zone in which to add the external load balancer appliance.'}], u'requiredparams': [u'username', u'url', u'password', u'zoneid'], u'description': u'Adds F5 external load balancer appliance.'}, u'vpnuser': {u'name': u'addVpnUser', u'related': [u'listVpnUsers'], u'isasync': True, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'password for the username'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'username for the vpn user'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the vpn user. Must be used with domainId.'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the vpn user. If the account parameter is used, domainId must also be used.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'add vpn user to the specific project'}], u'requiredparams': [u'password', u'username'], u'description': u'Adds vpn users'}, u'baremetalhost': {u'name': u'addBaremetalHost', u'related': [u'listSwifts', u'addHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'isasync': False, u'params': [{u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'ip address intentionally allocated to this host after provisioning'}, {u'name': u'hosttags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of tags to be added to the host'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the host URL'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the host'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the host'}, {u'name': u'clustername', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the cluster name for the host'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID for the host'}, {u'name': u'hypervisor', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the host'}, {u'name': u'podid', u'required': True, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the host'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the password for the host'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this Host for allocation of new resources'}], u'requiredparams': [u'url', u'username', u'zoneid', u'hypervisor', u'podid', u'password'], u'description': u'add a baremetal host'}, u'traffictype': {u'name': u'addTrafficType', u'related': [u'updateTrafficType'], u'isasync': True, u'params': [{u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The VLAN id to be used for Management traffic by VMware host'}, {u'name': u'kvmnetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a KVM host'}, {u'name': u'traffictype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the trafficType to be added to the physical network'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'vmwarenetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a VMware host'}, {u'name': u'xennetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a XenServer host'}], u'requiredparams': [u'traffictype', u'physicalnetworkid'], u'description': u'Adds traffic type to a physical network'}, u'niciranvpdevice': {u'name': u'addNiciraNvpDevice', u'related': [], u'isasync': True, u'params': [{u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'hostname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hostname of ip address of the Nicira NVP Controller.'}, {u'name': u'l3gatewayserviceuuid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The L3 Gateway Service UUID configured on the Nicira Controller'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to access the Nicira Controller API'}, {u'name': u'transportzoneuuid', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'The Transportzone UUID configured on the Nicira Controller'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to access the Nicira Controller API'}], u'requiredparams': [u'physicalnetworkid', u'hostname', u'username', u'transportzoneuuid', u'password'], u'description': u'Adds a Nicira NVP device'}, u'host': {u'name': u'addHost', u'related': [u'updateHost', u'listHosts'], u'isasync': False, u'params': [{u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the host'}, {u'name': u'podid', u'required': True, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the host'}, {u'name': u'clustername', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the cluster name for the host'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the host'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the host URL'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID for the host'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the password for the host'}, {u'name': u'hosttags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of tags to be added to the host'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this Host for allocation of new resources'}, {u'name': u'hypervisor', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the host'}], u'requiredparams': [u'username', u'podid', u'zoneid', u'url', u'password', u'hypervisor'], u'description': u'Adds a new host.'}, u'f5loadbalancer': {u'name': u'addF5LoadBalancer', u'related': [u'configureF5LoadBalancer', u'listF5LoadBalancers'], u'isasync': True, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach F5 BigIP load balancer device'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach F5 BigIP load balancer device'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'networkdevicetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'supports only F5BigIpLoadBalancer'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the F5 load balancer appliance.'}], u'requiredparams': [u'password', u'username', u'physicalnetworkid', u'networkdevicetype', u'url'], u'description': u'Adds a F5 BigIP load balancer device'}, u'networkdevice': {u'name': u'addNetworkDevice', u'related': [], u'isasync': False, u'params': [{u'name': u'networkdevicetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network device type, now supports ExternalDhcp, PxeServer, NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer, F5BigIpLoadBalancer, JuniperSRXFirewall'}, {u'name': u'networkdeviceparameterlist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'parameters for network device'}], u'requiredparams': [], u'description': u'Adds a network device of one of the following types: ExternalDhcp, ExternalFirewall, ExternalLoadBalancer, PxeServer'}, u'bigswitchvnsdevice': {u'name': u'addBigSwitchVnsDevice', u'related': [], u'isasync': True, u'params': [{u'name': u'physicalnetworkid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'hostname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hostname of ip address of the BigSwitch VNS Controller.'}], u'requiredparams': [u'physicalnetworkid', u'hostname'], u'description': u'Adds a BigSwitch VNS device'}, u'srxfirewall': {u'name': u'addSrxFirewall', u'related': [], u'isasync': True, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach SRX firewall device'}, {u'name': u'networkdevicetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'supports only JuniperSRXFirewall'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach SRX firewall device'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the SRX appliance.'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}], u'requiredparams': [u'password', u'networkdevicetype', u'username', u'url', u'physicalnetworkid'], u'description': u'Adds a SRX firewall device'}, u'swift': {u'name': u'addSwift', u'related': [u'listSwifts', u'addHost', u'updateHost', u'listHosts', u'listExternalLoadBalancers'], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account for swift'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL for swift'}, {u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for swift'}, {u'name': u'key', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u' key for the user for swift'}], u'requiredparams': [u'url'], u'description': u'Adds Swift.'}, u'externalfirewall': {u'name': u'addExternalFirewall', u'related': [], u'isasync': False, u'params': [{u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the external firewall appliance.'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Password of the external firewall appliance.'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Zone in which to add the external firewall appliance.'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Username of the external firewall appliance.'}], u'requiredparams': [u'url', u'password', u'zoneid', u'username'], u'description': u'Adds an external firewall appliance'}, u'networkserviceprovider': {u'name': u'addNetworkServiceProvider', u'related': [u'updateNetworkServiceProvider'], u'isasync': True, u'params': [{u'name': u'destinationphysicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the destination Physical Network ID to bridge to'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name for the physical network service provider'}, {u'name': u'servicelist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the list of services to be enabled for this physical network service provider'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID to add the provider to'}], u'requiredparams': [u'name', u'physicalnetworkid'], u'description': u'Adds a network serviceProvider to a physical network'}}, u'verbs': [u'authorize', u'restore', u'suspend', u'revoke', u'disassociate', u'migrate', u'lock', u'dissociate', u'activate', u'reconnect', u'cancel', u'query', u'recover', u'extract', u'detach', u'prepare', u'start', u'create', u'associate', u'reboot', u'mark', u'attach', u'add', u'change', u'deploy', u'ldap', u'destroy', u'enable', u'configure', u'get', u'modify', u'stop', u'update', u'disable', u'resize', u'copy', u'generate', u'restart', u'reset', u'register', u'list', u'upload', u'remove', u'assign', u'delete'], u'resize': {u'volume': {u'name': u'resizeVolume', u'related': [u'detachVolume', u'uploadVolume', u'createVolume'], u'isasync': True, u'params': [{u'name': u'diskofferingid', u'required': False, u'related': [u'updateDiskOffering', u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'new disk offering id'}, {u'name': u'id', u'required': False, u'related': [u'detachVolume', u'resizeVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'shrinkok', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Verify OK to Shrink'}, {u'name': u'size', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'New volume size in G'}], u'requiredparams': [], u'description': u'Resizes a volume'}}, u'ldap': {u'config': {u'name': u'ldapConfig', u'related': [u'ldapRemove'], u'isasync': False, u'params': [{u'name': u'hostname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hostname or ip address of the ldap server eg: my.ldap.com'}, {u'name': u'ssl', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Check Use SSL if the external LDAP server is configured for LDAP over SSL.'}, {u'name': u'truststore', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enter the path to trust certificates store.'}, {u'name': u'queryfilter', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'You specify a query filter here, which narrows down the users, who can be part of this domain.'}, {u'name': u'searchbase', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com.'}, {u'name': u'port', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Specify the LDAP port if required, default is 389.'}, {u'name': u'binddn', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specify the distinguished name of a user with the search permission on the directory.'}, {u'name': u'truststorepass', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enter the password for trust store.'}, {u'name': u'bindpass', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enter the password.'}], u'requiredparams': [u'hostname', u'queryfilter', u'searchbase'], u'description': u'Configure the LDAP context for this site.'}, u'remove': {u'name': u'ldapRemove', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'Remove the LDAP context for this site.'}}, u'destroy': {u'systemvm': {u'name': u'destroySystemVm', u'related': [u'startSystemVm', u'rebootSystemVm', u'listSystemVms', u'stopSystemVm', u'changeServiceForSystemVm'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startSystemVm', u'destroySystemVm', u'rebootSystemVm', u'listSystemVms', u'stopSystemVm', u'changeServiceForSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system virtual machine'}], u'requiredparams': [u'id'], u'description': u'Destroyes a system virtual machine.'}, u'router': {u'name': u'destroyRouter', u'related': [u'rebootRouter'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'destroyRouter', u'rebootRouter'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the router'}], u'requiredparams': [u'id'], u'description': u'Destroys a router.'}, u'volumeonfiler': {u'name': u'destroyVolumeOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'volumename', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'volume name.'}, {u'name': u'ipaddress', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'ip address.'}, {u'name': u'aggregatename', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'aggregate name.'}], u'requiredparams': [u'volumename', u'ipaddress', u'aggregatename'], u'description': u'Destroy a Volume'}, u'lunonfiler': {u'name': u'destroyLunOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'path', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'LUN path.'}], u'requiredparams': [u'path'], u'description': u'Destroy a LUN'}, u'virtualmachine': {u'name': u'destroyVirtualMachine', u'related': [u'listVirtualMachines'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listVirtualMachines', u'destroyVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Destroys a virtual machine. Once destroyed, only the administrator can recover it.'}}, u'get': {u'apilimit': {u'name': u'getApiLimit', u'related': [u'resetApiLimit'], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'Get API limit count for the caller'}, u'vmpassword': {u'name': u'getVMPassword', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Returns an encrypted password for the VM'}, u'user': {u'name': u'getUser', u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser', u'updateUser'], u'isasync': False, u'params': [{u'name': u'userapikey', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'API key of the user'}], u'requiredparams': [u'userapikey'], u'description': u'Find user account by API key'}, u'cloudidentifier': {u'name': u'getCloudIdentifier', u'related': [], u'isasync': False, u'params': [{u'name': u'userid', u'required': True, u'related': [u'lockUser', u'listUsers', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'the user ID for the cloud identifier'}], u'requiredparams': [u'userid'], u'description': u'Retrieves a cloud identifier.'}}, u'count': 355, u'enable': {u'account': {u'name': u'enableAccount', u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount', u'disableAccount'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'Enables specified account in this domain.'}, {u'name': u'id', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount', u'enableAccount', u'disableAccount'], u'length': 255, u'type': u'uuid', u'description': u'Account id'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enables specified account.'}], u'requiredparams': [], u'description': u'Enables an account'}, u'storagemaintenance': {u'name': u'enableStorageMaintenance', u'related': [u'cancelStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'cancelStorageMaintenance', u'enableStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'length': 255, u'type': u'uuid', u'description': u'Primary storage ID'}], u'requiredparams': [u'id'], u'description': u'Puts storage pool into maintenance state'}, u'cisconexusvsm': {u'name': u'enableCiscoNexusVSM', u'related': [u'disableCiscoNexusVSM'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableCiscoNexusVSM', u'enableCiscoNexusVSM'], u'length': 255, u'type': u'uuid', u'description': u'Id of the Cisco Nexus 1000v VSM device to be enabled'}], u'requiredparams': [u'id'], u'description': u'Enable a Cisco Nexus VSM device'}, u'staticnat': {u'name': u'enableStaticNat', u'related': [], u'isasync': False, u'params': [{u'name': u'ipaddressid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the public IP address id for which static nat feature is being enabled'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine for enabling static nat feature'}, {u'name': u'networkid', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The network of the vm the static nat will be enabled for. Required when public Ip address is not associated with any Guest network yet (VPC case)'}], u'requiredparams': [u'ipaddressid', u'virtualmachineid'], u'description': u'Enables static nat for given ip address'}, u'user': {u'name': u'enableUser', u'related': [u'lockUser', u'listUsers', u'createUser'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'Enables user by user ID.'}], u'requiredparams': [u'id'], u'description': u'Enables a user account'}, u'autoscalevmgroup': {u'name': u'enableAutoScaleVmGroup', u'related': [u'createAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale group'}], u'requiredparams': [u'id'], u'description': u'Enables an AutoScale Vm Group'}}, u'configure': {u'srxfirewall': {u'name': u'configureSrxFirewall', u'related': [u'listSrxFirewalls', u'addSrxFirewall'], u'isasync': True, u'params': [{u'name': u'fwdeviceid', u'required': True, u'related': [u'listSrxFirewalls', u'configureSrxFirewall', u'addSrxFirewall'], u'length': 255, u'type': u'uuid', u'description': u'SRX firewall device ID'}, {u'name': u'fwdevicecapacity', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'capacity of the firewall device, Capacity will be interpreted as number of networks device can handle'}], u'requiredparams': [u'fwdeviceid'], u'description': u'Configures a SRX firewall device'}, u'f5loadbalancer': {u'name': u'configureF5LoadBalancer', u'related': [], u'isasync': True, u'params': [{u'name': u'lbdeviceid', u'required': True, u'related': [u'configureF5LoadBalancer'], u'length': 255, u'type': u'uuid', u'description': u'F5 load balancer device ID'}, {u'name': u'lbdevicecapacity', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'capacity of the device, Capacity will be interpreted as number of networks device can handle'}], u'requiredparams': [u'lbdeviceid'], u'description': u'configures a F5 load balancer device'}, u'netscalerloadbalancer': {u'name': u'configureNetscalerLoadBalancer', u'related': [u'listNetscalerLoadBalancers'], u'isasync': True, u'params': [{u'name': u'podids', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'list', u'description': u"Used when NetScaler device is provider of EIP service. This parameter represents the list of pod's, for which there exists a policy based route on datacenter L3 router to route pod's subnet IP to a NetScaler device."}, {u'name': u'lbdevicecapacity', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'capacity of the device, Capacity will be interpreted as number of networks device can handle'}, {u'name': u'lbdeviceid', u'required': True, u'related': [u'listNetscalerLoadBalancers', u'configureNetscalerLoadBalancer'], u'length': 255, u'type': u'uuid', u'description': u'Netscaler load balancer device ID'}, {u'name': u'inline', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if netscaler load balancer is intended to be used in in-line with firewall, false if netscaler load balancer will side-by-side with firewall'}, {u'name': u'lbdevicededicated', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this netscaler device to dedicated for a account, false if the netscaler device will be shared by multiple accounts'}], u'requiredparams': [u'lbdeviceid'], u'description': u'configures a netscaler load balancer device'}, u'virtualrouterelement': {u'name': u'configureVirtualRouterElement', u'related': [u'createVirtualRouterElement'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createVirtualRouterElement', u'configureVirtualRouterElement'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual router provider'}, {u'name': u'enabled', u'required': True, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Enabled/Disabled the service provider'}], u'requiredparams': [u'id', u'enabled'], u'description': u'Configures a virtual router element.'}}, u'associate': {u'ipaddress': {u'name': u'associateIpAddress', u'related': [], u'isasync': True, u'params': [{u'name': u'networkid', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The network this ip address should be associated to.'}, {u'name': u'vpcid', u'required': False, u'related': [u'restartVPC', u'listVPCs'], u'length': 255, u'type': u'uuid', u'description': u'the VPC you want the ip address to be associated with'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account to associate with this IP address'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the availability zone you want to acquire an public IP address from'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'Deploy vm for the project'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain to associate with this IP address'}], u'requiredparams': [], u'description': u'Acquires and associates a public IP to an account.'}, u'lun': {u'name': u'associateLun', u'related': [], u'isasync': False, u'params': [{u'name': u'iqn', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Guest IQN to which the LUN associate.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'LUN name.'}], u'requiredparams': [u'iqn', u'name'], u'description': u'Associate a LUN with a guest IQN'}}, u'stop': {u'systemvm': {u'name': u'stopSystemVm', u'related': [u'startSystemVm', u'rebootSystemVm', u'listSystemVms', u'changeServiceForSystemVm'], u'isasync': True, u'params': [{u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force stop the VM. The caller knows the VM is stopped.'}, {u'name': u'id', u'required': True, u'related': [u'startSystemVm', u'rebootSystemVm', u'listSystemVms', u'stopSystemVm', u'changeServiceForSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system virtual machine'}], u'requiredparams': [u'id'], u'description': u'Stops a system VM.'}, u'router': {u'name': u'stopRouter', u'related': [u'changeServiceForRouter', u'destroyRouter', u'rebootRouter', u'startRouter'], u'isasync': True, u'params': [{u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force stop the VM. The caller knows the VM is stopped.'}, {u'name': u'id', u'required': True, u'related': [u'changeServiceForRouter', u'stopRouter', u'destroyRouter', u'rebootRouter', u'startRouter'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the router'}], u'requiredparams': [u'id'], u'description': u'Stops a router.'}, u'virtualmachine': {u'name': u'stopVirtualMachine', u'related': [u'listVirtualMachines', u'destroyVirtualMachine'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force stop the VM (vm is marked as Stopped even when command fails to be send to the backend). The caller knows the VM is stopped.'}], u'requiredparams': [u'id'], u'description': u'Stops a virtual machine.'}}, u'modify': {u'pool': {u'name': u'modifyPool', u'related': [], u'isasync': False, u'params': [{u'name': u'algorithm', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'algorithm.'}, {u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'algorithm', u'poolname'], u'description': u'Modify pool'}}, u'update': {u'loadbalancerrule': {u'name': u'updateLoadBalancerRule', u'related': [], u'isasync': True, u'params': [{u'name': u'description', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the description of the load balancer rule'}, {u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id of the load balancer rule to update'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the load balancer rule'}, {u'name': u'algorithm', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'load balancer algorithm (source, roundrobin, leastconn)'}], u'requiredparams': [u'id'], u'description': u'Updates load balancer'}, u'domain': {u'name': u'updateDomain', u'related': [u'listDomainChildren', u'createDomain'], u'isasync': False, u'params': [{u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"Network domain for the domain's networks; empty string will update domainName with NULL value"}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'updates domain with this name'}, {u'name': u'id', u'required': True, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'ID of domain to update'}], u'requiredparams': [u'id'], u'description': u'Updates a domain with a new name'}, u'projectinvitation': {u'name': u'updateProjectInvitation', u'related': [], u'isasync': True, u'params': [{u'name': u'accept', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, accept the invitation, decline if false. True by default'}, {u'name': u'projectid', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to join'}, {u'name': u'token', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list invitations for specified account; this parameter has to be specified with domainId'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'account that is joining the project'}], u'requiredparams': [u'projectid'], u'description': u'Accepts or declines project invitation'}, u'diskoffering': {u'name': u'updateDiskOffering', u'related': [u'createDiskOffering', u'listDiskOfferings'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateDiskOffering', u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'ID of the disk offering'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'updates alternate display text of the disk offering with this value'}, {u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the disk offering, integer'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'updates name of the disk offering with this value'}], u'requiredparams': [u'id'], u'description': u'Updates a disk offering.'}, u'virtualmachine': {u'name': u'updateVirtualMachine', u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'displayname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'user generated name'}, {u'name': u'group', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'group of the virtual machine'}, {u'name': u'haenable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if high-availability is enabled for the virtual machine, false otherwise'}, {u'name': u'id', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'ostypeid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS type that best represents this VM.'}, {u'name': u'userdata', u'required': False, u'related': [], u'length': 2048, u'type': u'string', u'description': u'an optional binary data that can be sent to the virtual machine upon a successful deployment. This binary data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. Using HTTP GET (via querystring), you can send up to 2KB of data after base64 encoding.'}], u'requiredparams': [u'id'], u'description': u'Updates properties of a virtual machine. The VM has to be stopped and restarted for the new properties to take effect. UpdateVirtualMachine does not first check whether the VM is stopped. Therefore, stop the VM manually before issuing this call.'}, u'portforwardingrule': {u'name': u'updatePortForwardingRule', u'related': [u'listIpForwardingRules', u'listPortForwardingRules', u'createPortForwardingRule'], u'isasync': True, u'params': [{u'name': u'privateport', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the private port of the port forwarding rule'}, {u'name': u'publicport', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the public port of the port forwarding rule'}, {u'name': u'privateip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the private IP address of the port forwarding rule'}, {u'name': u'ipaddressid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the IP address id of the port forwarding rule'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the port fowarding rule. Valid values are TCP or UDP.'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine for the port forwarding rule'}], u'requiredparams': [u'privateport', u'publicport', u'ipaddressid', u'protocol'], u'description': u'Updates a port forwarding rule. Only the private port and the virtual machine can be updated.'}, u'cluster': {u'name': u'updateCluster', u'related': [], u'isasync': False, u'params': [{u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the cluster'}, {u'name': u'id', u'required': True, u'related': [u'updateCluster'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Cluster'}, {u'name': u'managedstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'whether this cluster is managed by cloudstack'}, {u'name': u'clustername', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the cluster name'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this cluster for allocation of new resources'}, {u'name': u'clustertype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the cluster'}], u'requiredparams': [u'id'], u'description': u'Updates an existing cluster'}, u'hostpassword': {u'name': u'updateHostPassword', u'related': [], u'isasync': False, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the new password for the host/cluster'}, {u'name': u'hostid', u'required': False, u'related': [u'listSwifts', u'addHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the host/cluster'}], u'requiredparams': [u'password', u'username'], u'description': u'Update password of a host/pool on management server.'}, u'pod': {u'name': u'updatePod', u'related': [], u'isasync': False, u'params': [{u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address for the Pod'}, {u'name': u'gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway for the Pod'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this cluster for allocation of new resources'}, {u'name': u'id', u'required': True, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Pod'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the Pod'}, {u'name': u'startip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the starting IP address for the Pod'}, {u'name': u'netmask', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask of the Pod'}], u'requiredparams': [u'id'], u'description': u'Updates a Pod.'}, u'isopermissions': {u'name': u'updateIsoPermissions', u'related': [], u'isasync': False, u'params': [{u'name': u'isextractable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template/iso is extractable, false other wise. Can be set only by root admin'}, {u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true for featured template/iso, false otherwise'}, {u'name': u'accounts', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'a comma delimited list of accounts. If specified, "op" parameter has to be passed in.'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true for public template/iso, false for private templates/isos'}, {u'name': u'projectids', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'list', u'description': u'a comma delimited list of projects. If specified, "op" parameter has to be passed in.'}, {u'name': u'op', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'permission operator (add, remove, reset)'}, {u'name': u'id', u'required': True, u'related': [u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}], u'requiredparams': [u'id'], u'description': u'Updates iso permissions'}, u'resourcelimit': {u'name': u'updateResourceLimit', u'related': [], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Update resource for a specified account. Must be used with the domainId parameter.'}, {u'name': u'resourcetype', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Type of resource to update. Values are 0, 1, 2, 3, and 4. 0 - Instance. Number of instances a user can create. 1 - IP. Number of public IP addresses a user can own. 2 - Volume. Number of disk volumes a user can create.3 - Snapshot. Number of snapshots a user can create.4 - Template. Number of templates that a user can register/create.'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Update resource limits for all accounts in specified domain. If used with the account parameter, updates resource limits for a specified account in specified domain.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Update resource limits for project'}, {u'name': u'max', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u' Maximum resource limit.'}], u'requiredparams': [u'resourcetype'], u'description': u'Updates resource limits for an account or domain.'}, u'vpcoffering': {u'name': u'updateVPCOffering', u'related': [u'listVPCOfferings', u'createVPCOffering'], u'isasync': True, u'params': [{u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the VPC offering'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'update state for the VPC offering; supported states - Enabled/Disabled'}, {u'name': u'id', u'required': False, u'related': [u'listVPCOfferings', u'createVPCOffering', u'updateVPCOffering'], u'length': 255, u'type': u'uuid', u'description': u'the id of the VPC offering'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the VPC offering'}], u'requiredparams': [], u'description': u'Updates VPC offering'}, u'network': {u'name': u'updateNetwork', u'related': [u'listNetscalerLoadBalancerNetworks'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network'}, {u'name': u'networkofferingid', u'required': False, u'related': [u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'network offering ID'}, {u'name': u'changecidr', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force update even if cidr type is different'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the new name for the network'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the new display text for the network'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'network domain'}], u'requiredparams': [u'id'], u'description': u'Updates a network'}, u'zone': {u'name': u'updateZone', u'related': [u'listZones', u'createZone'], u'isasync': False, u'params': [{u'name': u'internaldns1', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first internal DNS for the Zone'}, {u'name': u'dnssearchorder', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the dns search order list'}, {u'name': u'internaldns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second internal DNS for the Zone'}, {u'name': u'domain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network domain name for the networks in the zone; empty string will update domain with NULL value'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'the details for the Zone'}, {u'name': u'ip6dns1', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first DNS for IPv6 network in the Zone'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this cluster for allocation of new resources'}, {u'name': u'ip6dns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second DNS for IPv6 network in the Zone'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the Zone'}, {u'name': u'id', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Zone'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'updates a private zone to public if set, but not vice-versa'}, {u'name': u'dns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second DNS for the Zone'}, {u'name': u'guestcidraddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the guest CIDR address for the Zone'}, {u'name': u'dhcpprovider', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the dhcp Provider for the Zone'}, {u'name': u'dns1', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first DNS for the Zone'}, {u'name': u'localstorageenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if local storage offering enabled, false otherwise'}], u'requiredparams': [u'id'], u'description': u'Updates a Zone.'}, u'instancegroup': {u'name': u'updateInstanceGroup', u'related': [u'createInstanceGroup'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateInstanceGroup', u'createInstanceGroup'], u'length': 255, u'type': u'uuid', u'description': u'Instance group ID'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'new instance group name'}], u'requiredparams': [u'id'], u'description': u'Updates a vm group'}, u'autoscalepolicy': {u'name': u'updateAutoScalePolicy', u'related': [], u'isasync': True, u'params': [{u'name': u'duration', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the duration for which the conditions have to be true before action is taken'}, {u'name': u'id', u'required': True, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale policy'}, {u'name': u'quiettime', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the cool down period for which the policy should not be evaluated after the action has been taken'}, {u'name': u'conditionids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the list of IDs of the conditions that are being evaluated on every interval'}], u'requiredparams': [u'id'], u'description': u'Updates an existing autoscale policy.'}, u'serviceoffering': {u'name': u'updateServiceOffering', u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering'], u'isasync': False, u'params': [{u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the service offering, integer'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the service offering to be updated'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the service offering to be updated'}, {u'name': u'id', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering', u'updateServiceOffering'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the service offering to be updated'}], u'requiredparams': [u'id'], u'description': u'Updates a service offering.'}, u'storagepool': {u'name': u'updateStoragePool', u'related': [u'cancelStorageMaintenance', u'createStoragePool', u'listStoragePools'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'cancelStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'length': 255, u'type': u'uuid', u'description': u'the Id of the storage pool'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma-separated list of tags for the storage pool'}], u'requiredparams': [u'id'], u'description': u'Updates a storage pool.'}, u'hypervisorcapabilities': {u'name': u'updateHypervisorCapabilities', u'related': [], u'isasync': False, u'params': [{u'name': u'securitygroupenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'set true to enable security group for this hypervisor.'}, {u'name': u'maxguestslimit', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the max number of Guest VMs per host for this hypervisor.'}, {u'name': u'id', u'required': False, u'related': [u'listHypervisorCapabilities'], u'length': 255, u'type': u'uuid', u'description': u'ID of the hypervisor capability'}], u'requiredparams': [], u'description': u'Updates a hypervisor capabilities.'}, u'template': {u'name': u'updateTemplate', u'related': [u'registerIso', u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'bootable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if image is bootable, false otherwise'}, {u'name': u'passwordenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the image supports the password reset feature; default is false'}, {u'name': u'format', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the format for the image'}, {u'name': u'ostypeid', u'required': False, u'related': [u'listOsTypes'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS type that best represents the OS of this image.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the image file'}, {u'name': u'id', u'required': True, u'related': [u'registerIso', u'updateTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the image file'}, {u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the template, integer'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the image'}], u'requiredparams': [u'id'], u'description': u'Updates attributes of a template.'}, u'defaultnicforvirtualmachine': {u'name': u'updateDefaultNicForVirtualMachine', u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'nicid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'NIC ID'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Virtual Machine ID'}], u'requiredparams': [u'nicid', u'virtualmachineid'], u'description': u'Changes the default NIC on a VM'}, u'traffictype': {u'name': u'updateTrafficType', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateTrafficType'], u'length': 255, u'type': u'uuid', u'description': u'traffic type id'}, {u'name': u'xennetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a XenServer host'}, {u'name': u'vmwarenetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a VMware host'}, {u'name': u'kvmnetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a KVM host'}], u'requiredparams': [u'id'], u'description': u'Updates traffic type of a physical network'}, u'host': {u'name': u'updateHost', u'related': [u'listHosts'], u'isasync': False, u'params': [{u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Change resource state of host, valid values are [Enable, Disable]. Operation may failed if host in states not allowing Enable/Disable'}, {u'name': u'oscategoryid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id of Os category to update the host with'}, {u'name': u'hosttags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of tags to be added to the host'}, {u'name': u'id', u'required': True, u'related': [u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the host to update'}, {u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the new uri for the secondary storage: nfs://host/path'}], u'requiredparams': [u'id'], u'description': u'Updates a host.'}, u'user': {u'name': u'updateUser', u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser', u'updateUser'], u'length': 255, u'type': u'uuid', u'description': u'User uuid'}, {u'name': u'timezone', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.'}, {u'name': u'email', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'email'}, {u'name': u'usersecretkey', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The secret key for the user. Must be specified with userApiKey'}, {u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Unique username'}, {u'name': u'firstname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'first name'}, {u'name': u'lastname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'last name'}, {u'name': u'password', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hashed password (default is MD5). If you wish to use any other hasing algorithm, you would need to write a custom authentication adapter'}, {u'name': u'userapikey', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The API key for the user. Must be specified with userSecretKey'}], u'requiredparams': [u'id'], u'description': u'Updates a user account'}, u'vpc': {u'name': u'updateVPC', u'related': [u'restartVPC', u'listVPCs'], u'isasync': True, u'params': [{u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the VPC'}, {u'name': u'id', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs'], u'length': 255, u'type': u'uuid', u'description': u'the id of the VPC'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the VPC'}], u'requiredparams': [], u'description': u'Updates a VPC'}, u'resourcecount': {u'name': u'updateResourceCount', u'related': [], u'isasync': False, u'params': [{u'name': u'resourcetype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Type of resource to update. If specifies valid values are 0, 1, 2, 3, and 4. If not specified will update all resource counts0 - Instance. Number of instances a user can create. 1 - IP. Number of public IP addresses a user can own. 2 - Volume. Number of disk volumes a user can create.3 - Snapshot. Number of snapshots a user can create.4 - Template. Number of templates that a user can register/create.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Update resource limits for project'}, {u'name': u'domainid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'If account parameter specified then updates resource counts for a specified account in this domain else update resource counts for all accounts & child domains in specified domain.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Update resource count for a specified account. Must be used with the domainId parameter.'}], u'requiredparams': [u'domainid'], u'description': u'Recalculate and update resource count for an account or domain.'}, u'storagenetworkiprange': {u'name': u'updateStorageNetworkIpRange', u'related': [], u'isasync': True, u'params': [{u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Optional. the vlan the ip range sits on'}, {u'name': u'netmask', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask for storage network'}, {u'name': u'id', u'required': True, u'related': [u'updateStorageNetworkIpRange'], u'length': 255, u'type': u'uuid', u'description': u'UUID of storage network ip range'}, {u'name': u'startip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IP address'}], u'requiredparams': [u'id'], u'description': u'Update a Storage network IP range, only allowed when no IPs in this range have been allocated.'}, u'configuration': {u'name': u'updateConfiguration', u'related': [u'listConfigurations'], u'isasync': False, u'params': [{u'name': u'value', u'required': False, u'related': [], u'length': 4095, u'type': u'string', u'description': u'the value of the configuration'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the configuration'}], u'requiredparams': [u'name'], u'description': u'Updates a configuration.'}, u'templatepermissions': {u'name': u'updateTemplatePermissions', u'related': [], u'isasync': False, u'params': [{u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true for featured template/iso, false otherwise'}, {u'name': u'isextractable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template/iso is extractable, false other wise. Can be set only by root admin'}, {u'name': u'projectids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'a comma delimited list of projects. If specified, "op" parameter has to be passed in.'}, {u'name': u'op', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'permission operator (add, remove, reset)'}, {u'name': u'id', u'required': True, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true for public template/iso, false for private templates/isos'}, {u'name': u'accounts', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'a comma delimited list of accounts. If specified, "op" parameter has to be passed in.'}], u'requiredparams': [u'id'], u'description': u'Updates a template visibility permissions. A public template is visible to all accounts within the same domain. A private template is visible only to the owner of the template. A priviledged template is a private template with account permissions added. Only accounts specified under the template permissions are visible to them.'}, u'autoscalevmprofile': {u'name': u'updateAutoScaleVmProfile', u'related': [u'listAutoScaleVmProfiles'], u'isasync': True, u'params': [{u'name': u'expungevmgraceperiod', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the time allowed for existing connections to get closed before a vm is destroyed'}, {u'name': u'autoscaleuserid', u'required': False, u'related': [u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the user used to launch and destroy the VMs'}, {u'name': u'templateid', u'required': False, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template of the auto deployed virtual machine'}, {u'name': u'id', u'required': True, u'related': [u'updateAutoScaleVmProfile', u'listAutoScaleVmProfiles'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale vm profile'}, {u'name': u'counterparam', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'counterparam list. Example: counterparam[0].name=snmpcommunity&counterparam[0].value=public&counterparam[1].name=snmpport&counterparam[1].value=161'}], u'requiredparams': [u'id'], u'description': u'Updates an existing autoscale vm profile.'}, u'account': {u'name': u'updateAccount', u'related': [u'markDefaultZoneForAccount', u'listAccounts', u'lockAccount'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount'], u'length': 255, u'type': u'uuid', u'description': u'Account id'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain where the account exists'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"Network domain for the account's networks; empty string will update domainName with NULL value"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the current account name'}, {u'name': u'accountdetails', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'details for account used to store specific parameters'}, {u'name': u'newname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'new name for the account'}], u'requiredparams': [u'newname'], u'description': u'Updates account information for the authenticated user'}, u'networkoffering': {u'name': u'updateNetworkOffering', u'related': [], u'isasync': False, u'params': [{u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the network offering, integer'}, {u'name': u'id', u'required': False, u'related': [u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'the id of the network offering'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the network offering'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the network offering'}, {u'name': u'availability', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the availability of network offering. Default value is Required for Guest Virtual network offering; Optional for Guest Direct network offering'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'update state for the network offering'}], u'requiredparams': [], u'description': u'Updates a network offering.'}, u'vpncustomergateway': {u'name': u'updateVpnCustomerGateway', u'related': [u'createVpnCustomerGateway'], u'isasync': True, u'params': [{u'name': u'ikelifetime', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lifetime of phase 1 VPN connection to the customer gateway, in seconds'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the gateway. If used with the account parameter returns the gateway associated with the account for the specified domain.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of this customer gateway'}, {u'name': u'id', u'required': True, u'related': [u'updateVpnCustomerGateway', u'createVpnCustomerGateway'], u'length': 255, u'type': u'uuid', u'description': u'id of customer gateway'}, {u'name': u'esplifetime', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lifetime of phase 2 VPN connection to the customer gateway, in seconds'}, {u'name': u'ikepolicy', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'IKE policy of the customer gateway'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the gateway. Must be used with the domainId parameter.'}, {u'name': u'esppolicy', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'ESP policy of the customer gateway'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'public ip address id of the customer gateway'}, {u'name': u'ipsecpsk', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'IPsec Preshared-Key of the customer gateway'}, {u'name': u'dpd', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'If DPD is enabled for VPN connection'}, {u'name': u'cidrlist', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'guest cidr of the customer gateway'}], u'requiredparams': [u'id', u'ikepolicy', u'esppolicy', u'gateway', u'ipsecpsk', u'cidrlist'], u'description': u'Update site to site vpn customer gateway'}, u'region': {u'name': u'updateRegion', u'related': [u'addRegion', u'listRegions'], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'updates region with this name'}, {u'name': u'endpoint', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'updates region with this end point'}, {u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Id of region to update'}], u'requiredparams': [u'id'], u'description': u'Updates a region'}, u'project': {u'name': u'updateProject', u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to be modified'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'display text of the project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'new Admin account for the project'}], u'requiredparams': [u'id'], u'description': u'Updates a project'}, u'physicalnetwork': {u'name': u'updatePhysicalNetwork', u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'isasync': True, u'params': [{u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the VLAN for the physical network'}, {u'name': u'id', u'required': True, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'physical network id'}, {u'name': u'networkspeed', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the speed for the physical network[1G/10G]'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'Tag the physical network'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enabled/Disabled'}], u'requiredparams': [u'id'], u'description': u'Updates a physical network'}, u'iso': {u'name': u'updateIso', u'related': [u'listIsos'], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the image file'}, {u'name': u'id', u'required': True, u'related': [u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the image file'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the image'}, {u'name': u'format', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the format for the image'}, {u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the template, integer'}, {u'name': u'ostypeid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS type that best represents the OS of this image.'}, {u'name': u'passwordenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the image supports the password reset feature; default is false'}, {u'name': u'bootable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if image is bootable, false otherwise'}], u'requiredparams': [u'id'], u'description': u'Updates an ISO file.'}, u'networkserviceprovider': {u'name': u'updateNetworkServiceProvider', u'related': [], u'isasync': True, u'params': [{u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enabled/Disabled/Shutdown the physical network service provider'}, {u'name': u'id', u'required': True, u'related': [u'updateNetworkServiceProvider'], u'length': 255, u'type': u'uuid', u'description': u'network service provider id'}, {u'name': u'servicelist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the list of services to be enabled for this physical network service provider'}], u'requiredparams': [u'id'], u'description': u'Updates a network serviceProvider of a physical network'}, u'autoscalevmgroup': {u'name': u'updateAutoScaleVmGroup', u'related': [], u'isasync': True, u'params': [{u'name': u'scaledownpolicyids', u'required': False, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'list', u'description': u'list of scaledown autoscale policies'}, {u'name': u'interval', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the frequency at which the conditions have to be evaluated'}, {u'name': u'minmembers', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the minimum number of members in the vmgroup, the number of instances in the vm group will be equal to or more than this number.'}, {u'name': u'maxmembers', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the maximum number of members in the vmgroup, The number of instances in the vm group will be equal to or less than this number.'}, {u'name': u'id', u'required': True, u'related': [u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale group'}, {u'name': u'scaleuppolicyids', u'required': False, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'list', u'description': u'list of scaleup autoscale policies'}], u'requiredparams': [u'id'], u'description': u'Updates an existing autoscale vm group.'}}, u'disable': {u'account': {u'name': u'disableAccount', u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount'], u'isasync': True, u'params': [{u'name': u'lock', u'required': True, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'If true, only lock the account; else disable the account'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Disables specified account.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'Disables specified account in this domain.'}, {u'name': u'id', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount', u'disableAccount'], u'length': 255, u'type': u'uuid', u'description': u'Account id'}], u'requiredparams': [u'lock'], u'description': u'Disables an account'}, u'autoscalevmgroup': {u'name': u'disableAutoScaleVmGroup', u'related': [u'listAutoScaleVmGroups', u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listAutoScaleVmGroups', u'createAutoScaleVmGroup', u'disableAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale group'}], u'requiredparams': [u'id'], u'description': u'Disables an AutoScale Vm Group'}, u'cisconexusvsm': {u'name': u'disableCiscoNexusVSM', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableCiscoNexusVSM'], u'length': 255, u'type': u'uuid', u'description': u'Id of the Cisco Nexus 1000v VSM device to be deleted'}], u'requiredparams': [u'id'], u'description': u'disable a Cisco Nexus VSM device'}, u'staticnat': {u'name': u'disableStaticNat', u'related': [], u'isasync': True, u'params': [{u'name': u'ipaddressid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the public IP address id for which static nat feature is being disableed'}], u'requiredparams': [u'ipaddressid'], u'description': u'Disables static rule for given ip address'}, u'user': {u'name': u'disableUser', u'related': [u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'Disables user by user ID.'}], u'requiredparams': [u'id'], u'description': u'Disables a user account'}}, u'detach': {u'volume': {u'name': u'detachVolume', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': False, u'related': [u'detachVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'deviceid', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the device ID on the virtual machine where volume is detached from'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'listVirtualMachines'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine where the volume is detached from'}], u'requiredparams': [], u'description': u'Detaches a disk volume from a virtual machine.'}, u'iso': {u'name': u'detachIso', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'virtualmachineid', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'virtualmachineid'], u'description': u'Detaches any ISO file (if any) currently attached to a virtual machine.'}}, u'generate': {u'usagerecords': {u'name': u'generateUsageRecords', u'related': [], u'isasync': False, u'params': [{u'name': u'enddate', u'required': True, u'related': [], u'length': 255, u'type': u'date', u'description': u'End date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'List events for the specified domain.'}, {u'name': u'startdate', u'required': True, u'related': [], u'length': 255, u'type': u'date', u'description': u'Start date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.'}], u'requiredparams': [u'enddate', u'startdate'], u'description': u'Generates usage records. This will generate records only if there any records to be generated, i.e if the scheduled usage job was not run or failed'}}, u'change': {u'serviceforvirtualmachine': {u'name': u'changeServiceForVirtualMachine', u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the service offering ID to apply to the virtual machine'}], u'requiredparams': [u'id', u'serviceofferingid'], u'description': u'Changes the service offering for a virtual machine. The virtual machine must be in a "Stopped" state for this command to take effect.'}, u'serviceforsystemvm': {u'name': u'changeServiceForSystemVm', u'related': [u'rebootSystemVm', u'listSystemVms'], u'isasync': False, u'params': [{u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering'], u'length': 255, u'type': u'uuid', u'description': u'the service offering ID to apply to the system vm'}, {u'name': u'id', u'required': True, u'related': [u'rebootSystemVm', u'listSystemVms', u'changeServiceForSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system vm'}], u'requiredparams': [u'serviceofferingid', u'id'], u'description': u'Changes the service offering for a system vm (console proxy or secondary storage). The system vm must be in a "Stopped" state for this command to take effect.'}, u'serviceforrouter': {u'name': u'changeServiceForRouter', u'related': [u'destroyRouter', u'rebootRouter', u'startRouter'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'changeServiceForRouter', u'destroyRouter', u'rebootRouter', u'startRouter'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the router'}, {u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering', u'updateServiceOffering'], u'length': 255, u'type': u'uuid', u'description': u'the service offering ID to apply to the domain router'}], u'requiredparams': [u'id', u'serviceofferingid'], u'description': u'Upgrades domain router to a new service offering'}}, u'reset': {u'apilimit': {u'name': u'resetApiLimit', u'related': [], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the acount whose limit to be reset'}], u'requiredparams': [], u'description': u'Reset api count'}, u'sshkeyforvirtualmachine': {u'name': u'resetSSHKeyForVirtualMachine', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'an optional project for the ssh key'}, {u'name': u'keypair', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the ssh key pair used to login to the virtual machine'}, {u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the ssh key. Must be used with domainId.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.'}], u'requiredparams': [u'keypair', u'id'], u'description': u'Resets the SSH Key for virtual machine. The virtual machine must be in a "Stopped" state. [async]'}, u'passwordforvirtualmachine': {u'name': u'resetPasswordForVirtualMachine', u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Resets the password for virtual machine. The virtual machine must be in a "Stopped" state and the template must already support this feature for this command to take effect. [async]'}, u'vpnconnection': {u'name': u'resetVpnConnection', u'related': [u'listVpnConnections'], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for connection. Must be used with domainId.'}, {u'name': u'id', u'required': True, u'related': [u'listVpnConnections', u'resetVpnConnection'], u'length': 255, u'type': u'uuid', u'description': u'id of vpn connection'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for connection. If the account parameter is used, domainId must also be used.'}], u'requiredparams': [u'id'], u'description': u'Reset site to site vpn connection'}}, u'register': {u'userkeys': {u'name': u'registerUserKeys', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'User id'}], u'requiredparams': [u'id'], u'description': u'This command allows a user to register for the developer API, returning a secret key and an API key. This request is made through the integration API port, so it is a privileged command and must be made on behalf of a user. It is up to the implementer just how the username and password are entered, and then how that translates to an integration API request. Both secret key and API key should be returned to the user'}, u'iso': {u'name': u'registerIso', u'related': [u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'ostypeid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS Type that best represents the OS of this ISO. If the iso is bootable this parameter needs to be passed'}, {u'name': u'checksum', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the MD5 checksum value of this ISO'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the ISO'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId. If the account parameter is used, domainId must also be used.'}, {u'name': u'bootable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this ISO is bootable. If not passed explicitly its assumed to be true'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'Register iso for the project'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if you want to register the ISO to be publicly available to all users, false otherwise.'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone you wish to register the ISO to.'}, {u'name': u'isextractable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the iso or its derivatives are extractable; default is false'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the ISO. This is usually used for display purposes.'}, {u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if you want this ISO to be featured'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL to where the ISO is currently being hosted'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account name. Must be used with domainId.'}], u'requiredparams': [u'name', u'zoneid', u'displaytext', u'url'], u'description': u'Registers an existing ISO into the CloudStack Cloud.'}, u'sshkeypair': {u'name': u'registerSSHKeyPair', u'related': [u'createSSHKeyPair', u'listSSHKeyPairs'], u'isasync': False, u'params': [{u'name': u'publickey', u'required': True, u'related': [], u'length': 5120, u'type': u'string', u'description': u'Public key material of the keypair'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the ssh key. If the account parameter is used, domainId must also be used.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the keypair'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'an optional project for the ssh key'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the ssh key. Must be used with domainId.'}], u'requiredparams': [u'publickey', u'name'], u'description': u'Register a public key in a keypair under a certain name'}, u'template': {u'name': u'registerTemplate', u'related': [u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'isextractable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template or its derivatives are extractable; default is false'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone the template is to be hosted on'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId. If the account parameter is used, domainId must also be used.'}, {u'name': u'checksum', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the MD5 checksum value of this template'}, {u'name': u'templatetag', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the tag for this template.'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template is available to all accounts; default is true'}, {u'name': u'passwordenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template supports the password reset feature; default is false'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the template. This is usually used for display purposes.'}, {u'name': u'sshkeyenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template supports the sshkey upload feature; default is false'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'Register template for the project'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the template'}, {u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this template is a featured template, false otherwise'}, {u'name': u'format', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the format for the template. Possible values include QCOW2, RAW, and VHD.'}, {u'name': u'requireshvm', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this template requires HVM'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional accountName. Must be used with domainId.'}, {u'name': u'ostypeid', u'required': True, u'related': [u'listOsTypes'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS Type that best represents the OS of this template.'}, {u'name': u'hypervisor', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the target hypervisor for the template'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL of where the template is hosted. Possible URL include http:// and https://'}, {u'name': u'bits', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'32 or 64 bits support. 64 by default'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'Template details in key/value pairs.'}], u'requiredparams': [u'zoneid', u'displaytext', u'name', u'format', u'ostypeid', u'hypervisor', u'url'], u'description': u'Registers an existing template into the CloudStack cloud. '}}, u'list': {u'instancegroups': {u'name': u'listInstanceGroups', u'related': [u'updateInstanceGroup', u'createInstanceGroup'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listInstanceGroups', u'updateInstanceGroup', u'createInstanceGroup'], u'length': 255, u'type': u'uuid', u'description': u'list instance groups by ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list instance groups by name'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists vm groups'}, u'physicalnetworks': {u'name': u'listPhysicalNetworks', u'related': [], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the physical network'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listPhysicalNetworks'], u'length': 255, u'type': u'uuid', u'description': u'list physical network by id'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'search by name'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists physical networks'}, u'networks': {u'name': u'listNetworks', u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'issystem', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network is system, false otherwise'}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'List networks by VPC'}, {u'name': u'acltype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list networks by ACL (access control list) type. Supported values are Account and Domain'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'specifyipranges', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only networks which support specifying ip ranges'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the network'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'restartrequired', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list networks by restartRequired'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the type of the network. Supported values are: Isolated and Shared'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'list networks by physical network id'}, {u'name': u'supportedservices', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list networks supporting certain services'}, {u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of the traffic'}, {u'name': u'id', u'required': False, u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'list networks by id'}, {u'name': u'canusefordeploy', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list networks available for vm deployment'}, {u'name': u'forvpc', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the network belongs to vpc'}], u'requiredparams': [], u'description': u'Lists all available networks.'}, u'capabilities': {u'name': u'listCapabilities', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'Lists capabilities'}, u'clusters': {u'name': u'listClusters', u'related': [u'updateCluster'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listClusters', u'updateCluster'], u'length': 255, u'type': u'uuid', u'description': u'lists clusters by the cluster ID'}, {u'name': u'managedstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'whether this cluster is managed by cloudstack'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists clusters by hypervisor type'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists clusters by allocation state'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'lists clusters by Zone ID'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists clusters by the cluster name'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'clustertype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists clusters by cluster type'}, {u'name': u'showcapacities', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'flag to display the capacity of the clusters'}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'lists clusters by Pod ID'}], u'requiredparams': [], u'description': u'Lists clusters.'}, u'resourcelimits': {u'name': u'listResourceLimits', u'related': [u'updateResourceLimit'], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'resourcetype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Type of resource to update. Values are 0, 1, 2, 3, and 4. 0 - Instance. Number of instances a user can create. 1 - IP. Number of public IP addresses a user can own. 2 - Volume. Number of disk volumes a user can create.3 - Snapshot. Number of snapshots a user can create.4 - Template. Number of templates that a user can register/create.'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lists resource limits by ID.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists resource limits.'}, u'firewallrules': {u'name': u'listFirewallRules', u'related': [u'createEgressFirewallRule', u'createFirewallRule', u'listEgressFirewallRules'], u'isasync': False, u'params': [{u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'ipaddressid', u'required': False, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the id of IP address of the firwall services'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists all firewall rules for an IP address.'}, u'supportednetworkservices': {u'name': u'listSupportedNetworkServices', u'related': [], u'isasync': False, u'params': [{u'name': u'service', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'network service name to list providers and capabilities of'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'provider', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'network service provider name'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists all network services provided by CloudStack or for the given Provider.'}, u'loadbalancerrules': {u'name': u'listLoadBalancerRules', u'related': [u'createLoadBalancerRule', u'updateLoadBalancerRule'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the availability zone ID'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine of the load balancer rule'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'id', u'required': False, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'publicipid', u'required': False, u'related': [u'restartNetwork', u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the public IP address id of the load balancer rule '}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the load balancer rule'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists load balancer rules.'}, u'autoscalepolicies': {u'name': u'listAutoScalePolicies', u'related': [u'createAutoScalePolicy', u'updateAutoScalePolicy'], u'isasync': False, u'params': [{u'name': u'action', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the action to be executed if all the conditions evaluate to true for the specified duration.'}, {u'name': u'id', u'required': False, u'related': [u'createAutoScalePolicy', u'updateAutoScalePolicy', u'listAutoScalePolicies'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale policy'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'vmgroupid', u'required': False, u'related': [u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale vm group'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'conditionid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the condition of the policy'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists autoscale policies.'}, u'niciranvpdevices': {u'name': u'listNiciraNvpDevices', u'related': [u'addNiciraNvpDevice'], u'isasync': False, u'params': [{u'name': u'nvpdeviceid', u'required': False, u'related': [u'addNiciraNvpDevice', u'listNiciraNvpDevices'], u'length': 255, u'type': u'uuid', u'description': u'nicira nvp device ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists Nicira NVP devices'}, u'f5loadbalancernetworks': {u'name': u'listF5LoadBalancerNetworks', u'related': [u'createNetwork', u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'lbdeviceid', u'required': True, u'related': [u'configureF5LoadBalancer', u'addF5LoadBalancer', u'listF5LoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'f5 load balancer device ID'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'lbdeviceid'], u'description': u'lists network that are using a F5 load balancer device'}, u'templatepermissions': {u'name': u'listTemplatePermissions', u'related': [u'listIsoPermissions'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIsoPermissions', u'listTemplatePermissions'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}], u'requiredparams': [u'id'], u'description': u'List template visibility and all accounts that have permissions to view this template.'}, u'projects': {u'name': u'listProjects', u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List projects by tags (key/value pairs)'}, {u'name': u'id', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list projects by project ID'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list projects by name'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list projects by state'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list projects by display text'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists projects and provides detailed information for listed projects'}, u'systemvms': {u'name': u'listSystemVms', u'related': [u'rebootSystemVm'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the system VM'}, {u'name': u'hostid', u'required': False, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'the host ID of the system VM'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the state of the system VM'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'storageid', u'required': False, u'related': [u'cancelStorageMaintenance'], u'length': 255, u'type': u'uuid', u'description': u"the storage ID where vm's volumes belong to"}, {u'name': u'systemvmtype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the system VM type. Possible types are "consoleproxy" and "secondarystoragevm".'}, {u'name': u'podid', u'required': False, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID of the system VM'}, {u'name': u'id', u'required': False, u'related': [u'rebootSystemVm', u'listSystemVms'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the system VM'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the system VM'}], u'requiredparams': [], u'description': u'List system virtual machines.'}, u'portforwardingrules': {u'name': u'listPortForwardingRules', u'related': [u'listIpForwardingRules', u'createPortForwardingRule'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'id', u'required': False, u'related': [u'listIpForwardingRules', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'ipaddressid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id of IP address of the port forwarding services'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists all port forwarding rules for an IP address.'}, u'hypervisors': {u'name': u'listHypervisors', u'related': [], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the zone id for listing hypervisors.'}], u'requiredparams': [], u'description': u'List hypervisors'}, u'publicipaddresses': {u'name': u'listPublicIpAddresses', u'related': [u'restartNetwork', u'associateIpAddress'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'lists all public IP addresses by Zone ID'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'allocatedonly', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'limits search results to allocated public IP addresses'}, {u'name': u'id', u'required': False, u'related': [u'restartNetwork', u'listPublicIpAddresses', u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'lists ip address by id'}, {u'name': u'forloadbalancing', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list only ips used for load balancing'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isstaticnat', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list only static nat ip addresses'}, {u'name': u'issourcenat', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list only source nat ip addresses'}, {u'name': u'vlanid', u'required': False, u'related': [u'listVlanIpRanges'], u'length': 255, u'type': u'uuid', u'description': u'lists all public IP addresses by VLAN ID'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists the specified IP address'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'lists all public IP addresses by physical network id'}, {u'name': u'associatednetworkid', u'required': False, u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'lists all public IP addresses associated to the network specified'}, {u'name': u'forvirtualnetwork', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the virtual network for the IP address'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'List ips belonging to the VPC'}], u'requiredparams': [], u'description': u'Lists all public ip addresses'}, u'vpngateways': {u'name': u'listVpnGateways', u'related': [u'createVpnGateway'], u'isasync': False, u'params': [{u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'id', u'required': False, u'related': [u'createVpnGateway', u'listVpnGateways'], u'length': 255, u'type': u'uuid', u'description': u'id of the vpn gateway'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'id of vpc'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists site 2 site vpn gateways'}, u'loadbalancerruleinstances': {u'name': u'listLoadBalancerRuleInstances', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'applied', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if listing all virtual machines currently applied to the load balancer rule; default is true'}, {u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}], u'requiredparams': [u'id'], u'description': u'List all virtual machine instances that are assigned to a load balancer rule.'}, u'hosts': {u'name': u'listHosts', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'podid', u'required': False, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the host'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the state of the host'}, {u'name': u'resourcestate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list hosts by resource state. Resource state represents current state determined by admin of host, valule can be one of [Enabled, Disabled, Unmanaged, PrepareForMaintenance, ErrorInMaintenance, Maintenance, Error]'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the host'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the host'}, {u'name': u'virtualmachineid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'lists hosts in the same cluster as this VM and flag hosts with enough CPU/RAm to host this VM'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'lists hosts existing in particular cluster'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the host type'}, {u'name': u'id', u'required': False, u'related': [u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'the id of the host'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma separated list of host details requested, value can be a list of [ min, all, capacity, events, stats]'}, {u'name': u'hahost', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, list only hosts dedicated to HA'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists hosts.'}, u'pools': {u'name': u'listPools', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'List Pool'}, u'counters': {u'name': u'listCounters', u'related': [], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'source', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Source of the counter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'listCounters'], u'length': 255, u'type': u'uuid', u'description': u'ID of the Counter.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the counter.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'List the counters'}, u'configurations': {u'name': u'listConfigurations', u'related': [], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists configuration by name'}, {u'name': u'category', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists configurations by category'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all configurations.'}, u'usagerecords': {u'name': u'listUsageRecords', u'related': [], u'isasync': False, u'params': [{u'name': u'enddate', u'required': True, u'related': [], u'length': 255, u'type': u'date', u'description': u'End date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.'}, {u'name': u'startdate', u'required': True, u'related': [], u'length': 255, u'type': u'date', u'description': u'Start date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'List usage records for the specified usage type'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'List usage records for specified project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List usage records for the specified user.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'List usage records for the specified domain.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'accountid', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount'], u'length': 255, u'type': u'uuid', u'description': u'List usage records for the specified account'}], u'requiredparams': [u'enddate', u'startdate'], u'description': u'Lists usage records for accounts'}, u'storagepools': {u'name': u'listStoragePools', u'related': [u'cancelStorageMaintenance'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the storage pool'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'path', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the storage pool path'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list storage pools belongig to the specific cluster'}, {u'name': u'id', u'required': False, u'related': [u'cancelStorageMaintenance', u'listStoragePools'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the storage pool'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the IP address for the storage pool'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the storage pool'}, {u'name': u'podid', u'required': False, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the storage pool'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists storage pools.'}, u'vpncustomergateways': {u'name': u'listVpnCustomerGateways', u'related': [u'updateVpnCustomerGateway', u'createVpnCustomerGateway'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'updateVpnCustomerGateway', u'createVpnCustomerGateway', u'listVpnCustomerGateways'], u'length': 255, u'type': u'uuid', u'description': u'id of the customer gateway'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}], u'requiredparams': [], u'description': u'Lists site to site vpn customer gateways'}, u'zones': {u'name': u'listZones', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone'}, {u'name': u'available', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if you want to retrieve all available Zones. False if you only want to return the Zones from which you have at least one VM. Default is false.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the zone'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain associated with the zone'}, {u'name': u'showcapacities', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'flag to display the capacity of the zones'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists zones'}, u'serviceofferings': {u'name': u'listServiceOfferings', u'related': [u'updateHypervisorCapabilities'], u'isasync': False, u'params': [{u'name': u'systemvmtype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the system VM type. Possible types are "consoleproxy", "secondarystoragevm" or "domainrouter".'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain associated with the service offering'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the service offering'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine. Pass this in if you want to see the available service offering that a virtual machine can be changed to.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'issystem', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'is this a system vm offering'}, {u'name': u'id', u'required': False, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'length': 255, u'type': u'uuid', u'description': u'ID of the service offering'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all available service offerings.'}, u'externalfirewalls': {u'name': u'listExternalFirewalls', u'related': [u'addExternalFirewall'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'zone Id'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'zoneid'], u'description': u'List external firewall appliances.'}, u'networkserviceproviders': {u'name': u'listNetworkServiceProviders', u'related': [u'addNetworkServiceProvider', u'listTrafficTypes', u'updateNetworkServiceProvider'], u'isasync': False, u'params': [{u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list providers by state'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list providers by name'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists network serviceproviders for a given physical network.'}, u'capacity': {u'name': u'listCapacity', u'related': [], u'isasync': False, u'params': [{u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'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.'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'lists capacity by the Cluster ID'}, {u'name': u'sortby', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Sort the results. Available values: Usage'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'fetchlatest', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'recalculate capacities and fetch the latest'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'lists capacity by the Zone ID'}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'lists capacity by the Pod ID'}], u'requiredparams': [], u'description': u'Lists all the system wide capacities.'}, u'diskofferings': {u'name': u'listDiskOfferings', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'ID of the disk offering'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the disk offering'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain of the disk offering.'}], u'requiredparams': [], u'description': u'Lists all available disk offerings.'}, u'lbstickinesspolicies': {u'name': u'listLBStickinessPolicies', u'related': [u'createLBStickinessPolicy'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'lbruleid', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [u'lbruleid'], u'description': u'Lists LBStickiness policies.'}, u'srxfirewallnetworks': {u'name': u'listSrxFirewallNetworks', u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'isasync': False, u'params': [{u'name': u'lbdeviceid', u'required': True, u'related': [u'addSrxFirewall'], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'lbdeviceid'], u'description': u'lists network that are using SRX firewall device'}, u'securitygroups': {u'name': u'listSecurityGroups', u'related': [], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'id', u'required': False, u'related': [u'listSecurityGroups'], u'length': 255, u'type': u'uuid', u'description': u'list the security group by the id provided'}, {u'name': u'securitygroupname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists security groups by name'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'lists security groups by virtual machine id'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists security groups'}, u'conditions': {u'name': u'listConditions', u'related': [u'listCounters', u'createCounter'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'ID of the Condition.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'counterid', u'required': False, u'related': [u'listConditions', u'listCounters', u'createCounter'], u'length': 255, u'type': u'uuid', u'description': u'Counter-id of the condition.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'policyid', u'required': False, u'related': [u'createAutoScalePolicy', u'updateAutoScalePolicy'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the policy'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}], u'requiredparams': [], u'description': u'List Conditions for the specific user'}, u'swifts': {u'name': u'listSwifts', u'related': [u'addHost', u'updateHost', u'listHosts', u'listExternalLoadBalancers'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the id of the swift'}], u'requiredparams': [], u'description': u'List Swift.'}, u'hypervisorcapabilities': {u'name': u'listHypervisorCapabilities', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listHypervisorCapabilities'], u'length': 255, u'type': u'uuid', u'description': u'ID of the hypervisor capability'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the hypervisor for which to restrict the search'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists all hypervisor capabilities.'}, u'tags': {u'name': u'listTags', u'related': [], u'isasync': False, u'params': [{u'name': u'resourceid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by resource id'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'resourcetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by resource type'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'key', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by key'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'customer', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by customer name'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'value', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by value'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'List resource tag(s)'}, u'routers': {u'name': u'listRouters', u'related': [u'changeServiceForRouter', u'stopRouter', u'destroyRouter', u'rebootRouter', u'startRouter'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the state of the router'}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'List networks by VPC'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID of the router'}, {u'name': u'hostid', u'required': False, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'the host ID of the router'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the router'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the router'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'id', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'addNicToVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk router'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'networkid', u'required': False, u'related': [u'createNetwork', u'listNiciraNvpDeviceNetworks', u'updateNetwork', u'listF5LoadBalancerNetworks', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'list by network id'}, {u'name': u'forvpc', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true is passed for this parameter, list only VPC routers'}], u'requiredparams': [], u'description': u'List routers.'}, u'traffictypes': {u'name': u'listTrafficTypes', u'related': [u'addNetworkServiceProvider', u'updateNetworkServiceProvider'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'physicalnetworkid'], u'description': u'Lists traffic types of a given physical network.'}, u'projectinvitations': {u'name': u'listProjectInvitations', u'related': [], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'activeonly', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, list only active invitations - having Pending state and ones that are not timed out yet'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list by project id'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list invitations by state'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'id', u'required': False, u'related': [u'listProjectInvitations'], u'length': 255, u'type': u'uuid', u'description': u'list invitations by id'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists projects and provides detailed information for listed projects'}, u'isos': {u'name': u'listIsos', u'related': [], u'isasync': False, u'params': [{u'name': u'bootable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the ISO is bootable, false otherwise'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list all isos by name'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'id', u'required': False, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'list ISO by id'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the ISO is publicly available to all users, false otherwise.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isofilter', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'possible values are "featured", "self", "selfexecutable","sharedexecutable","executable", and "community". * featured : templates that have been marked as featured and public. * self : templates that have been registered or created by the calling user. * selfexecutable : same as self, but only returns templates that can be used to deploy a new VM. * sharedexecutable : templates ready to be deployed that have been granted to the calling user by another user. * executable : templates that are owned by the calling user, or public templates, that can be used to deploy a VM. * community : templates that have been marked as public but not featured. * all : all templates (only usable by admins).'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the hypervisor for which to restrict the search'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'isready', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this ISO is ready to be deployed'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all available ISO files.'}, u'users': {u'name': u'listUsers', u'related': [], u'isasync': False, u'params': [{u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List user by the username'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'accounttype', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'List users by account type. Valid types include admin, domain-admin, read-only-admin, or user.'}, {u'name': u'id', u'required': False, u'related': [u'listUsers'], u'length': 255, u'type': u'uuid', u'description': u'List user by ID.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List users by state of the user account.'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists user accounts'}, u'sshkeypairs': {u'name': u'listSSHKeyPairs', u'related': [], u'isasync': False, u'params': [{u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'fingerprint', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'A public key fingerprint to look for'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'A key pair name to look for'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}], u'requiredparams': [], u'description': u'List registered keypairs'}, u'privategateways': {u'name': u'listPrivateGateways', u'related': [u'createPrivateGateway'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'createPrivateGateway', u'listPrivateGateways'], u'length': 255, u'type': u'uuid', u'description': u'list private gateway by id'}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list gateways by ip address'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'list gateways by vpc'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list gateways by state'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list gateways by vlan'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}], u'requiredparams': [], u'description': u'List private gateways'}, u'usagetypes': {u'name': u'listUsageTypes', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'List Usage Types'}, u'domainchildren': {u'name': u'listDomainChildren', u'related': [u'createDomain'], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list children domains by name'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list children domain by parent domain ID.'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'to return the entire tree, use the value "true". To return the first level children, use the value "false".'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all children domains belonging to a specified domain'}, u'domains': {u'name': u'listDomains', u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'List domain by domain ID.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List domain by domain name.'}, {u'name': u'level', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'List domains by domain level.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}], u'requiredparams': [], u'description': u'Lists domains and provides detailed information for listed domains'}, u'externalloadbalancers': {u'name': u'listExternalLoadBalancers', u'related': [u'addHost', u'updateHost', u'listHosts'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'zone Id'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists F5 external load balancer appliances added in a zone.'}, u'netscalerloadbalancers': {u'name': u'listNetscalerLoadBalancers', u'related': [], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'lbdeviceid', u'required': False, u'related': [u'listNetscalerLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'lists netscaler load balancer devices'}, u's3s': {u'name': u'listS3s', u'related': [u'addS3'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists S3s'}, u'bigswitchvnsdevices': {u'name': u'listBigSwitchVnsDevices', u'related': [u'addBigSwitchVnsDevice'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vnsdeviceid', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'bigswitch vns device ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}], u'requiredparams': [], u'description': u'Lists BigSwitch Vns devices'}, u'accounts': {u'name': u'listAccounts', u'related': [u'markDefaultZoneForAccount', u'lockAccount'], u'isasync': False, u'params': [{u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list accounts by state. Valid states are enabled, disabled, and locked.'}, {u'name': u'iscleanuprequired', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list accounts by cleanuprequred attribute (values are true or false)'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'accounttype', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'list accounts by account type. Valid account types are 1 (admin), 2 (domain-admin), and 0 (user).'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'markDefaultZoneForAccount', u'listAccounts', u'lockAccount'], u'length': 255, u'type': u'uuid', u'description': u'list account by account ID'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list account by account name'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists accounts and provides detailed account information for listed accounts'}, u'networkdevice': {u'name': u'listNetworkDevice', u'related': [u'addNetworkDevice'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'networkdevicetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network device type, now supports ExternalDhcp, PxeServer, NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer, F5BigIpLoadBalancer, JuniperSRXFirewall'}, {u'name': u'networkdeviceparameterlist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'parameters for network device'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'List network devices'}, u'vlanipranges': {u'name': u'listVlanIpRanges', u'related': [], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'networkid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'network id of the VLAN IP range'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the domain ID with which the VLAN IP range is associated. If used with the account parameter, returns all VLAN IP ranges for that account in the specified domain.'}, {u'name': u'id', u'required': False, u'related': [u'listVlanIpRanges'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the VLAN IP range'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks'], u'length': 255, u'type': u'uuid', u'description': u'physical network id of the VLAN IP range'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'project who will own the VLAN'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account with which the VLAN IP range is associated. Must be used with the domainId parameter.'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ID or VID of the VLAN. Default is an "untagged" VLAN.'}, {u'name': u'podid', u'required': False, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID of the VLAN IP range'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the VLAN IP range'}, {u'name': u'forvirtualnetwork', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if VLAN is of Virtual type, false if Direct'}], u'requiredparams': [], u'description': u'Lists all VLAN IP ranges.'}, u'traffictypeimplementors': {u'name': u'listTrafficTypeImplementors', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Optional. The network traffic type, if specified, return its implementor. Otherwise, return all traffic types with their implementor'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists implementors of implementor of a network traffic type or implementors of all network traffic types'}, u'storagenetworkiprange': {u'name': u'listStorageNetworkIpRange', u'related': [u'updateStorageNetworkIpRange'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'optional parameter. Zone uuid, if specicied and both pod uuid and range uuid are absent, using it to search the range.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'listStorageNetworkIpRange', u'updateStorageNetworkIpRange'], u'length': 255, u'type': u'uuid', u'description': u'optional parameter. Storaget network IP range uuid, if specicied, using it to search the range.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'podid', u'required': False, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'optional parameter. Pod uuid, if specicied and range uuid is absent, using it to search the range.'}], u'requiredparams': [], u'description': u'List a storage network IP range.'}, u'isopermissions': {u'name': u'listIsoPermissions', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIsoPermissions'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}], u'requiredparams': [u'id'], u'description': u'List iso visibility and all accounts that have permissions to view this iso.'}, u'snapshotpolicies': {u'name': u'listSnapshotPolicies', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'volumeid', u'required': True, u'related': [u'detachVolume', u'uploadVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [u'volumeid'], u'description': u'Lists snapshot policies.'}, u'autoscalevmgroups': {u'name': u'listAutoScaleVmGroups', u'related': [u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'isasync': False, u'params': [{u'name': u'policyid', u'required': False, u'related': [u'createAutoScalePolicy', u'updateAutoScalePolicy', u'listAutoScalePolicies'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the policy'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'vmprofileid', u'required': False, u'related': [u'updateAutoScaleVmProfile', u'createAutoScaleVmProfile', u'listAutoScaleVmProfiles'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the profile'}, {u'name': u'lbruleid', u'required': False, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the loadbalancer'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the availability zone ID'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'id', u'required': False, u'related': [u'listAutoScaleVmGroups', u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale vm group'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists autoscale vm groups.'}, u'projectaccounts': {u'name': u'listProjectAccounts', u'related': [u'createProject'], u'isasync': False, u'params': [{u'name': u'projectid', u'required': True, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'id of the project'}, {u'name': u'role', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list accounts of the project by role'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list accounts of the project by account name'}], u'requiredparams': [u'projectid'], u'description': u"Lists project's accounts"}, u'autoscalevmprofiles': {u'name': u'listAutoScaleVmProfiles', u'related': [], u'isasync': False, u'params': [{u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'id', u'required': False, u'related': [u'listAutoScaleVmProfiles'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale vm profile'}, {u'name': u'templateid', u'required': False, u'related': [u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the templateid of the autoscale vm profile'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'otherdeployparams', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the otherdeployparameters of the autoscale vm profile'}], u'requiredparams': [], u'description': u'Lists autoscale vm profiles.'}, u'apis': {u'name': u'listApis', u'related': [], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'API name'}], u'requiredparams': [], u'description': u'lists all available apis on the server, provided by the Api Discovery plugin'}, u'vpcs': {u'name': u'listVPCs', u'related': [u'restartVPC'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by name of the VPC'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'cidr', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"list by cidr of the VPC. All VPC guest networks' cidrs should be within this CIDR"}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'restartrequired', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list VPCs by restartRequired option'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list VPCs by state'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by display text of the VPC'}, {u'name': u'id', u'required': False, u'related': [u'restartVPC', u'listVPCs'], u'length': 255, u'type': u'uuid', u'description': u'list VPC by id'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list by zone'}, {u'name': u'supportedservices', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list VPC supporting certain services'}, {u'name': u'vpcofferingid', u'required': False, u'related': [u'listVPCOfferings', u'createVPCOffering'], u'length': 255, u'type': u'uuid', u'description': u'list by ID of the VPC offering'}], u'requiredparams': [], u'description': u'Lists VPCs'}, u'f5loadbalancers': {u'name': u'listF5LoadBalancers', u'related': [u'configureF5LoadBalancer'], u'isasync': False, u'params': [{u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'lbdeviceid', u'required': False, u'related': [u'configureF5LoadBalancer', u'listF5LoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'f5 load balancer device ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'lists F5 load balancer devices'}, u'snapshots': {u'name': u'listSnapshots', u'related': [], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'id', u'required': False, u'related': [u'listSnapshots'], u'length': 255, u'type': u'uuid', u'description': u'lists snapshot by snapshot ID'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'intervaltype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'valid values are HOURLY, DAILY, WEEKLY, and MONTHLY.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'volumeid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists snapshot by snapshot name'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'snapshottype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'valid values are MANUAL or RECURRING.'}], u'requiredparams': [], u'description': u'Lists all available snapshots for the account.'}, u'networkofferings': {u'name': u'listNetworkOfferings', u'related': [u'createNetworkOffering', u'updateNetworkOffering'], u'isasync': False, u'params': [{u'name': u'isdefault', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only default network offerings. Default value is false'}, {u'name': u'sourcenatsupported', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only netwok offerings where source nat is supported, false otherwise'}, {u'name': u'supportedservices', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list network offerings supporting certain services'}, {u'name': u'networkid', u'required': False, u'related': [u'createNetwork', u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network. Pass this in if you want to see the available network offering that a network can be changed to.'}, {u'name': u'specifyipranges', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only network offerings which support specifying ip ranges'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network offerings by name'}, {u'name': u'id', u'required': False, u'related': [u'listNetworkOfferings', u'createNetworkOffering', u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'list network offerings by id'}, {u'name': u'specifyvlan', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the tags for the network offering.'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'list netowrk offerings available for network creation in specific zone'}, {u'name': u'forvpc', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the network offering can be used only for network creation inside the VPC'}, {u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by traffic type'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'guestiptype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network offerings by guest type: Shared or Isolated'}, {u'name': u'istagged', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if offering has tags specified'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'list network offerings by tags'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network offerings by display text'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network offerings by state'}, {u'name': u'availability', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the availability of network offering. Default value is Required'}], u'requiredparams': [], u'description': u'Lists all available network offerings.'}, u'virtualmachines': {u'name': u'listVirtualMachines', u'related': [], u'isasync': False, u'params': [{u'name': u'templateid', u'required': False, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'list vms by template'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'networkid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list by network id'}, {u'name': u'storageid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u"the storage ID where vm's volumes belong to"}, {u'name': u'isoid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list vms by iso'}, {u'name': u'vpcid', u'required': False, u'related': [u'restartVPC'], u'length': 255, u'type': u'uuid', u'description': u'list vms by vpc'}, {u'name': u'podid', u'required': False, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the pod ID'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the virtual machine'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma separated list of host details requested, value can be a list of [all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min]. If no parameter is passed in, the details will be defaulted to all'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the target hypervisor for the template'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'groupid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the group ID'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the availability zone ID'}, {u'name': u'hostid', u'required': False, u'related': [u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}, {u'name': u'id', u'required': False, u'related': [u'listVirtualMachines'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'forvirtualnetwork', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list by network type; true if need to list vms using Virtual Network, false otherwise'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'state of the virtual machine'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'List the virtual machines owned by the account.'}, u'netscalerloadbalancernetworks': {u'name': u'listNetscalerLoadBalancerNetworks', u'related': [], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'lbdeviceid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}], u'requiredparams': [u'lbdeviceid'], u'description': u'lists network that are using a netscaler load balancer device'}, u'oscategories': {u'name': u'listOsCategories', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listOsCategories'], u'length': 255, u'type': u'uuid', u'description': u'list Os category by id'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list os category by name'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists all supported OS categories for this cloud.'}, u'virtualrouterelements': {u'name': u'listVirtualRouterElements', u'related': [u'createVirtualRouterElement', u'configureVirtualRouterElement'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'nspid', u'required': False, u'related': [u'addNetworkServiceProvider', u'listTrafficTypes', u'updateNetworkServiceProvider'], u'length': 255, u'type': u'uuid', u'description': u'list virtual router elements by network service provider id'}, {u'name': u'id', u'required': False, u'related': [u'createVirtualRouterElement', u'configureVirtualRouterElement', u'listVirtualRouterElements'], u'length': 255, u'type': u'uuid', u'description': u'list virtual router elements by id'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'enabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list network offerings by enabled state'}], u'requiredparams': [], u'description': u'Lists all available virtual router elements.'}, u'lunsonfiler': {u'name': u'listLunsOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'poolname'], u'description': u'List LUN'}, u'asyncjobs': {u'name': u'listAsyncJobs', u'related': [u'queryAsyncJobResult'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'startdate', u'required': False, u'related': [], u'length': 255, u'type': u'tzdate', u'description': u'the start date of the async job'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists all pending asynchronous jobs for the account.'}, u'ostypes': {u'name': u'listOsTypes', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listOsTypes'], u'length': 255, u'type': u'uuid', u'description': u'list by Os type Id'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'oscategoryid', u'required': False, u'related': [u'listOsCategories'], u'length': 255, u'type': u'uuid', u'description': u'list by Os Category id'}, {u'name': u'description', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list os by description'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all supported OS types for this cloud.'}, u'networkacls': {u'name': u'listNetworkACLs', u'related': [u'createNetworkACL'], u'isasync': False, u'params': [{u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network ACLs by traffic type - Ingress or Egress'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'Lists network ACL with the specified ID.'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'networkid', u'required': False, u'related': [u'createNetwork', u'listNiciraNvpDeviceNetworks', u'updateNetwork', u'listF5LoadBalancerNetworks', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'list network ACLs by network Id'}], u'requiredparams': [], u'description': u'Lists all network ACLs'}, u'volumesonfiler': {u'name': u'listVolumesOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'poolname'], u'description': u'List Volumes'}, u'eventtypes': {u'name': u'listEventTypes', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'List Event Types'}, u'remoteaccessvpns': {u'name': u'listRemoteAccessVpns', u'related': [u'createRemoteAccessVpn'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'publicipid', u'required': True, u'related': [u'restartNetwork', u'listPublicIpAddresses', u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'public ip address id of the vpn server'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [u'publicipid'], u'description': u'Lists remote access vpns'}, u'alerts': {u'name': u'listAlerts', u'related': [], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by alert type'}, {u'name': u'id', u'required': False, u'related': [u'listAlerts'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the alert'}], u'requiredparams': [], u'description': u'Lists all alerts.'}, u'regions': {u'name': u'listRegions', u'related': [u'addRegion'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'List Region by region ID.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List Region by region name.'}], u'requiredparams': [], u'description': u'Lists Regions'}, u'vpcofferings': {u'name': u'listVPCOfferings', u'related': [], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listVPCOfferings'], u'length': 255, u'type': u'uuid', u'description': u'list VPC offerings by id'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list VPC offerings by state'}, {u'name': u'supportedservices', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list VPC offerings supporting certain services'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list VPC offerings by display text'}, {u'name': u'isdefault', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only default VPC offerings. Default value is false'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list VPC offerings by name'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists VPC offerings'}, u'niciranvpdevicenetworks': {u'name': u'listNiciraNvpDeviceNetworks', u'related': [u'createNetwork', u'updateNetwork', u'listF5LoadBalancerNetworks', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'isasync': False, u'params': [{u'name': u'nvpdeviceid', u'required': True, u'related': [u'addNiciraNvpDevice', u'listNiciraNvpDevices'], u'length': 255, u'type': u'uuid', u'description': u'nicira nvp device ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'nvpdeviceid'], u'description': u'lists network that are using a nicira nvp device'}, u'events': {u'name': u'listEvents', u'related': [], u'isasync': False, u'params': [{u'name': u'startdate', u'required': False, u'related': [], u'length': 255, u'type': u'date', u'description': u'the start date range of the list you want to retrieve (use format "yyyy-MM-dd" or the new format "yyyy-MM-dd HH:mm:ss")'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'enddate', u'required': False, u'related': [], u'length': 255, u'type': u'date', u'description': u'the end date range of the list you want to retrieve (use format "yyyy-MM-dd" or the new format "yyyy-MM-dd HH:mm:ss")'}, {u'name': u'duration', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the duration of the event'}, {u'name': u'id', u'required': False, u'related': [u'listEvents'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the event'}, {u'name': u'level', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the event level (INFO, WARN, ERROR)'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'entrytime', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the time the event was entered'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the event type (see event types)'}], u'requiredparams': [], u'description': u'A command to list events.'}, u'templates': {u'name': u'listTemplates', u'related': [u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'templatefilter', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'possible values are "featured", "self", "selfexecutable","sharedexecutable","executable", and "community". * featured : templates that have been marked as featured and public. * self : templates that have been registered or created by the calling user. * selfexecutable : same as self, but only returns templates that can be used to deploy a new VM. * sharedexecutable : templates ready to be deployed that have been granted to the calling user by another user. * executable : templates that are owned by the calling user, or public templates, that can be used to deploy a VM. * community : templates that have been marked as public but not featured. * all : all templates (only usable by admins).'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the template name'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the hypervisor for which to restrict the search'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'list templates by zoneId'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}], u'requiredparams': [u'templatefilter'], u'description': u'List all public, private, and privileged templates.'}, u'cisconexusvsms': {u'name': u'listCiscoNexusVSMs', u'related': [u'disableCiscoNexusVSM', u'enableCiscoNexusVSM'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Id of the CloudStack cluster in which the Cisco Nexus 1000v VSM appliance.'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'Id of the CloudStack cluster in which the Cisco Nexus 1000v VSM appliance.'}], u'requiredparams': [], u'description': u'Retrieves a Cisco Nexus 1000v Virtual Switch Manager device associated with a Cluster'}, u'ipforwardingrules': {u'name': u'listIpForwardingRules', u'related': [], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'listIpForwardingRules'], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'listVirtualMachines', u'destroyVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Lists all rules applied to the specified Vm.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'ipaddressid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list the rule belonging to this public ip address'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}], u'requiredparams': [], u'description': u'List the ip forwarding rules'}, u'srxfirewalls': {u'name': u'listSrxFirewalls', u'related': [u'addSrxFirewall'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'fwdeviceid', u'required': False, u'related': [u'listSrxFirewalls', u'addSrxFirewall'], u'length': 255, u'type': u'uuid', u'description': u'SRX firewall device ID'}], u'requiredparams': [], u'description': u'lists SRX firewall devices in a physical network'}, u'vpnconnections': {u'name': u'listVpnConnections', u'related': [], u'isasync': False, u'params': [{u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vpcid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'id of vpc'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'id', u'required': False, u'related': [u'listVpnConnections'], u'length': 255, u'type': u'uuid', u'description': u'id of the vpn connection'}], u'requiredparams': [], u'description': u'Lists site to site vpn connection gateways'}, u'trafficmonitors': {u'name': u'listTrafficMonitors', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'zone Id'}], u'requiredparams': [u'zoneid'], u'description': u'List traffic monitor Hosts.'}, u'vpnusers': {u'name': u'listVpnUsers', u'related': [], u'isasync': False, u'params': [{u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listVpnUsers'], u'length': 255, u'type': u'uuid', u'description': u'The uuid of the Vpn user'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username of the vpn user.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists vpn users'}, u'egressfirewallrules': {u'name': u'listEgressFirewallRules', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'networkid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id network network for the egress firwall services'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'ipaddressid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id of IP address of the firwall services'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}], u'requiredparams': [], u'description': u'Lists all egress firewall rules for network id.'}, u'staticroutes': {u'name': u'listStaticRoutes', u'related': [u'createStaticRoute'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'gatewayid', u'required': False, u'related': [u'createPrivateGateway'], u'length': 255, u'type': u'uuid', u'description': u'list static routes by gateway id'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'list static routes by vpc id'}, {u'name': u'id', u'required': False, u'related': [u'createStaticRoute', u'listStaticRoutes'], u'length': 255, u'type': u'uuid', u'description': u'list static route by id'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}], u'requiredparams': [], u'description': u'Lists all static routes'}, u'volumes': {u'name': u'listVolumes', u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the disk volume'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'hostid', u'required': False, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'list volumes on specified host'}, {u'name': u'id', u'required': False, u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'listVolumes', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the availability zone'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the type of disk volume'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the pod id the disk volume belongs to'}], u'requiredparams': [], u'description': u'Lists all volumes.'}, u'pods': {u'name': u'listPods', u'related': [u'updatePod'], u'isasync': False, u'params': [{u'name': u'showcapacities', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'flag to display the capacity of the pods'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list pods by allocation state'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list Pods by Zone ID'}, {u'name': u'id', u'required': False, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'list Pods by ID'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list Pods by name'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all Pods.'}}, u'upload': {u'volume': {u'name': u'uploadVolume', u'related': [u'detachVolume'], u'isasync': True, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the volume'}, {u'name': u'format', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the format for the volume. Possible values include QCOW2, OVA, and VHD.'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL of where the volume is hosted. Possible URL include http:// and https://'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional accountName. Must be used with domainId.'}, {u'name': u'domainid', u'required': False, u'related': [u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId. If the account parameter is used, domainId must also be used.'}, {u'name': u'checksum', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the MD5 checksum value of this volume'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone the volume is to be hosted on'}], u'requiredparams': [u'name', u'format', u'url', u'zoneid'], u'description': u'Uploads a data disk.'}, u'customcertificate': {u'name': u'uploadCustomCertificate', u'related': [], u'isasync': True, u'params': [{u'name': u'domainsuffix', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'DNS domain suffix that the certificate is granted for.'}, {u'name': u'certificate', u'required': True, u'related': [], u'length': 65535, u'type': u'string', u'description': u'The certificate to be uploaded.'}, {u'name': u'privatekey', u'required': False, u'related': [], u'length': 65535, u'type': u'string', u'description': u'The private key for the attached certificate.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'A name / alias for the certificate.'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'An integer providing the location in a chain that the certificate will hold. Usually, this can be left empty. When creating a chain, the top level certificate should have an ID of 1, with each step in the chain incrementing by one. Example, CA with id = 1, Intermediate CA with id = 2, Site certificate with ID = 3'}], u'requiredparams': [u'domainsuffix', u'certificate'], u'description': u'Uploads a custom certificate for the console proxy VMs to use for SSL. Can be used to upload a single certificate signed by a known CA. Can also be used, through multiple calls, to upload a chain of certificates from CA to the custom certificate itself.'}}, u'remove': {u'region': {u'name': u'removeRegion', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'ID of the region to delete'}], u'requiredparams': [u'id'], u'description': u'Removes specified region'}, u'nicfromvirtualmachine': {u'name': u'removeNicFromVirtualMachine', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'nicid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'NIC ID'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Virtual Machine ID'}], u'requiredparams': [u'nicid', u'virtualmachineid'], u'description': u'Removes VM from specified network by deleting a NIC'}, u'fromloadbalancerrule': {u'name': u'removeFromLoadBalancerRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIpForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the load balancer rule'}, {u'name': u'virtualmachineids', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'list', u'description': u'the list of IDs of the virtual machines that are being removed from the load balancer rule (i.e. virtualMachineIds=1,2,3)'}], u'requiredparams': [u'id', u'virtualmachineids'], u'description': u'Removes a virtual machine or a list of virtual machines from a load balancer rule.'}, u'vpnuser': {u'name': u'removeVpnUser', u'related': [], u'isasync': True, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the vpn user. If the account parameter is used, domainId must also be used.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'remove vpn user from the project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the vpn user. Must be used with domainId.'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'username for the vpn user'}], u'requiredparams': [u'username'], u'description': u'Removes vpn user'}}, u'asyncapis': [u'createCondition', u'reconnectHost', u'copyTemplate', u'deleteBigSwitchVnsDevice', u'addNicToVirtualMachine', u'extractVolume', u'addAccountToProject', u'deleteEgressFirewallRule', u'deleteCiscoNexusVSM', u'createVpnConnection', u'suspendProject', u'addF5LoadBalancer', u'deleteAutoScaleVmGroup', u'authorizeSecurityGroupIngress', u'addNetscalerLoadBalancer', u'deleteDomain', u'configureNetscalerLoadBalancer', u'disableAutoScaleVmGroup', u'authorizeSecurityGroupEgress', u'createTemplate', u'migrateVolume', u'updatePhysicalNetwork', u'prepareHostForMaintenance', u'deletePrivateGateway', u'deleteStaticRoute', u'deleteTrafficType', u'deleteLoadBalancerRule', u'attachIso', u'destroySystemVm', u'deletePortForwardingRule', u'enableStorageMaintenance', u'stopRouter', u'configureSrxFirewall', u'attachVolume', u'updateVPCOffering', u'resetSSHKeyForVirtualMachine', u'updateProjectInvitation', u'createTags', u'enableAutoScaleVmGroup', u'deleteTags', u'deleteAccountFromProject', u'removeVpnUser', u'updateVpnCustomerGateway', u'stopSystemVm', u'uploadCustomCertificate', u'restartNetwork', u'createAutoScaleVmProfile', u'rebootVirtualMachine', u'enableCiscoNexusVSM', u'cancelHostMaintenance', u'deleteStorageNetworkIpRange', u'deleteFirewallRule', u'deleteVpnConnection', u'startSystemVm', u'deleteF5LoadBalancer', u'deleteNiciraNvpDevice', u'updateProject', u'deleteNetwork', u'deleteProject', u'deleteNetscalerLoadBalancer', u'deleteIpForwardingRule', u'addTrafficType', u'disableUser', u'resizeVolume', u'configureVirtualRouterElement', u'createStaticRoute', u'deleteProjectInvitation', u'migrateSystemVm', u'activateProject', u'removeNicFromVirtualMachine', u'revokeSecurityGroupIngress', u'updateDefaultNicForVirtualMachine', u'disableStaticNat', u'createNetworkACL', u'createVPC', u'configureF5LoadBalancer', u'disassociateIpAddress', u'createIpForwardingRule', u'createVolume', u'resetPasswordForVirtualMachine', u'assignToLoadBalancerRule', u'startRouter', u'extractIso', u'deleteRemoteAccessVpn', u'resetVpnConnection', u'createRemoteAccessVpn', u'extractTemplate', u'startVirtualMachine', u'detachIso', u'updateVPC', u'deleteAccount', u'associateIpAddress', u'updateAutoScaleVmProfile', u'disableAccount', u'updatePortForwardingRule', u'migrateVirtualMachine', u'createStorageNetworkIpRange', u'cancelStorageMaintenance', u'deployVirtualMachine', u'removeFromLoadBalancerRule', u'revokeSecurityGroupEgress', u'deleteCondition', u'createPortForwardingRule', u'addVpnUser', u'createVPCOffering', u'createEgressFirewallRule', u'deleteLBStickinessPolicy', u'destroyRouter', u'createPrivateGateway', u'disableCiscoNexusVSM', u'deleteAutoScaleVmProfile', u'updateTrafficType', u'deleteSnapshot', u'createProject', u'createLoadBalancerRule', u'addSrxFirewall', u'addNiciraNvpDevice', u'createAutoScalePolicy', u'restoreVirtualMachine', u'copyIso', u'uploadVolume', u'createLBStickinessPolicy', u'stopVirtualMachine', u'createCounter', u'createSnapshot', u'destroyVirtualMachine', u'updateNetwork', u'deleteVpnGateway', u'createAutoScaleVmGroup', u'rebootRouter', u'deleteNetworkServiceProvider', u'deleteIso', u'createVpnCustomerGateway', u'createFirewallRule', u'deleteAutoScalePolicy', u'deleteSrxFirewall', u'addNetworkServiceProvider', u'rebootSystemVm', u'detachVolume', u'deleteNetworkACL', u'markDefaultZoneForAccount', u'deleteVPC', u'restartVPC', u'updateAutoScaleVmGroup', u'updateLoadBalancerRule', u'createPhysicalNetwork', u'deleteTemplate', u'deletePhysicalNetwork', u'deleteVpnCustomerGateway', u'deleteVPCOffering', u'createVirtualRouterElement', u'updateAutoScalePolicy', u'addBigSwitchVnsDevice', u'createVpnGateway', u'updateNetworkServiceProvider', u'deleteCounter', u'updateStorageNetworkIpRange'], u'assign': {u'toloadbalancerrule': {u'name': u'assignToLoadBalancerRule', u'related': [], u'isasync': True, u'params': [{u'name': u'virtualmachineids', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'list', u'description': u'the list of IDs of the virtual machine that are being assigned to the load balancer rule(i.e. virtualMachineIds=1,2,3)'}, {u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}], u'requiredparams': [u'virtualmachineids', u'id'], u'description': u'Assigns virtual machine or a list of virtual machines to a load balancer rule.'}, u'virtualmachine': {u'name': u'assignVirtualMachine', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'networkids', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'list', u'description': u'list of new network ids in which the moved VM will participate. In case no network ids are provided the VM will be part of the default network for that zone. In case there is no network yet created for the new account the default network will be created.'}, {u'name': u'domainid', u'required': True, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'domain id of the new VM owner.'}, {u'name': u'securitygroupids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of security group ids to be applied on the virtual machine. In case no security groups are provided the VM is part of the default security group.'}, {u'name': u'account', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'account name of the new VM owner.'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'id of the VM to be moved'}], u'requiredparams': [u'domainid', u'account', u'virtualmachineid'], u'description': u'Assign a VM from one account to another under the same domain. This API is available for Basic zones with security groups and Advance zones with guest networks. The VM is restricted to move between accounts under same domain.'}}, u'delete': {u'loadbalancerrule': {u'name': u'deleteLoadBalancerRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a load balancer rule.'}, u'domain': {u'name': u'deleteDomain', u'related': [], u'isasync': True, u'params': [{u'name': u'cleanup', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if all domain resources (child domains, accounts) have to be cleaned up, false otherwise'}, {u'name': u'id', u'required': True, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'ID of domain to delete'}], u'requiredparams': [u'id'], u'description': u'Deletes a specified domain'}, u'instancegroup': {u'name': u'deleteInstanceGroup', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the instance group'}], u'requiredparams': [u'id'], u'description': u'Deletes a vm group'}, u'diskoffering': {u'name': u'deleteDiskOffering', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateDiskOffering', u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'ID of the disk offering'}], u'requiredparams': [u'id'], u'description': u'Updates a disk offering.'}, u'externalloadbalancer': {u'name': u'deleteExternalLoadBalancer', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'Id of the external loadbalancer appliance.'}], u'requiredparams': [u'id'], u'description': u'Deletes a F5 external load balancer appliance added in a zone.'}, u'securitygroup': {u'name': u'deleteSecurityGroup', u'related': [], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the domain ID of account owning the security group'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The ID of the security group. Mutually exclusive with name parameter'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The ID of the security group. Mutually exclusive with id parameter'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account of the security group. Must be specified with domain ID'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the project of the security group'}], u'requiredparams': [], u'description': u'Deletes security group'}, u'portforwardingrule': {u'name': u'deletePortForwardingRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the port forwarding rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a port forwarding rule'}, u'cluster': {u'name': u'deleteCluster', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID'}], u'requiredparams': [u'id'], u'description': u'Deletes a cluster.'}, u'accountfromproject': {u'name': u'deleteAccountFromProject', u'related': [], u'isasync': True, u'params': [{u'name': u'projectid', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to remove the account from'}, {u'name': u'account', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the account to be removed from the project'}], u'requiredparams': [u'projectid', u'account'], u'description': u'Deletes account from the project'}, u'networkdevice': {u'name': u'deleteNetworkDevice', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'Id of network device to delete'}], u'requiredparams': [u'id'], u'description': u'Deletes network device.'}, u'firewallrule': {u'name': u'deleteFirewallRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the firewall rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a firewall rule'}, u'pod': {u'name': u'deletePod', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Pod'}], u'requiredparams': [u'id'], u'description': u'Deletes a Pod.'}, u'ipforwardingrule': {u'name': u'deleteIpForwardingRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the id of the forwarding rule'}], u'requiredparams': [u'id'], u'description': u'Deletes an ip forwarding rule'}, u'vpnconnection': {u'name': u'deleteVpnConnection', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listVpnConnections', u'resetVpnConnection'], u'length': 255, u'type': u'uuid', u'description': u'id of vpn connection'}], u'requiredparams': [u'id'], u'description': u'Delete site to site vpn connection'}, u'lbstickinesspolicy': {u'name': u'deleteLBStickinessPolicy', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createLBStickinessPolicy'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the LB stickiness policy'}], u'requiredparams': [u'id'], u'description': u'Deletes a LB stickiness policy.'}, u'vpcoffering': {u'name': u'deleteVPCOffering', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the VPC offering'}], u'requiredparams': [u'id'], u'description': u'Deletes VPC offering'}, u'network': {u'name': u'deleteNetwork', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network'}], u'requiredparams': [u'id'], u'description': u'Deletes a network'}, u'zone': {u'name': u'deleteZone', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Zone'}], u'requiredparams': [u'id'], u'description': u'Deletes a Zone.'}, u'remoteaccessvpn': {u'name': u'deleteRemoteAccessVpn', u'related': [], u'isasync': True, u'params': [{u'name': u'publicipid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'public ip address id of the vpn server'}], u'requiredparams': [u'publicipid'], u'description': u'Destroys a l2tp/ipsec remote access vpn'}, u'storagenetworkiprange': {u'name': u'deleteStorageNetworkIpRange', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listStorageNetworkIpRange', u'createStorageNetworkIpRange', u'updateStorageNetworkIpRange'], u'length': 255, u'type': u'uuid', u'description': u'the uuid of the storage network ip range'}], u'requiredparams': [u'id'], u'description': u'Deletes a storage network IP Range.'}, u'bigswitchvnsdevice': {u'name': u'deleteBigSwitchVnsDevice', u'related': [], u'isasync': True, u'params': [{u'name': u'vnsdeviceid', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'BigSwitch device ID'}], u'requiredparams': [u'vnsdeviceid'], u'description': u' delete a bigswitch vns device'}, u'projectinvitation': {u'name': u'deleteProjectInvitation', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listProjectInvitations'], u'length': 255, u'type': u'uuid', u'description': u'id of the invitation'}], u'requiredparams': [u'id'], u'description': u'Accepts or declines project invitation'}, u'autoscalepolicy': {u'name': u'deleteAutoScalePolicy', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale policy'}], u'requiredparams': [u'id'], u'description': u'Deletes a autoscale policy.'}, u'niciranvpdevice': {u'name': u'deleteNiciraNvpDevice', u'related': [], u'isasync': True, u'params': [{u'name': u'nvpdeviceid', u'required': True, u'related': [u'addNiciraNvpDevice', u'listNiciraNvpDevices'], u'length': 255, u'type': u'uuid', u'description': u'Nicira device ID'}], u'requiredparams': [u'nvpdeviceid'], u'description': u' delete a nicira nvp device'}, u'serviceoffering': {u'name': u'deleteServiceOffering', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the service offering'}], u'requiredparams': [u'id'], u'description': u'Deletes a service offering.'}, u'condition': {u'name': u'deleteCondition', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the condition.'}], u'requiredparams': [u'id'], u'description': u'Removes a condition'}, u'storagepool': {u'name': u'deleteStoragePool', u'related': [], u'isasync': False, u'params': [{u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force destroy storage pool (force expunge volumes in Destroyed state as a part of pool removal)'}, {u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Storage pool id'}], u'requiredparams': [u'id'], u'description': u'Deletes a storage pool.'}, u'vpngateway': {u'name': u'deleteVpnGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createVpnGateway'], u'length': 255, u'type': u'uuid', u'description': u'id of customer gateway'}], u'requiredparams': [u'id'], u'description': u'Delete site to site vpn gateway'}, u'snapshot': {u'name': u'deleteSnapshot', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createSnapshot', u'listSnapshots'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the snapshot'}], u'requiredparams': [u'id'], u'description': u'Deletes a snapshot of a disk volume.'}, u'autoscalevmgroup': {u'name': u'deleteAutoScaleVmGroup', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listAutoScaleVmGroups', u'createAutoScaleVmGroup', u'disableAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale group'}], u'requiredparams': [u'id'], u'description': u'Deletes a autoscale vm group.'}, u'trafficmonitor': {u'name': u'deleteTrafficMonitor', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'Id of the Traffic Monitor Host.'}], u'requiredparams': [u'id'], u'description': u'Deletes an traffic monitor host.'}, u'networkacl': {u'name': u'deleteNetworkACL', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network ACL'}], u'requiredparams': [u'id'], u'description': u'Deletes a Network ACL'}, u'template': {u'name': u'deleteTemplate', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the template'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of zone of the template'}], u'requiredparams': [u'id'], u'description': u'Deletes a template from the system. All virtual machines using the deleted template will not be affected.'}, u'tags': {u'name': u'deleteTags', u'related': [], u'isasync': True, u'params': [{u'name': u'resourceids', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'Delete tags for resource id(s)'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'Delete tags matching key/value pairs'}, {u'name': u'resourcetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Delete tag by resource type'}], u'requiredparams': [u'resourceids', u'resourcetype'], u'description': u'Deleting resource tag(s)'}, u'snapshotpolicies': {u'name': u'deleteSnapshotPolicies', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Id of the snapshot policy'}, {u'name': u'ids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of snapshots policy IDs separated by comma'}], u'requiredparams': [], u'description': u'Deletes snapshot policies for the account.'}, u'privategateway': {u'name': u'deletePrivateGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createPrivateGateway', u'listPrivateGateways'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the private gateway'}], u'requiredparams': [u'id'], u'description': u'Deletes a Private gateway'}, u'traffictype': {u'name': u'deleteTrafficType', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'addTrafficType', u'updateTrafficType'], u'length': 255, u'type': u'uuid', u'description': u'traffic type id'}], u'requiredparams': [u'id'], u'description': u'Deletes traffic type of a physical network'}, u'host': {u'name': u'deleteHost', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}, {u'name': u'forcedestroylocalstorage', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force destroy local storage on this host. All VMs created on this local storage will be destroyed'}, {u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force delete the host. All HA enabled vms running on the host will be put to HA; HA disabled ones will be stopped'}], u'requiredparams': [u'id'], u'description': u'Deletes a host.'}, u'staticroute': {u'name': u'deleteStaticRoute', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createStaticRoute', u'listStaticRoutes'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the static route'}], u'requiredparams': [u'id'], u'description': u'Deletes a static route'}, u'vpc': {u'name': u'deleteVPC', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'restartVPC'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the VPC'}], u'requiredparams': [u'id'], u'description': u'Deletes a VPC'}, u'srxfirewall': {u'name': u'deleteSrxFirewall', u'related': [], u'isasync': True, u'params': [{u'name': u'fwdeviceid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'srx firewall device ID'}], u'requiredparams': [u'fwdeviceid'], u'description': u' delete a SRX firewall device'}, u'externalfirewall': {u'name': u'deleteExternalFirewall', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'Id of the external firewall appliance.'}], u'requiredparams': [u'id'], u'description': u'Deletes an external firewall appliance.'}, u'pool': {u'name': u'deletePool', u'related': [], u'isasync': False, u'params': [{u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'poolname'], u'description': u'Delete a pool'}, u'autoscalevmprofile': {u'name': u'deleteAutoScaleVmProfile', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listAutoScaleVmProfiles'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale profile'}], u'requiredparams': [u'id'], u'description': u'Deletes a autoscale vm profile.'}, u'volume': {u'name': u'deleteVolume', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'detachVolume', u'resizeVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the disk volume'}], u'requiredparams': [u'id'], u'description': u'Deletes a detached disk volume.'}, u'account': {u'name': u'deleteAccount', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount', u'disableAccount'], u'length': 255, u'type': u'uuid', u'description': u'Account id'}], u'requiredparams': [u'id'], u'description': u'Deletes a account, and all users associated with this account'}, u'cisconexusvsm': {u'name': u'deleteCiscoNexusVSM', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableCiscoNexusVSM', u'listCiscoNexusVSMs', u'enableCiscoNexusVSM'], u'length': 255, u'type': u'uuid', u'description': u'Id of the Cisco Nexus 1000v VSM device to be deleted'}], u'requiredparams': [u'id'], u'description': u' delete a Cisco Nexus VSM device'}, u'netscalerloadbalancer': {u'name': u'deleteNetscalerLoadBalancer', u'related': [], u'isasync': True, u'params': [{u'name': u'lbdeviceid', u'required': True, u'related': [u'listNetscalerLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}], u'requiredparams': [u'lbdeviceid'], u'description': u' delete a netscaler load balancer device'}, u'networkoffering': {u'name': u'deleteNetworkOffering', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'createNetworkOffering', u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network offering'}], u'requiredparams': [u'id'], u'description': u'Deletes a network offering.'}, u'vpncustomergateway': {u'name': u'deleteVpnCustomerGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'id of customer gateway'}], u'requiredparams': [u'id'], u'description': u'Delete site to site vpn customer gateway'}, u'counter': {u'name': u'deleteCounter', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the counter'}], u'requiredparams': [u'id'], u'description': u'Deletes a counter'}, u'physicalnetwork': {u'name': u'deletePhysicalNetwork', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Physical network'}], u'requiredparams': [u'id'], u'description': u'Deletes a Physical Network.'}, u'project': {u'name': u'deleteProject', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to be deleted'}], u'requiredparams': [u'id'], u'description': u'Deletes a project'}, u'vlaniprange': {u'name': u'deleteVlanIpRange', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listVlanIpRanges'], u'length': 255, u'type': u'uuid', u'description': u'the id of the VLAN IP range'}], u'requiredparams': [u'id'], u'description': u'Creates a VLAN IP range.'}, u'f5loadbalancer': {u'name': u'deleteF5LoadBalancer', u'related': [], u'isasync': True, u'params': [{u'name': u'lbdeviceid', u'required': True, u'related': [u'configureF5LoadBalancer'], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}], u'requiredparams': [u'lbdeviceid'], u'description': u' delete a F5 load balancer device'}, u'iso': {u'name': u'deleteIso', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the ISO file'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone of the ISO file. If not specified, the ISO will be deleted from all the zones'}], u'requiredparams': [u'id'], u'description': u'Deletes an ISO file.'}, u'egressfirewallrule': {u'name': u'deleteEgressFirewallRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the firewall rule'}], u'requiredparams': [u'id'], u'description': u'Deletes an ggress firewall rule'}, u'networkserviceprovider': {u'name': u'deleteNetworkServiceProvider', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'addNetworkServiceProvider', u'listTrafficTypes', u'updateNetworkServiceProvider'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network service provider'}], u'requiredparams': [u'id'], u'description': u'Deletes a Network Service Provider.'}, u'sshkeypair': {u'name': u'deleteSSHKeyPair', u'related': [], u'isasync': False, u'params': [{u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the project associated with keypair'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the keypair'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the keypair'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the keypair. Must be used with the domainId parameter.'}], u'requiredparams': [u'name'], u'description': u'Deletes a keypair by name'}, u'user': {u'name': u'deleteUser', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'lockUser', u'listUsers'], u'length': 255, u'type': u'uuid', u'description': u'id of the user to be deleted'}], u'requiredparams': [u'id'], u'description': u'Deletes a user for an account'}}}
+apicache = {u'authorize': {u'securitygroupingress': {u'name': u'authorizeSecurityGroupIngress', u'related': [u'authorizeSecurityGroupEgress'], u'isasync': True, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the security group. If the account parameter is used, domainId must also be used.'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'start port for this ingress rule'}, {u'name': u'securitygroupid', u'required': False, u'related': [u'createSecurityGroup', u'listSecurityGroups'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the security group. Mutually exclusive with securityGroupName parameter'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list associated'}, {u'name': u'usersecuritygrouplist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'user to security group mapping'}, {u'name': u'securitygroupname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The name of the security group. Mutually exclusive with securityGroupName parameter'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the security group. Must be used with domainId.'}, {u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'protocol', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'TCP is default. UDP is the other supported protocol'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'an optional project of the security group'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'end port for this ingress rule'}], u'requiredparams': [], u'description': u'Authorizes a particular ingress rule for this security group'}, u'securitygroupegress': {u'name': u'authorizeSecurityGroupEgress', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the security group. Must be used with domainId.'}, {u'name': u'securitygroupname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The name of the security group. Mutually exclusive with securityGroupName parameter'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the security group. If the account parameter is used, domainId must also be used.'}, {u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'securitygroupid', u'required': False, u'related': [u'createSecurityGroup', u'listSecurityGroups'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the security group. Mutually exclusive with securityGroupName parameter'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}, {u'name': u'protocol', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'TCP is default. UDP is the other supported protocol'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'an optional project of the security group'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'end port for this egress rule'}, {u'name': u'usersecuritygrouplist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'user to security group mapping'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'start port for this egress rule'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list associated'}], u'requiredparams': [], u'description': u'Authorizes a particular egress rule for this security group'}}, u'restore': {u'virtualmachine': {u'name': u'restoreVirtualMachine', u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine'], u'isasync': True, u'params': [{u'name': u'virtualmachineid', u'required': True, u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Virtual Machine ID'}], u'requiredparams': [u'virtualmachineid'], u'description': u'Restore a VM to original template or specific snapshot'}}, u'suspend': {u'project': {u'name': u'suspendProject', u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to be suspended'}], u'requiredparams': [u'id'], u'description': u'Suspends a project'}}, u'revoke': {u'securitygroupingress': {u'name': u'revokeSecurityGroupIngress', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The ID of the ingress rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a particular ingress rule from this security group'}, u'securitygroupegress': {u'name': u'revokeSecurityGroupEgress', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The ID of the egress rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a particular egress rule from this security group'}}, u'disassociate': {u'ipaddress': {u'name': u'disassociateIpAddress', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the id of the public ip address to disassociate'}], u'requiredparams': [u'id'], u'description': u'Disassociates an ip address from the account.'}}, u'migrate': {u'volume': {u'name': u'migrateVolume', u'related': [u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'isasync': True, u'params': [{u'name': u'volumeid', u'required': True, u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the volume'}, {u'name': u'storageid', u'required': True, u'related': [u'cancelStorageMaintenance', u'enableStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'length': 255, u'type': u'uuid', u'description': u'destination storage pool ID to migrate the volume to'}], u'requiredparams': [u'volumeid', u'storageid'], u'description': u'Migrate volume'}, u'systemvm': {u'name': u'migrateSystemVm', u'related': [], u'isasync': True, u'params': [{u'name': u'virtualmachineid', u'required': True, u'related': [u'rebootSystemVm', u'listSystemVms'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'hostid', u'required': True, u'related': [u'addHost', u'updateHost', u'listHosts', u'listExternalLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'destination Host ID to migrate VM to'}], u'requiredparams': [u'virtualmachineid', u'hostid'], u'description': u'Attempts Migration of a system virtual machine to the host specified.'}, u'virtualmachine': {u'name': u'migrateVirtualMachine', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'deployVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'storageid', u'required': False, u'related': [u'cancelStorageMaintenance'], u'length': 255, u'type': u'long', u'description': u'Destination storage pool ID to migrate VM volumes to. Required for migrating the root disk volume'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'hostid', u'required': False, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'Destination Host ID to migrate VM to. Required for live migrating a VM from host to host'}], u'requiredparams': [u'virtualmachineid'], u'description': u'Attempts Migration of a VM to a different host or Root volume of the vm to a different storage pool'}}, u'lock': {u'account': {u'name': u'lockAccount', u'related': [u'markDefaultZoneForAccount'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Locks the specified account on this domain.'}, {u'name': u'account', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Locks the specified account.'}], u'requiredparams': [u'domainid', u'account'], u'description': u'Locks an account'}, u'user': {u'name': u'lockUser', u'related': [u'listUsers'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'lockUser', u'listUsers'], u'length': 255, u'type': u'uuid', u'description': u'Locks user by user ID.'}], u'requiredparams': [u'id'], u'description': u'Locks a user account'}}, u'dissociate': {u'lun': {u'name': u'dissociateLun', u'related': [], u'isasync': False, u'params': [{u'name': u'iqn', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Guest IQN.'}, {u'name': u'path', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'LUN path.'}], u'requiredparams': [u'iqn', u'path'], u'description': u'Dissociate a LUN'}}, u'activate': {u'project': {u'name': u'activateProject', u'related': [u'createProject', u'listProjectAccounts'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to be modified'}], u'requiredparams': [u'id'], u'description': u'Activates a project'}}, u'reconnect': {u'host': {u'name': u'reconnectHost', u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'reconnectHost', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}], u'requiredparams': [u'id'], u'description': u'Reconnects a host.'}}, u'cancel': {u'hostmaintenance': {u'name': u'cancelHostMaintenance', u'related': [u'listSwifts', u'addHost', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}], u'requiredparams': [u'id'], u'description': u'Cancels host maintenance.'}, u'storagemaintenance': {u'name': u'cancelStorageMaintenance', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'cancelStorageMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'the primary storage ID'}], u'requiredparams': [u'id'], u'description': u'Cancels maintenance for primary storage'}}, u'query': {u'asyncjobresult': {u'name': u'queryAsyncJobResult', u'related': [], u'isasync': False, u'params': [{u'name': u'jobid', u'required': True, u'related': [u'queryAsyncJobResult'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the asynchronous job'}], u'requiredparams': [u'jobid'], u'description': u'Retrieves the current status of asynchronous job.'}}, u'recover': {u'virtualmachine': {u'name': u'recoverVirtualMachine', u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Recovers a virtual machine.'}}, u'extract': {u'volume': {u'name': u'extractVolume', u'related': [u'extractTemplate', u'extractIso'], u'isasync': True, u'params': [{u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the url to which the volume would be extracted'}, {u'name': u'id', u'required': True, u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'listVolumes', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the volume'}, {u'name': u'mode', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the mode of extraction - HTTP_DOWNLOAD or FTP_UPLOAD'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone where the volume is located'}], u'requiredparams': [u'id', u'mode', u'zoneid'], u'description': u'Extracts volume'}, u'iso': {u'name': u'extractIso', u'related': [u'extractTemplate'], u'isasync': True, u'params': [{u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone where the ISO is originally located'}, {u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the url to which the ISO would be extracted'}, {u'name': u'mode', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the mode of extraction - HTTP_DOWNLOAD or FTP_UPLOAD'}, {u'name': u'id', u'required': True, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the ISO file'}], u'requiredparams': [u'mode', u'id'], u'description': u'Extracts an ISO'}, u'template': {u'name': u'extractTemplate', u'related': [], u'isasync': True, u'params': [{u'name': u'mode', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the mode of extraction - HTTP_DOWNLOAD or FTP_UPLOAD'}, {u'name': u'id', u'required': True, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the template'}, {u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the url to which the ISO would be extracted'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone where the ISO is originally located'}], u'requiredparams': [u'mode', u'id'], u'description': u'Extracts a template'}}, u'copy': {u'iso': {u'name': u'copyIso', u'related': [u'updateIso', u'listIsos'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'Template ID.'}, {u'name': u'destzoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'ID of the zone the template is being copied to.'}, {u'name': u'sourcezoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'ID of the zone the template is currently hosted on.'}], u'requiredparams': [u'id', u'destzoneid', u'sourcezoneid'], u'description': u'Copies an iso from one zone to another.'}, u'template': {u'name': u'copyTemplate', u'related': [u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'registerTemplate', u'copyIso', u'updateIso', u'listIsos'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'copyTemplate', u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'registerTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'Template ID.'}, {u'name': u'destzoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'ID of the zone the template is being copied to.'}, {u'name': u'sourcezoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'ID of the zone the template is currently hosted on.'}], u'requiredparams': [u'id', u'destzoneid', u'sourcezoneid'], u'description': u'Copies a template from one zone to another.'}}, u'prepare': {u'hostformaintenance': {u'name': u'prepareHostForMaintenance', u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}], u'requiredparams': [u'id'], u'description': u'Prepares a host for maintenance.'}, u'template': {u'name': u'prepareTemplate', u'related': [u'registerIso', u'updateTemplate', u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'zone ID of the template to be prepared in primary storage(s).'}, {u'name': u'templateid', u'required': True, u'related': [u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'template ID of the template to be prepared in primary storage(s).'}], u'requiredparams': [u'zoneid', u'templateid'], u'description': u'load template into primary storage'}}, u'attach': {u'volume': {u'name': u'attachVolume', u'related': [u'detachVolume', u'resizeVolume', u'uploadVolume', u'createVolume'], u'isasync': True, u'params': [{u'name': u'deviceid', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the ID of the device to map the volume to within the guest OS. If no deviceId is passed in, the next available deviceId will be chosen. Possible values for a Linux OS are:* 1 - /dev/xvdb* 2 - /dev/xvdc* 4 - /dev/xvde* 5 - /dev/xvdf* 6 - /dev/xvdg* 7 - /dev/xvdh* 8 - /dev/xvdi* 9 - /dev/xvdj'}, {u'name': u'id', u'required': True, u'related': [u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u' the ID of the virtual machine'}], u'requiredparams': [u'id', u'virtualmachineid'], u'description': u'Attaches a disk volume to a virtual machine.'}, u'iso': {u'name': u'attachIso', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'id', u'required': True, u'related': [u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the ISO file'}], u'requiredparams': [u'virtualmachineid', u'id'], u'description': u'Attaches an ISO to a virtual machine.'}}, u'create': {u'loadbalancerrule': {u'name': u'createLoadBalancerRule', u'related': [u'updateLoadBalancerRule'], u'isasync': True, u'params': [{u'name': u'openfirewall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, firewall rule for source/end public port is automatically created; if false - firewall rule has to be created explicitely. If not specified 1) defaulted to false when LB rule is being created for VPC guest network 2) in all other cases defaulted to true'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the load balancer. Must be used with the domainId parameter.'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the load balancer'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'zone where the load balancer is going to be created. This parameter is required when LB service provider is ElasticLoadBalancerVm'}, {u'name': u'publicipid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'public ip address id from where the network traffic will be load balanced from'}, {u'name': u'algorithm', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'load balancer algorithm (source, roundrobin, leastconn)'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the load balancer rule'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}, {u'name': u'publicport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the public port from where the network traffic will be load balanced from'}, {u'name': u'description', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the description of the load balancer rule'}, {u'name': u'privateport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the private port of the private ip address/virtual machine where the network traffic will be load balanced to'}, {u'name': u'networkid', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The guest network this rule will be created for. Required when public Ip address is not associated with any Guest network yet (VPC case)'}], u'requiredparams': [u'algorithm', u'name', u'publicport', u'privateport'], u'description': u'Creates a load balancer rule'}, u'domain': {u'name': u'createDomain', u'related': [], u'isasync': False, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'creates domain with this name'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Domain UUID, required for adding domain from another Region'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network domain for networks in the domain'}, {u'name': u'parentdomainid', u'required': False, u'related': [u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'assigns new domain a parent domain by domain ID of the parent. If no parent domain is specied, the ROOT domain is assumed.'}], u'requiredparams': [u'name'], u'description': u'Creates a domain'}, u'snapshotpolicy': {u'name': u'createSnapshotPolicy', u'related': [u'listSnapshotPolicies'], u'isasync': False, u'params': [{u'name': u'intervaltype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'valid values are HOURLY, DAILY, WEEKLY, and MONTHLY'}, {u'name': u'maxsnaps', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'maximum number of snapshots to retain'}, {u'name': u'schedule', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'time the snapshot is scheduled to be taken. Format is:* if HOURLY, MM* if DAILY, MM:HH* if WEEKLY, MM:HH:DD (1-7)* if MONTHLY, MM:HH:DD (1-28)'}, {u'name': u'timezone', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.'}, {u'name': u'volumeid', u'required': True, u'related': [u'detachVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}], u'requiredparams': [u'intervaltype', u'maxsnaps', u'schedule', u'timezone', u'volumeid'], u'description': u'Creates a snapshot policy for the account.'}, u'diskoffering': {u'name': u'createDiskOffering', u'related': [u'listDiskOfferings'], u'isasync': False, u'params': [{u'name': u'customized', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'whether disk offering is custom or not'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 4096, u'type': u'string', u'description': u'alternate display text of the disk offering'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the containing domain, null for public offerings'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the disk offering'}, {u'name': u'disksize', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'size of the disk offering in GB'}, {u'name': u'storagetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the storage type of the disk offering. Values are local and shared.'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'tags for the disk offering'}], u'requiredparams': [u'displaytext', u'name'], u'description': u'Creates a disk offering.'}, u'securitygroup': {u'name': u'createSecurityGroup', u'related': [u'listSecurityGroups'], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the security group. Must be used with domainId.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the security group. If the account parameter is used, domainId must also be used.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the security group'}, {u'name': u'description', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the description of the security group'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Deploy vm for the project'}], u'requiredparams': [u'name'], u'description': u'Creates a security group'}, u'portforwardingrule': {u'name': u'createPortForwardingRule', u'related': [u'listIpForwardingRules'], u'isasync': True, u'params': [{u'name': u'privateport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u"the starting port of port forwarding rule's private port range"}, {u'name': u'ipaddressid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the IP address id of the port forwarding rule'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the port fowarding rule. Valid values are TCP or UDP.'}, {u'name': u'openfirewall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. If not specified 1) defaulted to false when PF rule is being created for VPC guest network 2) in all other cases defaulted to true'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine for the port forwarding rule'}, {u'name': u'privateendport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u"the ending port of port forwarding rule's private port range"}, {u'name': u'networkid', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The network of the vm the Port Forwarding rule will be created for. Required when public Ip address is not associated with any Guest network yet (VPC case)'}, {u'name': u'publicendport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u"the ending port of port forwarding rule's private port range"}, {u'name': u'publicport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u"the starting port of port forwarding rule's public port range"}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}], u'requiredparams': [u'privateport', u'ipaddressid', u'protocol', u'virtualmachineid', u'publicport'], u'description': u'Creates a port forwarding rule'}, u'pod': {u'name': u'createPod', u'related': [u'updatePod', u'listPods'], u'isasync': False, u'params': [{u'name': u'startip', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the starting IP address for the Pod'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the Pod'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID in which the Pod will be created'}, {u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address for the Pod'}, {u'name': u'netmask', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask for the Pod'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this Pod for allocation of new resources'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway for the Pod'}], u'requiredparams': [u'startip', u'name', u'zoneid', u'netmask', u'gateway'], u'description': u'Creates a new Pod.'}, u'ipforwardingrule': {u'name': u'createIpForwardingRule', u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'listPortForwardingRules', u'createPortForwardingRule'], u'isasync': True, u'params': [{u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the end port for the rule'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}, {u'name': u'ipaddressid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the public IP address id of the forwarding rule, already associated via associateIp'}, {u'name': u'openfirewall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default'}, {u'name': u'startport', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the start port for the rule'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the rule. Valid values are TCP or UDP.'}], u'requiredparams': [u'ipaddressid', u'startport', u'protocol'], u'description': u'Creates an ip forwarding rule'}, u'vpnconnection': {u'name': u'createVpnConnection', u'related': [u'listVpnConnections', u'resetVpnConnection'], u'isasync': True, u'params': [{u'name': u's2svpngatewayid', u'required': True, u'related': [u'createVpnGateway', u'listVpnGateways'], u'length': 255, u'type': u'uuid', u'description': u'id of the vpn gateway'}, {u'name': u's2scustomergatewayid', u'required': True, u'related': [u'updateVpnCustomerGateway', u'createVpnCustomerGateway', u'listVpnCustomerGateways'], u'length': 255, u'type': u'uuid', u'description': u'id of the customer gateway'}], u'requiredparams': [u's2svpngatewayid', u's2scustomergatewayid'], u'description': u'Create site to site vpn connection'}, u'vpncustomergateway': {u'name': u'createVpnCustomerGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the gateway. If used with the account parameter returns the gateway associated with the account for the specified domain.'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'public ip address id of the customer gateway'}, {u'name': u'esplifetime', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lifetime of phase 2 VPN connection to the customer gateway, in seconds'}, {u'name': u'esppolicy', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'ESP policy of the customer gateway'}, {u'name': u'ikepolicy', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'IKE policy of the customer gateway'}, {u'name': u'cidrlist', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'guest cidr list of the customer gateway'}, {u'name': u'dpd', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'If DPD is enabled for VPN connection'}, {u'name': u'ipsecpsk', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'IPsec Preshared-Key of the customer gateway'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the gateway. Must be used with the domainId parameter.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of this customer gateway'}, {u'name': u'ikelifetime', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lifetime of phase 1 VPN connection to the customer gateway, in seconds'}], u'requiredparams': [u'gateway', u'esppolicy', u'ikepolicy', u'cidrlist', u'ipsecpsk'], u'description': u'Creates site to site vpn customer gateway'}, u'lbstickinesspolicy': {u'name': u'createLBStickinessPolicy', u'related': [], u'isasync': True, u'params': [{u'name': u'lbruleid', u'required': True, u'related': [u'listIpForwardingRules'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the LB Stickiness policy'}, {u'name': u'methodname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the LB Stickiness policy method, possible values can be obtained from ListNetworks API '}, {u'name': u'description', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the description of the LB Stickiness policy'}, {u'name': u'param', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'param list. Example: param[0].name=cookiename¶m[0].value=LBCookie '}], u'requiredparams': [u'lbruleid', u'name', u'methodname'], u'description': u'Creates a Load Balancer stickiness policy '}, u'vpcoffering': {u'name': u'createVPCOffering', u'related': [u'listVPCOfferings'], u'isasync': True, u'params': [{u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the vpc offering'}, {u'name': u'supportedservices', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'services supported by the vpc offering'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the vpc offering'}], u'requiredparams': [u'displaytext', u'supportedservices', u'name'], u'description': u'Creates VPC offering'}, u'network': {u'name': u'createNetwork', u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'isasync': False, u'params': [{u'name': u'endipv6', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IPv6 address in the IPv6 network range'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'an optional project for the ssh key'}, {u'name': u'ip6cidr', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the CIDR of IPv6 network, must be at least /64'}, {u'name': u'acltype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Access control type; supported values are account and domain. In 3.0 all shared networks should have aclType=Domain, and all Isolated networks - Account. Account means that only the account owner can use the network, domain - all accouns in the domain can use the network'}, {u'name': u'gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the network. Required for Shared networks and Isolated networks when it belongs to VPC'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the network'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID the network belongs to'}, {u'name': u'subdomainaccess', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Defines whether to allow subdomains to use networks dedicated to their parent domain(s). Should be used with aclType=Domain, defaulted to allow.subdomain.network.access global config if not specified'}, {u'name': u'startip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IP address in the network IP range'}, {u'name': u'netmask', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask of the network. Required for Shared networks and Isolated networks when it belongs to VPC'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'domain ID of the account owning a network'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'network domain'}, {u'name': u'ip6gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the IPv6 network. Required for Shared networks and Isolated networks when it belongs to VPC'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'account who will own the network'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the network'}, {u'name': u'startipv6', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IPv6 address in the IPv6 network range'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the network'}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'the VPC network belongs to'}, {u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address in the network IP range. If not specified, will be defaulted to startIP'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ID or VID of the network'}, {u'name': u'networkofferingid', u'required': True, u'related': [u'createNetworkOffering', u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'the network offering id'}], u'requiredparams': [u'displaytext', u'zoneid', u'name', u'networkofferingid'], u'description': u'Creates a network'}, u'zone': {u'name': u'createZone', u'related': [u'listZones'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the containing domain, null for public zones'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the Zone'}, {u'name': u'ip6dns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second DNS for IPv6 network in the Zone'}, {u'name': u'domain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network domain name for the networks in the zone'}, {u'name': u'internaldns1', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first internal DNS for the Zone'}, {u'name': u'localstorageenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if local storage offering enabled, false otherwise'}, {u'name': u'securitygroupenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network is security group enabled, false otherwise'}, {u'name': u'networktype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'network type of the zone, can be Basic or Advanced'}, {u'name': u'internaldns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second internal DNS for the Zone'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this Zone for allocation of new resources'}, {u'name': u'guestcidraddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the guest CIDR address for the Zone'}, {u'name': u'dns1', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first DNS for the Zone'}, {u'name': u'ip6dns1', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first DNS for IPv6 network in the Zone'}, {u'name': u'dns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second DNS for the Zone'}], u'requiredparams': [u'name', u'internaldns1', u'networktype', u'dns1'], u'description': u'Creates a Zone.'}, u'remoteaccessvpn': {u'name': u'createRemoteAccessVpn', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the VPN. Must be used with domainId.'}, {u'name': u'openfirewall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default'}, {u'name': u'publicipid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'public ip address id of the vpn server'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the VPN. If the account parameter is used, domainId must also be used.'}, {u'name': u'iprange', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the range of ip addresses to allocate to vpn clients. The first ip in the range will be taken by the vpn server'}], u'requiredparams': [u'publicipid'], u'description': u'Creates a l2tp/ipsec remote access vpn'}, u'instancegroup': {u'name': u'createInstanceGroup', u'related': [], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account of the instance group. The account parameter must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The project of the instance group'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the instance group'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID of account owning the instance group'}], u'requiredparams': [u'name'], u'description': u'Creates a vm group'}, u'autoscalepolicy': {u'name': u'createAutoScalePolicy', u'related': [u'updateAutoScalePolicy'], u'isasync': True, u'params': [{u'name': u'action', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the action to be executed if all the conditions evaluate to true for the specified duration.'}, {u'name': u'quiettime', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the cool down period for which the policy should not be evaluated after the action has been taken'}, {u'name': u'conditionids', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'the list of IDs of the conditions that are being evaluated on every interval'}, {u'name': u'duration', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the duration for which the conditions have to be true before action is taken'}], u'requiredparams': [u'action', u'conditionids', u'duration'], u'description': u'Creates an autoscale policy for a provision or deprovision action, the action is taken when the all the conditions evaluates to true for the specified duration. The policy is in effect once it is attached to a autscale vm group.'}, u'tags': {u'name': u'createTags', u'related': [], u'isasync': True, u'params': [{u'name': u'tags', u'required': True, u'related': [], u'length': 255, u'type': u'map', u'description': u'Map of tags (key/value pairs)'}, {u'name': u'resourcetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of the resource'}, {u'name': u'customer', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"identifies client specific tag. When the value is not null, the tag can't be used by cloudStack code internally"}, {u'name': u'resourceids', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of resources to create the tags for'}], u'requiredparams': [u'tags', u'resourcetype', u'resourceids'], u'description': u'Creates resource tag(s)'}, u'serviceoffering': {u'name': u'createServiceOffering', u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'isasync': False, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the service offering'}, {u'name': u'storagetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the storage type of the service offering. Values are local and shared.'}, {u'name': u'issystem', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'is this a system vm offering'}, {u'name': u'cpunumber', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'the CPU number of the service offering'}, {u'name': u'systemvmtype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the system VM type. Possible types are "domainrouter", "consoleproxy" and "secondarystoragevm".'}, {u'name': u'limitcpuuse', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'restrict the CPU usage to committed service offering'}, {u'name': u'hosttags', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the host tag for this service offering.'}, {u'name': u'offerha', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the HA for the service offering'}, {u'name': u'memory', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'the total memory of the service offering in MB'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the containing domain, null for public offerings'}, {u'name': u'cpuspeed', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'the CPU speed of the service offering in MHz.'}, {u'name': u'networkrate', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'data transfer rate in megabits per second allowed. Supported only for non-System offering and system offerings having "domainrouter" systemvmtype'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the service offering'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the tags for this service offering.'}], u'requiredparams': [u'name', u'cpunumber', u'memory', u'cpuspeed', u'displaytext'], u'description': u'Creates a service offering.'}, u'condition': {u'name': u'createCondition', u'related': [], u'isasync': True, u'params': [{u'name': u'threshold', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'Threshold value.'}, {u'name': u'counterid', u'required': True, u'related': [u'listConditions', u'listCounters', u'createCounter'], u'length': 255, u'type': u'uuid', u'description': u'ID of the Counter.'}, {u'name': u'relationaloperator', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Relational Operator to be used with threshold.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account of the condition. Must be used with the domainId parameter.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID of the account.'}], u'requiredparams': [u'threshold', u'counterid', u'relationaloperator'], u'description': u'Creates a condition'}, u'storagepool': {u'name': u'createStoragePool', u'related': [u'cancelStorageMaintenance', u'listStoragePools'], u'isasync': False, u'params': [{u'name': u'clusterid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID for the storage pool'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the storage pool'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name for the storage pool'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the tags for the storage pool'}, {u'name': u'podid', u'required': True, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the storage pool'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL of the storage pool'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'the details for the storage pool'}], u'requiredparams': [u'clusterid', u'zoneid', u'name', u'podid', u'url'], u'description': u'Creates a storage pool.'}, u'vpngateway': {u'name': u'createVpnGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'vpcid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'public ip address id of the vpn gateway'}], u'requiredparams': [u'vpcid'], u'description': u'Creates site to site vpn local gateway'}, u'autoscalevmgroup': {u'name': u'createAutoScaleVmGroup', u'related': [u'updateAutoScaleVmGroup'], u'isasync': True, u'params': [{u'name': u'vmprofileid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the autoscale profile that contains information about the vms in the vm group.'}, {u'name': u'scaledownpolicyids', u'required': True, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'list', u'description': u'list of scaledown autoscale policies'}, {u'name': u'scaleuppolicyids', u'required': True, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'list', u'description': u'list of scaleup autoscale policies'}, {u'name': u'interval', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the frequency at which the conditions have to be evaluated'}, {u'name': u'minmembers', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the minimum number of members in the vmgroup, the number of instances in the vm group will be equal to or more than this number.'}, {u'name': u'maxmembers', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the maximum number of members in the vmgroup, The number of instances in the vm group will be equal to or less than this number.'}, {u'name': u'lbruleid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}], u'requiredparams': [u'vmprofileid', u'scaledownpolicyids', u'scaleuppolicyids', u'minmembers', u'maxmembers', u'lbruleid'], u'description': u'Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.'}, u'networkacl': {u'name': u'createNetworkACL', u'related': [], u'isasync': True, u'params': [{u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the ending port of ACL'}, {u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the traffic type for the ACL,can be Ingress or Egress, defaulted to Ingress if not specified'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to allow traffic from/to'}, {u'name': u'networkid', u'required': True, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The network of the vm the ACL will be created for'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the ACL rule. Valid values are TCP/UDP/ICMP.'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the starting port of ACL'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}], u'requiredparams': [u'networkid', u'protocol'], u'description': u'Creates a ACL rule the given network (the network has to belong to VPC)'}, u'template': {u'name': u'createTemplate', u'related': [u'cancelStorageMaintenance', u'enableStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'isasync': True, u'params': [{u'name': u'ostypeid', u'required': True, u'related': [u'listOsTypes'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS Type that best represents the OS of this template.'}, {u'name': u'templatetag', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the tag for this template.'}, {u'name': u'bits', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'32 or 64 bit'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this template is a public template, false otherwise'}, {u'name': u'volumeid', u'required': False, u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume the template is being created from. Either this parameter, or snapshotId has to be passed in'}, {u'name': u'passwordenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template supports the password reset feature; default is false'}, {u'name': u'snapshotid', u'required': False, u'related': [u'createSnapshot', u'listSnapshots'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the snapshot the template is being created from. Either this parameter, or volumeId has to be passed in'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Optional, VM ID. If this presents, it is going to create a baremetal template for VM this ID refers to. This is only for VM whose hypervisor type is BareMetal'}, {u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Optional, only for baremetal hypervisor. The directory name where template stored on CIFS server'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the template. This is usually used for display purposes.'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'Template details in key/value pairs.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the template'}, {u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this template is a featured template, false otherwise'}, {u'name': u'requireshvm', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template requires HVM, false otherwise'}], u'requiredparams': [u'ostypeid', u'displaytext', u'name'], u'description': u'Creates a template of a virtual machine. The virtual machine must be in a STOPPED state. A template created from this command is automatically designated as a private template visible to the account that created it.'}, u'privategateway': {u'name': u'createPrivateGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'vlan', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the Vlan for the private gateway'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the Private gateway'}, {u'name': u'netmask', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask of the Private gateway'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID the network belongs to'}, {u'name': u'vpcid', u'required': True, u'related': [u'restartVPC'], u'length': 255, u'type': u'uuid', u'description': u'the VPC network belongs to'}, {u'name': u'ipaddress', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the IP address of the Private gateaway'}], u'requiredparams': [u'vlan', u'gateway', u'netmask', u'vpcid', u'ipaddress'], u'description': u'Creates a private gateway'}, u'volumeonfiler': {u'name': u'createVolumeOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'volumename', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'volume name.'}, {u'name': u'aggregatename', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'aggregate name.'}, {u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}, {u'name': u'snapshotpolicy', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'snapshot policy.'}, {u'name': u'ipaddress', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'ip address.'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'password.'}, {u'name': u'size', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'volume size.'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'user name.'}, {u'name': u'snapshotreservation', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'snapshot reservation.'}], u'requiredparams': [u'volumename', u'aggregatename', u'poolname', u'ipaddress', u'password', u'size', u'username'], u'description': u'Create a volume'}, u'staticroute': {u'name': u'createStaticRoute', u'related': [], u'isasync': True, u'params': [{u'name': u'gatewayid', u'required': True, u'related': [u'createPrivateGateway'], u'length': 255, u'type': u'uuid', u'description': u'the gateway id we are creating static route for'}, {u'name': u'cidr', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'static route cidr'}], u'requiredparams': [u'gatewayid', u'cidr'], u'description': u'Creates a static route'}, u'volume': {u'name': u'createVolume', u'related': [u'detachVolume', u'uploadVolume'], u'isasync': True, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the disk volume'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the availability zone'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'the project associated with the volume. Mutually exclusive with account parameter'}, {u'name': u'diskofferingid', u'required': False, u'related': [u'updateDiskOffering', u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk offering. Either diskOfferingId or snapshotId must be passed in.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the disk volume. Must be used with the domainId parameter.'}, {u'name': u'size', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Arbitrary volume size'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the disk offering. If used with the account parameter returns the disk volume associated with the account for the specified domain.'}, {u'name': u'snapshotid', u'required': False, u'related': [u'createSnapshot', u'listSnapshots'], u'length': 255, u'type': u'uuid', u'description': u'the snapshot ID for the disk volume. Either diskOfferingId or snapshotId must be passed in.'}], u'requiredparams': [u'name'], u'description': u'Creates a disk volume from a disk offering. This disk volume must still be attached to a virtual machine to make use of it.'}, u'user': {u'name': u'createUser', u'related': [u'lockUser', u'listUsers'], u'isasync': False, u'params': [{u'name': u'account', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Creates the user under the specified account. If no account is specified, the username will be used as the account name.'}, {u'name': u'userid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'User UUID, required for adding account from external provisioning system'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Unique username.'}, {u'name': u'timezone', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Creates the user under the specified domain. Has to be accompanied with the account parameter'}, {u'name': u'email', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'email'}, {u'name': u'lastname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'lastname'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.'}, {u'name': u'firstname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'firstname'}], u'requiredparams': [u'account', u'username', u'email', u'lastname', u'password', u'firstname'], u'description': u'Creates a user for an account that already exists'}, u'vpc': {u'name': u'createVPC', u'related': [u'updateVPC', u'restartVPC', u'listVPCs'], u'isasync': True, u'params': [{u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the VPC'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the availability zone'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the VPC'}, {u'name': u'vpcofferingid', u'required': True, u'related': [u'listVPCOfferings', u'createVPCOffering'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the VPC offering'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'VPC network domain. All networks inside the VPC will belong to this domain'}, {u'name': u'cidr', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u"the cidr of the VPC. All VPC guest networks' cidrs should be within this CIDR"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the VPC. Must be used with the domainId parameter.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the VPC. If used with the account parameter returns the VPC associated with the account for the specified domain.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'create VPC for the project'}], u'requiredparams': [u'displaytext', u'zoneid', u'name', u'vpcofferingid', u'cidr'], u'description': u'Creates a VPC'}, u'storagenetworkiprange': {u'name': u'createStorageNetworkIpRange', u'related': [u'listStorageNetworkIpRange', u'updateStorageNetworkIpRange'], u'isasync': True, u'params': [{u'name': u'startip', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IP address'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Optional. The vlan the ip range sits on, default to Null when it is not specified which means you network is not on any Vlan. This is mainly for Vmware as other hypervisors can directly reterive bridge from pyhsical network traffic type table'}, {u'name': u'podid', u'required': True, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'UUID of pod where the ip range belongs to'}, {u'name': u'netmask', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask for storage network'}, {u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway for storage network'}], u'requiredparams': [u'startip', u'podid', u'netmask', u'gateway'], u'description': u'Creates a Storage network IP range.'}, u'pool': {u'name': u'createPool', u'related': [], u'isasync': False, u'params': [{u'name': u'algorithm', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'algorithm.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'algorithm', u'name'], u'description': u'Create a pool'}, u'autoscalevmprofile': {u'name': u'createAutoScaleVmProfile', u'related': [u'updateAutoScaleVmProfile', u'listAutoScaleVmProfiles'], u'isasync': True, u'params': [{u'name': u'otherdeployparams', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'parameters other than zoneId/serviceOfferringId/templateId of the auto deployed virtual machine'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'availability zone for the auto deployed virtual machine'}, {u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering', u'updateServiceOffering'], u'length': 255, u'type': u'uuid', u'description': u'the service offering of the auto deployed virtual machine'}, {u'name': u'expungevmgraceperiod', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the time allowed for existing connections to get closed before a vm is destroyed'}, {u'name': u'counterparam', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'counterparam list. Example: counterparam[0].name=snmpcommunity&counterparam[0].value=public&counterparam[1].name=snmpport&counterparam[1].value=161'}, {u'name': u'templateid', u'required': True, u'related': [u'registerIso', u'updateTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template of the auto deployed virtual machine'}, {u'name': u'autoscaleuserid', u'required': False, u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser', u'updateUser'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the user used to launch and destroy the VMs'}], u'requiredparams': [u'zoneid', u'serviceofferingid', u'templateid'], u'description': u'Creates a profile that contains information about the virtual machine which will be provisioned automatically by autoscale feature.'}, u'account': {u'name': u'createAccount', u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser', u'getUser', u'updateUser'], u'isasync': False, u'params': [{u'name': u'lastname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'lastname'}, {u'name': u'accounttype', u'required': True, u'related': [], u'length': 255, u'type': u'short', u'description': u'Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Unique username.'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.'}, {u'name': u'firstname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'firstname'}, {u'name': u'userid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'User UUID, required for adding account from external provisioning system'}, {u'name': u'timezone', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Creates the user under the specified account. If no account is specified, the username will be used as the account name.'}, {u'name': u'accountdetails', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'details for account used to store specific parameters'}, {u'name': u'email', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'email'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"Network domain for the account's networks"}, {u'name': u'accountid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Account UUID, required for adding account from external provisioning system'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'Creates the user under the specified domain.'}], u'requiredparams': [u'lastname', u'accounttype', u'username', u'password', u'firstname', u'email'], u'description': u'Creates an account'}, u'firewallrule': {u'name': u'createFirewallRule', u'related': [u'listEgressFirewallRules'], u'isasync': True, u'params': [{u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the firewall rule. Valid values are TCP/UDP/ICMP.'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of firewallrule: system/user'}, {u'name': u'ipaddressid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the IP address id of the port forwarding rule'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the starting port of firewall rule'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}, {u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the ending port of firewall rule'}], u'requiredparams': [u'protocol', u'ipaddressid'], u'description': u'Creates a firewall rule for a given ip address'}, u'networkoffering': {u'name': u'createNetworkOffering', u'related': [u'updateNetworkOffering'], u'isasync': False, u'params': [{u'name': u'serviceproviderlist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'provider to service mapping. If not specified, the provider for the service will be mapped to the default provider on the physical network'}, {u'name': u'serviceofferingid', u'required': False, u'related': [u'updateHypervisorCapabilities'], u'length': 255, u'type': u'uuid', u'description': u'the service offering ID used by virtual router provider'}, {u'name': u'supportedservices', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'services supported by the network offering'}, {u'name': u'networkrate', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'data transfer rate in megabits per second allowed'}, {u'name': u'ispersistent', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network offering supports persistent networks; defaulted to false if not specified'}, {u'name': u'servicecapabilitylist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'desired service capabilities as part of network offering'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the network offering'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the tags for the network offering.'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the network offering'}, {u'name': u'conservemode', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the network offering is IP conserve mode enabled'}, {u'name': u'guestiptype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'guest type of the network offering: Shared or Isolated'}, {u'name': u'traffictype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the traffic type for the network offering. Supported type in current release is GUEST only'}, {u'name': u'specifyvlan', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network offering supports vlans'}, {u'name': u'availability', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the availability of network offering. Default value is Optional'}, {u'name': u'specifyipranges', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network offering supports specifying ip ranges; defaulted to false if not specified'}], u'requiredparams': [u'supportedservices', u'name', u'displaytext', u'guestiptype', u'traffictype'], u'description': u'Creates a network offering.'}, u'vlaniprange': {u'name': u'createVlanIpRange', u'related': [u'listVlanIpRanges'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'domain ID of the account owning a VLAN'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'project who will own the VLAN. If VLAN is Zone wide, this parameter should be ommited'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ID or VID of the VLAN. If not specified, will be defaulted to the vlan of the network or if vlan of the network is null - to Untagged'}, {u'name': u'networkid', u'required': False, u'related': [u'createNetwork', u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the network id'}, {u'name': u'forvirtualnetwork', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if VLAN is of Virtual type, false if Direct'}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'optional parameter. Have to be specified for Direct Untagged vlan only.'}, {u'name': u'ip6cidr', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the CIDR of IPv6 network, must be at least /64'}, {u'name': u'endipv6', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IPv6 address in the IPv6 network range'}, {u'name': u'startip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IP address in the VLAN IP range'}, {u'name': u'startipv6', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IPv6 address in the IPv6 network range'}, {u'name': u'gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the VLAN IP range'}, {u'name': u'netmask', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask of the VLAN IP range'}, {u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address in the VLAN IP range'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'account who will own the VLAN. If VLAN is Zone wide, this parameter should be ommited'}, {u'name': u'ip6gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway of the IPv6 network. Required for Shared networks and Isolated networks when it belongs to VPC'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the physical network id'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the VLAN IP range'}], u'requiredparams': [], u'description': u'Creates a VLAN IP range.'}, u'counter': {u'name': u'createCounter', u'related': [u'listCounters'], u'isasync': True, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the counter.'}, {u'name': u'source', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Source of the counter.'}, {u'name': u'value', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Value of the counter e.g. oid in case of snmp.'}], u'requiredparams': [u'name', u'source', u'value'], u'description': u'Adds metric counter'}, u'lunonfiler': {u'name': u'createLunOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'size', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'LUN size.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'size', u'name'], u'description': u'Create a LUN from a pool'}, u'project': {u'name': u'createProject', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'account who will be Admin for the project'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the project'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'domain ID of the account owning a project'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'display text of the project'}], u'requiredparams': [u'name', u'displaytext'], u'description': u'Creates a project'}, u'physicalnetwork': {u'name': u'createPhysicalNetwork', u'related': [u'listPhysicalNetworks'], u'isasync': True, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the physical network'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the physical network'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'Tag the physical network'}, {u'name': u'networkspeed', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the speed for the physical network[1G/10G]'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the VLAN for the physical network'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'domain ID of the account owning a physical network'}, {u'name': u'broadcastdomainrange', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the broadcast domain range for the physical network[Pod or Zone]. In Acton release it can be Zone only in Advance zone, and Pod in Basic'}, {u'name': u'isolationmethods', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the isolation method for the physical network[VLAN/L3/GRE]'}], u'requiredparams': [u'name', u'zoneid'], u'description': u'Creates a physical network'}, u'snapshot': {u'name': u'createSnapshot', u'related': [u'listSnapshots'], u'isasync': True, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The domain ID of the snapshot. If used with the account parameter, specifies a domain for the account associated with the disk volume.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The account of the snapshot. The account parameter must be used with the domainId parameter.'}, {u'name': u'volumeid', u'required': True, u'related': [u'detachVolume'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the disk volume'}, {u'name': u'policyid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'policy id of the snapshot, if this is null, then use MANUAL_POLICY.'}], u'requiredparams': [u'volumeid'], u'description': u'Creates an instant snapshot of a volume.'}, u'virtualrouterelement': {u'name': u'createVirtualRouterElement', u'related': [], u'isasync': True, u'params': [{u'name': u'nspid', u'required': True, u'related': [u'updateNetworkServiceProvider'], u'length': 255, u'type': u'uuid', u'description': u'the network service provider ID of the virtual router element'}], u'requiredparams': [u'nspid'], u'description': u'Create a virtual router element.'}, u'egressfirewallrule': {u'name': u'createEgressFirewallRule', u'related': [u'createFirewallRule', u'listEgressFirewallRules'], u'isasync': True, u'params': [{u'name': u'networkid', u'required': True, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the network id of the port forwarding rule'}, {u'name': u'startport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the starting port of firewall rule'}, {u'name': u'icmpcode', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'error code for this icmp message'}, {u'name': u'icmptype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'type of the icmp message being sent'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the cidr list to forward traffic from'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of firewallrule: system/user'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the firewall rule. Valid values are TCP/UDP/ICMP.'}, {u'name': u'endport', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the ending port of firewall rule'}], u'requiredparams': [u'networkid', u'protocol'], u'description': u'Creates a egress firewall rule for a given network '}, u'sshkeypair': {u'name': u'createSSHKeyPair', u'related': [u'listSSHKeyPairs'], u'isasync': False, u'params': [{u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'an optional project for the ssh key'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the ssh key. If the account parameter is used, domainId must also be used.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the keypair'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the ssh key. Must be used with domainId.'}], u'requiredparams': [u'name'], u'description': u'Create a new keypair and returns the private key'}}, u'deploy': {u'virtualmachine': {u'name': u'deployVirtualMachine', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'keypair', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the ssh key pair used to login to the virtual machine'}, {u'name': u'userdata', u'required': False, u'related': [], u'length': 2048, u'type': u'string', u'description': u'an optional binary data that can be sent to the virtual machine upon a successful deployment. This binary data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. Using HTTP GET (via querystring), you can send up to 2KB of data after base64 encoding.'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the hypervisor on which to deploy the virtual machine'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.'}, {u'name': u'size', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId'}, {u'name': u'diskofferingid', u'required': False, u'related': [u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk offering for the virtual machine. If the template is of ISO format, the diskOfferingId is for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk volume. If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk Volume created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT Disk Volume created.'}, {u'name': u'securitygroupids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma separated list of security groups id that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupnames parameter'}, {u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the service offering for the virtual machine'}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"the ip address for default vm's network"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the virtual machine. Must be used with domainId.'}, {u'name': u'hostid', u'required': False, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'destination Host ID to deploy the VM to - parameter available for root admin only'}, {u'name': u'iptonetworklist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u"ip to network mapping. Can't be specified with networkIds parameter. Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].ipv6=fc00:1234:5678::abcd&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid"}, {u'name': u'ip6address', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"the ipv6 address for default vm's network"}, {u'name': u'keyboard', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'Deploy vm for the project'}, {u'name': u'networkids', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'list', u'description': u"list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter"}, {u'name': u'displayname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional user generated name for the virtual machine'}, {u'name': u'securitygroupnames', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma separated list of security groups names that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupids parameter'}, {u'name': u'templateid', u'required': True, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the template for the virtual machine'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'availability zone for the virtual machine'}, {u'name': u'group', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional group for the virtual machine'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'host name for the virtual machine'}, {u'name': u'startvm', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network offering supports specifying ip ranges; defaulted to true if not specified'}], u'requiredparams': [u'serviceofferingid', u'templateid', u'zoneid'], u'description': u'Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.'}}, u'restart': {u'network': {u'name': u'restartNetwork', u'related': [u'associateIpAddress'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The id of the network to restart.'}, {u'name': u'cleanup', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'If cleanup old network elements'}], u'requiredparams': [u'id'], u'description': u'Restarts the network; includes 1) restarting network elements - virtual routers, dhcp servers 2) reapplying all public ips 3) reapplying loadBalancing/portForwarding rules'}, u'vpc': {u'name': u'restartVPC', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': False, u'related': [u'restartVPC'], u'length': 255, u'type': u'uuid', u'description': u'the id of the VPC'}], u'requiredparams': [], u'description': u'Restarts a VPC'}}, u'reboot': {u'systemvm': {u'name': u'rebootSystemVm', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'rebootSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system virtual machine'}], u'requiredparams': [u'id'], u'description': u'Reboots a system VM.'}, u'router': {u'name': u'rebootRouter', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'rebootRouter'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the router'}], u'requiredparams': [u'id'], u'description': u'Starts a router.'}, u'virtualmachine': {u'name': u'rebootVirtualMachine', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Reboots a virtual machine.'}}, u'mark': {u'defaultzoneforaccount': {u'name': u'markDefaultZoneForAccount', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': True, u'related': [u'markDefaultZoneForAccount'], u'length': 255, u'type': u'string', u'description': u'Name of the account that is to be marked.'}, {u'name': u'domainid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Marks the account that belongs to the specified domain.'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The Zone ID with which the account is to be marked.'}], u'requiredparams': [u'account', u'domainid', u'zoneid'], u'description': u'Marks a default zone for this account'}}, u'start': {u'systemvm': {u'name': u'startSystemVm', u'related': [u'rebootSystemVm', u'listSystemVms', u'changeServiceForSystemVm'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startSystemVm', u'rebootSystemVm', u'listSystemVms', u'changeServiceForSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system virtual machine'}], u'requiredparams': [u'id'], u'description': u'Starts a system virtual machine.'}, u'router': {u'name': u'startRouter', u'related': [u'destroyRouter', u'rebootRouter'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'destroyRouter', u'rebootRouter', u'startRouter'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the router'}], u'requiredparams': [u'id'], u'description': u'Starts a router.'}, u'virtualmachine': {u'name': u'startVirtualMachine', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'hostid', u'required': False, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'destination Host ID to deploy the VM to - parameter available for root admin only'}], u'requiredparams': [u'id'], u'description': u'Starts a virtual machine.'}}, u'add': {u'trafficmonitor': {u'name': u'addTrafficMonitor', u'related': [u'listTrafficMonitors'], u'isasync': False, u'params': [{u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the traffic monitor Host'}, {u'name': u'includezones', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Traffic going into the listed zones will be metered'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'Zone in which to add the external firewall appliance.'}, {u'name': u'excludezones', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Traffic going into the listed zones will not be metered'}], u'requiredparams': [u'url', u'zoneid'], u'description': u'Adds Traffic Monitor Host for Direct Network Usage'}, u'secondarystorage': {u'name': u'addSecondaryStorage', u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the secondary storage'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL for the secondary storage'}], u'requiredparams': [u'url'], u'description': u'Adds secondary storage.'}, u'nictovirtualmachine': {u'name': u'addNicToVirtualMachine', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'networkid', u'required': True, u'related': [u'createNetwork', u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'Network ID'}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'IP Address for the new network'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'addNicToVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Virtual Machine ID'}], u'requiredparams': [u'networkid', u'virtualmachineid'], u'description': u'Adds VM to specified network by creating a NIC'}, u'netscalerloadbalancer': {u'name': u'addNetscalerLoadBalancer', u'related': [u'listNetscalerLoadBalancers', u'configureNetscalerLoadBalancer'], u'isasync': True, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach netscaler load balancer device'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach netscaler load balancer device'}, {u'name': u'networkdevicetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Netscaler device type supports NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the netscaler load balancer appliance.'}], u'requiredparams': [u'password', u'physicalnetworkid', u'username', u'networkdevicetype', u'url'], u'description': u'Adds a netscaler load balancer device'}, u'cluster': {u'name': u'addCluster', u'related': [u'listClusters', u'updateCluster'], u'isasync': False, u'params': [{u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this cluster for allocation of new resources'}, {u'name': u'vsmpassword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the password for the VSM associated with this cluster'}, {u'name': u'podid', u'required': True, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the host'}, {u'name': u'vsmipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ipaddress of the VSM associated with this cluster'}, {u'name': u'hypervisor', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the cluster: XenServer,KVM,VMware,Hyperv,BareMetal,Simulator'}, {u'name': u'vsmusername', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the VSM associated with this cluster'}, {u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the cluster'}, {u'name': u'clustertype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of the cluster: CloudManaged, ExternalManaged'}, {u'name': u'clustername', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the cluster name'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the cluster'}, {u'name': u'password', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the password for the host'}], u'requiredparams': [u'podid', u'hypervisor', u'clustertype', u'clustername', u'zoneid'], u'description': u'Adds a new cluster'}, u's3': {u'name': u'addS3', u'related': [], u'isasync': False, u'params': [{u'name': u'connectiontimeout', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'connection timeout (milliseconds)'}, {u'name': u'accesskey', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'S3 access key'}, {u'name': u'bucket', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the template storage bucket'}, {u'name': u'endpoint', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'S3 host name'}, {u'name': u'secretkey', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'S3 secret key'}, {u'name': u'sockettimeout', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'socket timeout (milliseconds)'}, {u'name': u'maxerrorretry', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'maximum number of times to retry on error'}, {u'name': u'usehttps', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'connect to the S3 endpoint via HTTPS?'}], u'requiredparams': [u'accesskey', u'bucket', u'secretkey'], u'description': u'Adds S3'}, u'accounttoproject': {u'name': u'addAccountToProject', u'related': [], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the account to be added to the project'}, {u'name': u'email', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'email to which invitation to the project is going to be sent'}, {u'name': u'projectid', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to add the account to'}], u'requiredparams': [u'projectid'], u'description': u'Adds account to a project'}, u'region': {u'name': u'addRegion', u'related': [], u'isasync': False, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the region'}, {u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Id of the Region'}, {u'name': u'endpoint', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Region service endpoint'}], u'requiredparams': [u'name', u'id', u'endpoint'], u'description': u'Adds a Region'}, u'externalloadbalancer': {u'name': u'addExternalLoadBalancer', u'related': [], u'isasync': False, u'params': [{u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Username of the external load balancer appliance.'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the external load balancer appliance.'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Password of the external load balancer appliance.'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'Zone in which to add the external load balancer appliance.'}], u'requiredparams': [u'username', u'url', u'password', u'zoneid'], u'description': u'Adds F5 external load balancer appliance.'}, u'vpnuser': {u'name': u'addVpnUser', u'related': [u'listVpnUsers'], u'isasync': True, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'password for the username'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'username for the vpn user'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the vpn user. Must be used with domainId.'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the vpn user. If the account parameter is used, domainId must also be used.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'add vpn user to the specific project'}], u'requiredparams': [u'password', u'username'], u'description': u'Adds vpn users'}, u'baremetalhost': {u'name': u'addBaremetalHost', u'related': [u'listSwifts', u'addHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'isasync': False, u'params': [{u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'ip address intentionally allocated to this host after provisioning'}, {u'name': u'hosttags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of tags to be added to the host'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the host URL'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the host'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the host'}, {u'name': u'clustername', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the cluster name for the host'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID for the host'}, {u'name': u'hypervisor', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the host'}, {u'name': u'podid', u'required': True, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the host'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the password for the host'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this Host for allocation of new resources'}], u'requiredparams': [u'url', u'username', u'zoneid', u'hypervisor', u'podid', u'password'], u'description': u'add a baremetal host'}, u'traffictype': {u'name': u'addTrafficType', u'related': [u'updateTrafficType'], u'isasync': True, u'params': [{u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The VLAN id to be used for Management traffic by VMware host'}, {u'name': u'kvmnetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a KVM host'}, {u'name': u'traffictype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the trafficType to be added to the physical network'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'vmwarenetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a VMware host'}, {u'name': u'xennetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a XenServer host'}], u'requiredparams': [u'traffictype', u'physicalnetworkid'], u'description': u'Adds traffic type to a physical network'}, u'niciranvpdevice': {u'name': u'addNiciraNvpDevice', u'related': [], u'isasync': True, u'params': [{u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'hostname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hostname of ip address of the Nicira NVP Controller.'}, {u'name': u'l3gatewayserviceuuid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The L3 Gateway Service UUID configured on the Nicira Controller'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to access the Nicira Controller API'}, {u'name': u'transportzoneuuid', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'The Transportzone UUID configured on the Nicira Controller'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to access the Nicira Controller API'}], u'requiredparams': [u'physicalnetworkid', u'hostname', u'username', u'transportzoneuuid', u'password'], u'description': u'Adds a Nicira NVP device'}, u'host': {u'name': u'addHost', u'related': [u'updateHost', u'listHosts'], u'isasync': False, u'params': [{u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the host'}, {u'name': u'podid', u'required': True, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the host'}, {u'name': u'clustername', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the cluster name for the host'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the host'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the host URL'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID for the host'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the password for the host'}, {u'name': u'hosttags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of tags to be added to the host'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this Host for allocation of new resources'}, {u'name': u'hypervisor', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the host'}], u'requiredparams': [u'username', u'podid', u'zoneid', u'url', u'password', u'hypervisor'], u'description': u'Adds a new host.'}, u'f5loadbalancer': {u'name': u'addF5LoadBalancer', u'related': [u'configureF5LoadBalancer', u'listF5LoadBalancers'], u'isasync': True, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach F5 BigIP load balancer device'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach F5 BigIP load balancer device'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'networkdevicetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'supports only F5BigIpLoadBalancer'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the F5 load balancer appliance.'}], u'requiredparams': [u'password', u'username', u'physicalnetworkid', u'networkdevicetype', u'url'], u'description': u'Adds a F5 BigIP load balancer device'}, u'networkdevice': {u'name': u'addNetworkDevice', u'related': [], u'isasync': False, u'params': [{u'name': u'networkdevicetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network device type, now supports ExternalDhcp, PxeServer, NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer, F5BigIpLoadBalancer, JuniperSRXFirewall'}, {u'name': u'networkdeviceparameterlist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'parameters for network device'}], u'requiredparams': [], u'description': u'Adds a network device of one of the following types: ExternalDhcp, ExternalFirewall, ExternalLoadBalancer, PxeServer'}, u'bigswitchvnsdevice': {u'name': u'addBigSwitchVnsDevice', u'related': [], u'isasync': True, u'params': [{u'name': u'physicalnetworkid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'hostname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hostname of ip address of the BigSwitch VNS Controller.'}], u'requiredparams': [u'physicalnetworkid', u'hostname'], u'description': u'Adds a BigSwitch VNS device'}, u'srxfirewall': {u'name': u'addSrxFirewall', u'related': [], u'isasync': True, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach SRX firewall device'}, {u'name': u'networkdevicetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'supports only JuniperSRXFirewall'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Credentials to reach SRX firewall device'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the SRX appliance.'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}], u'requiredparams': [u'password', u'networkdevicetype', u'username', u'url', u'physicalnetworkid'], u'description': u'Adds a SRX firewall device'}, u'swift': {u'name': u'addSwift', u'related': [u'listSwifts', u'addHost', u'updateHost', u'listHosts', u'listExternalLoadBalancers'], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account for swift'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL for swift'}, {u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for swift'}, {u'name': u'key', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u' key for the user for swift'}], u'requiredparams': [u'url'], u'description': u'Adds Swift.'}, u'externalfirewall': {u'name': u'addExternalFirewall', u'related': [], u'isasync': False, u'params': [{u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'URL of the external firewall appliance.'}, {u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Password of the external firewall appliance.'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Zone in which to add the external firewall appliance.'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Username of the external firewall appliance.'}], u'requiredparams': [u'url', u'password', u'zoneid', u'username'], u'description': u'Adds an external firewall appliance'}, u'networkserviceprovider': {u'name': u'addNetworkServiceProvider', u'related': [u'updateNetworkServiceProvider'], u'isasync': True, u'params': [{u'name': u'destinationphysicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the destination Physical Network ID to bridge to'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name for the physical network service provider'}, {u'name': u'servicelist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the list of services to be enabled for this physical network service provider'}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID to add the provider to'}], u'requiredparams': [u'name', u'physicalnetworkid'], u'description': u'Adds a network serviceProvider to a physical network'}}, u'verbs': [u'authorize', u'restore', u'suspend', u'revoke', u'disassociate', u'migrate', u'lock', u'dissociate', u'activate', u'reconnect', u'cancel', u'query', u'recover', u'extract', u'detach', u'prepare', u'start', u'create', u'associate', u'reboot', u'mark', u'attach', u'add', u'change', u'deploy', u'ldap', u'destroy', u'enable', u'configure', u'get', u'modify', u'stop', u'update', u'disable', u'resize', u'copy', u'generate', u'restart', u'reset', u'register', u'list', u'upload', u'remove', u'assign', u'delete'], u'resize': {u'volume': {u'name': u'resizeVolume', u'related': [u'detachVolume', u'uploadVolume', u'createVolume'], u'isasync': True, u'params': [{u'name': u'diskofferingid', u'required': False, u'related': [u'updateDiskOffering', u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'new disk offering id'}, {u'name': u'id', u'required': False, u'related': [u'detachVolume', u'resizeVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'shrinkok', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Verify OK to Shrink'}, {u'name': u'size', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'New volume size in G'}], u'requiredparams': [], u'description': u'Resizes a volume'}}, u'ldap': {u'config': {u'name': u'ldapConfig', u'related': [u'ldapRemove'], u'isasync': False, u'params': [{u'name': u'hostname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hostname or ip address of the ldap server eg: my.ldap.com'}, {u'name': u'ssl', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Check Use SSL if the external LDAP server is configured for LDAP over SSL.'}, {u'name': u'truststore', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enter the path to trust certificates store.'}, {u'name': u'queryfilter', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'You specify a query filter here, which narrows down the users, who can be part of this domain.'}, {u'name': u'searchbase', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com.'}, {u'name': u'port', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Specify the LDAP port if required, default is 389.'}, {u'name': u'binddn', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specify the distinguished name of a user with the search permission on the directory.'}, {u'name': u'truststorepass', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enter the password for trust store.'}, {u'name': u'bindpass', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enter the password.'}], u'requiredparams': [u'hostname', u'queryfilter', u'searchbase'], u'description': u'Configure the LDAP context for this site.'}, u'remove': {u'name': u'ldapRemove', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'Remove the LDAP context for this site.'}}, u'destroy': {u'systemvm': {u'name': u'destroySystemVm', u'related': [u'startSystemVm', u'rebootSystemVm', u'listSystemVms', u'stopSystemVm', u'changeServiceForSystemVm'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startSystemVm', u'destroySystemVm', u'rebootSystemVm', u'listSystemVms', u'stopSystemVm', u'changeServiceForSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system virtual machine'}], u'requiredparams': [u'id'], u'description': u'Destroyes a system virtual machine.'}, u'router': {u'name': u'destroyRouter', u'related': [u'rebootRouter'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'destroyRouter', u'rebootRouter'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the router'}], u'requiredparams': [u'id'], u'description': u'Destroys a router.'}, u'volumeonfiler': {u'name': u'destroyVolumeOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'volumename', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'volume name.'}, {u'name': u'ipaddress', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'ip address.'}, {u'name': u'aggregatename', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'aggregate name.'}], u'requiredparams': [u'volumename', u'ipaddress', u'aggregatename'], u'description': u'Destroy a Volume'}, u'lunonfiler': {u'name': u'destroyLunOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'path', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'LUN path.'}], u'requiredparams': [u'path'], u'description': u'Destroy a LUN'}, u'virtualmachine': {u'name': u'destroyVirtualMachine', u'related': [u'listVirtualMachines'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listVirtualMachines', u'destroyVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Destroys a virtual machine. Once destroyed, only the administrator can recover it.'}}, u'get': {u'apilimit': {u'name': u'getApiLimit', u'related': [u'resetApiLimit'], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'Get API limit count for the caller'}, u'vmpassword': {u'name': u'getVMPassword', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Returns an encrypted password for the VM'}, u'user': {u'name': u'getUser', u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser', u'updateUser'], u'isasync': False, u'params': [{u'name': u'userapikey', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'API key of the user'}], u'requiredparams': [u'userapikey'], u'description': u'Find user account by API key'}, u'cloudidentifier': {u'name': u'getCloudIdentifier', u'related': [], u'isasync': False, u'params': [{u'name': u'userid', u'required': True, u'related': [u'lockUser', u'listUsers', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'the user ID for the cloud identifier'}], u'requiredparams': [u'userid'], u'description': u'Retrieves a cloud identifier.'}}, u'count': 355, u'enable': {u'account': {u'name': u'enableAccount', u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount', u'disableAccount'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'Enables specified account in this domain.'}, {u'name': u'id', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount', u'enableAccount', u'disableAccount'], u'length': 255, u'type': u'uuid', u'description': u'Account id'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enables specified account.'}], u'requiredparams': [], u'description': u'Enables an account'}, u'storagemaintenance': {u'name': u'enableStorageMaintenance', u'related': [u'cancelStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'cancelStorageMaintenance', u'enableStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'length': 255, u'type': u'uuid', u'description': u'Primary storage ID'}], u'requiredparams': [u'id'], u'description': u'Puts storage pool into maintenance state'}, u'cisconexusvsm': {u'name': u'enableCiscoNexusVSM', u'related': [u'disableCiscoNexusVSM'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableCiscoNexusVSM', u'enableCiscoNexusVSM'], u'length': 255, u'type': u'uuid', u'description': u'Id of the Cisco Nexus 1000v VSM device to be enabled'}], u'requiredparams': [u'id'], u'description': u'Enable a Cisco Nexus VSM device'}, u'staticnat': {u'name': u'enableStaticNat', u'related': [], u'isasync': False, u'params': [{u'name': u'ipaddressid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the public IP address id for which static nat feature is being enabled'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine for enabling static nat feature'}, {u'name': u'networkid', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The network of the vm the static nat will be enabled for. Required when public Ip address is not associated with any Guest network yet (VPC case)'}], u'requiredparams': [u'ipaddressid', u'virtualmachineid'], u'description': u'Enables static nat for given ip address'}, u'user': {u'name': u'enableUser', u'related': [u'lockUser', u'listUsers', u'createUser'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'Enables user by user ID.'}], u'requiredparams': [u'id'], u'description': u'Enables a user account'}, u'autoscalevmgroup': {u'name': u'enableAutoScaleVmGroup', u'related': [u'createAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale group'}], u'requiredparams': [u'id'], u'description': u'Enables an AutoScale Vm Group'}}, u'configure': {u'srxfirewall': {u'name': u'configureSrxFirewall', u'related': [u'listSrxFirewalls', u'addSrxFirewall'], u'isasync': True, u'params': [{u'name': u'fwdeviceid', u'required': True, u'related': [u'listSrxFirewalls', u'configureSrxFirewall', u'addSrxFirewall'], u'length': 255, u'type': u'uuid', u'description': u'SRX firewall device ID'}, {u'name': u'fwdevicecapacity', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'capacity of the firewall device, Capacity will be interpreted as number of networks device can handle'}], u'requiredparams': [u'fwdeviceid'], u'description': u'Configures a SRX firewall device'}, u'f5loadbalancer': {u'name': u'configureF5LoadBalancer', u'related': [], u'isasync': True, u'params': [{u'name': u'lbdeviceid', u'required': True, u'related': [u'configureF5LoadBalancer'], u'length': 255, u'type': u'uuid', u'description': u'F5 load balancer device ID'}, {u'name': u'lbdevicecapacity', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'capacity of the device, Capacity will be interpreted as number of networks device can handle'}], u'requiredparams': [u'lbdeviceid'], u'description': u'configures a F5 load balancer device'}, u'netscalerloadbalancer': {u'name': u'configureNetscalerLoadBalancer', u'related': [u'listNetscalerLoadBalancers'], u'isasync': True, u'params': [{u'name': u'podids', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'list', u'description': u"Used when NetScaler device is provider of EIP service. This parameter represents the list of pod's, for which there exists a policy based route on datacenter L3 router to route pod's subnet IP to a NetScaler device."}, {u'name': u'lbdevicecapacity', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'capacity of the device, Capacity will be interpreted as number of networks device can handle'}, {u'name': u'lbdeviceid', u'required': True, u'related': [u'listNetscalerLoadBalancers', u'configureNetscalerLoadBalancer'], u'length': 255, u'type': u'uuid', u'description': u'Netscaler load balancer device ID'}, {u'name': u'inline', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if netscaler load balancer is intended to be used in in-line with firewall, false if netscaler load balancer will side-by-side with firewall'}, {u'name': u'lbdevicededicated', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this netscaler device to dedicated for a account, false if the netscaler device will be shared by multiple accounts'}], u'requiredparams': [u'lbdeviceid'], u'description': u'configures a netscaler load balancer device'}, u'virtualrouterelement': {u'name': u'configureVirtualRouterElement', u'related': [u'createVirtualRouterElement'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createVirtualRouterElement', u'configureVirtualRouterElement'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual router provider'}, {u'name': u'enabled', u'required': True, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Enabled/Disabled the service provider'}], u'requiredparams': [u'id', u'enabled'], u'description': u'Configures a virtual router element.'}}, u'associate': {u'ipaddress': {u'name': u'associateIpAddress', u'related': [], u'isasync': True, u'params': [{u'name': u'networkid', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'The network this ip address should be associated to.'}, {u'name': u'vpcid', u'required': False, u'related': [u'restartVPC', u'listVPCs'], u'length': 255, u'type': u'uuid', u'description': u'the VPC you want the ip address to be associated with'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account to associate with this IP address'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the availability zone you want to acquire an public IP address from'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'Deploy vm for the project'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain to associate with this IP address'}], u'requiredparams': [], u'description': u'Acquires and associates a public IP to an account.'}, u'lun': {u'name': u'associateLun', u'related': [], u'isasync': False, u'params': [{u'name': u'iqn', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Guest IQN to which the LUN associate.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'LUN name.'}], u'requiredparams': [u'iqn', u'name'], u'description': u'Associate a LUN with a guest IQN'}}, u'stop': {u'systemvm': {u'name': u'stopSystemVm', u'related': [u'startSystemVm', u'rebootSystemVm', u'listSystemVms', u'changeServiceForSystemVm'], u'isasync': True, u'params': [{u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force stop the VM. The caller knows the VM is stopped.'}, {u'name': u'id', u'required': True, u'related': [u'startSystemVm', u'rebootSystemVm', u'listSystemVms', u'stopSystemVm', u'changeServiceForSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system virtual machine'}], u'requiredparams': [u'id'], u'description': u'Stops a system VM.'}, u'router': {u'name': u'stopRouter', u'related': [u'changeServiceForRouter', u'destroyRouter', u'rebootRouter', u'startRouter'], u'isasync': True, u'params': [{u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force stop the VM. The caller knows the VM is stopped.'}, {u'name': u'id', u'required': True, u'related': [u'changeServiceForRouter', u'stopRouter', u'destroyRouter', u'rebootRouter', u'startRouter'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the router'}], u'requiredparams': [u'id'], u'description': u'Stops a router.'}, u'virtualmachine': {u'name': u'stopVirtualMachine', u'related': [u'listVirtualMachines', u'destroyVirtualMachine'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force stop the VM (vm is marked as Stopped even when command fails to be send to the backend). The caller knows the VM is stopped.'}], u'requiredparams': [u'id'], u'description': u'Stops a virtual machine.'}}, u'modify': {u'pool': {u'name': u'modifyPool', u'related': [], u'isasync': False, u'params': [{u'name': u'algorithm', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'algorithm.'}, {u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'algorithm', u'poolname'], u'description': u'Modify pool'}}, u'update': {u'loadbalancerrule': {u'name': u'updateLoadBalancerRule', u'related': [], u'isasync': True, u'params': [{u'name': u'description', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the description of the load balancer rule'}, {u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id of the load balancer rule to update'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the load balancer rule'}, {u'name': u'algorithm', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'load balancer algorithm (source, roundrobin, leastconn)'}], u'requiredparams': [u'id'], u'description': u'Updates load balancer'}, u'domain': {u'name': u'updateDomain', u'related': [u'listDomainChildren', u'createDomain'], u'isasync': False, u'params': [{u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"Network domain for the domain's networks; empty string will update domainName with NULL value"}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'updates domain with this name'}, {u'name': u'id', u'required': True, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'ID of domain to update'}], u'requiredparams': [u'id'], u'description': u'Updates a domain with a new name'}, u'projectinvitation': {u'name': u'updateProjectInvitation', u'related': [], u'isasync': True, u'params': [{u'name': u'accept', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, accept the invitation, decline if false. True by default'}, {u'name': u'projectid', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to join'}, {u'name': u'token', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list invitations for specified account; this parameter has to be specified with domainId'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'account that is joining the project'}], u'requiredparams': [u'projectid'], u'description': u'Accepts or declines project invitation'}, u'diskoffering': {u'name': u'updateDiskOffering', u'related': [u'createDiskOffering', u'listDiskOfferings'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateDiskOffering', u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'ID of the disk offering'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'updates alternate display text of the disk offering with this value'}, {u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the disk offering, integer'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'updates name of the disk offering with this value'}], u'requiredparams': [u'id'], u'description': u'Updates a disk offering.'}, u'virtualmachine': {u'name': u'updateVirtualMachine', u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'displayname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'user generated name'}, {u'name': u'group', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'group of the virtual machine'}, {u'name': u'haenable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if high-availability is enabled for the virtual machine, false otherwise'}, {u'name': u'id', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'ostypeid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS type that best represents this VM.'}, {u'name': u'userdata', u'required': False, u'related': [], u'length': 2048, u'type': u'string', u'description': u'an optional binary data that can be sent to the virtual machine upon a successful deployment. This binary data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. Using HTTP GET (via querystring), you can send up to 2KB of data after base64 encoding.'}], u'requiredparams': [u'id'], u'description': u'Updates properties of a virtual machine. The VM has to be stopped and restarted for the new properties to take effect. UpdateVirtualMachine does not first check whether the VM is stopped. Therefore, stop the VM manually before issuing this call.'}, u'portforwardingrule': {u'name': u'updatePortForwardingRule', u'related': [u'listIpForwardingRules', u'listPortForwardingRules', u'createPortForwardingRule'], u'isasync': True, u'params': [{u'name': u'privateport', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the private port of the port forwarding rule'}, {u'name': u'publicport', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the public port of the port forwarding rule'}, {u'name': u'privateip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the private IP address of the port forwarding rule'}, {u'name': u'ipaddressid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the IP address id of the port forwarding rule'}, {u'name': u'protocol', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the protocol for the port fowarding rule. Valid values are TCP or UDP.'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine for the port forwarding rule'}], u'requiredparams': [u'privateport', u'publicport', u'ipaddressid', u'protocol'], u'description': u'Updates a port forwarding rule. Only the private port and the virtual machine can be updated.'}, u'cluster': {u'name': u'updateCluster', u'related': [], u'isasync': False, u'params': [{u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the cluster'}, {u'name': u'id', u'required': True, u'related': [u'updateCluster'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Cluster'}, {u'name': u'managedstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'whether this cluster is managed by cloudstack'}, {u'name': u'clustername', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the cluster name'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this cluster for allocation of new resources'}, {u'name': u'clustertype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'hypervisor type of the cluster'}], u'requiredparams': [u'id'], u'description': u'Updates an existing cluster'}, u'hostpassword': {u'name': u'updateHostPassword', u'related': [], u'isasync': False, u'params': [{u'name': u'password', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the new password for the host/cluster'}, {u'name': u'hostid', u'required': False, u'related': [u'listSwifts', u'addHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username for the host/cluster'}], u'requiredparams': [u'password', u'username'], u'description': u'Update password of a host/pool on management server.'}, u'pod': {u'name': u'updatePod', u'related': [], u'isasync': False, u'params': [{u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address for the Pod'}, {u'name': u'gateway', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the gateway for the Pod'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this cluster for allocation of new resources'}, {u'name': u'id', u'required': True, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Pod'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the Pod'}, {u'name': u'startip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the starting IP address for the Pod'}, {u'name': u'netmask', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask of the Pod'}], u'requiredparams': [u'id'], u'description': u'Updates a Pod.'}, u'isopermissions': {u'name': u'updateIsoPermissions', u'related': [], u'isasync': False, u'params': [{u'name': u'isextractable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template/iso is extractable, false other wise. Can be set only by root admin'}, {u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true for featured template/iso, false otherwise'}, {u'name': u'accounts', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'a comma delimited list of accounts. If specified, "op" parameter has to be passed in.'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true for public template/iso, false for private templates/isos'}, {u'name': u'projectids', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'list', u'description': u'a comma delimited list of projects. If specified, "op" parameter has to be passed in.'}, {u'name': u'op', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'permission operator (add, remove, reset)'}, {u'name': u'id', u'required': True, u'related': [u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}], u'requiredparams': [u'id'], u'description': u'Updates iso permissions'}, u'resourcelimit': {u'name': u'updateResourceLimit', u'related': [], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Update resource for a specified account. Must be used with the domainId parameter.'}, {u'name': u'resourcetype', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Type of resource to update. Values are 0, 1, 2, 3, and 4. 0 - Instance. Number of instances a user can create. 1 - IP. Number of public IP addresses a user can own. 2 - Volume. Number of disk volumes a user can create.3 - Snapshot. Number of snapshots a user can create.4 - Template. Number of templates that a user can register/create.'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Update resource limits for all accounts in specified domain. If used with the account parameter, updates resource limits for a specified account in specified domain.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Update resource limits for project'}, {u'name': u'max', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u' Maximum resource limit.'}], u'requiredparams': [u'resourcetype'], u'description': u'Updates resource limits for an account or domain.'}, u'vpcoffering': {u'name': u'updateVPCOffering', u'related': [u'listVPCOfferings', u'createVPCOffering'], u'isasync': True, u'params': [{u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the VPC offering'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'update state for the VPC offering; supported states - Enabled/Disabled'}, {u'name': u'id', u'required': False, u'related': [u'listVPCOfferings', u'createVPCOffering', u'updateVPCOffering'], u'length': 255, u'type': u'uuid', u'description': u'the id of the VPC offering'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the VPC offering'}], u'requiredparams': [], u'description': u'Updates VPC offering'}, u'network': {u'name': u'updateNetwork', u'related': [u'listNetscalerLoadBalancerNetworks'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network'}, {u'name': u'networkofferingid', u'required': False, u'related': [u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'network offering ID'}, {u'name': u'changecidr', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force update even if cidr type is different'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the new name for the network'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the new display text for the network'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'network domain'}], u'requiredparams': [u'id'], u'description': u'Updates a network'}, u'zone': {u'name': u'updateZone', u'related': [u'listZones', u'createZone'], u'isasync': False, u'params': [{u'name': u'internaldns1', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first internal DNS for the Zone'}, {u'name': u'dnssearchorder', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the dns search order list'}, {u'name': u'internaldns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second internal DNS for the Zone'}, {u'name': u'domain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network domain name for the networks in the zone; empty string will update domain with NULL value'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'the details for the Zone'}, {u'name': u'ip6dns1', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first DNS for IPv6 network in the Zone'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Allocation state of this cluster for allocation of new resources'}, {u'name': u'ip6dns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second DNS for IPv6 network in the Zone'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the Zone'}, {u'name': u'id', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Zone'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'updates a private zone to public if set, but not vice-versa'}, {u'name': u'dns2', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the second DNS for the Zone'}, {u'name': u'guestcidraddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the guest CIDR address for the Zone'}, {u'name': u'dhcpprovider', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the dhcp Provider for the Zone'}, {u'name': u'dns1', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the first DNS for the Zone'}, {u'name': u'localstorageenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if local storage offering enabled, false otherwise'}], u'requiredparams': [u'id'], u'description': u'Updates a Zone.'}, u'instancegroup': {u'name': u'updateInstanceGroup', u'related': [u'createInstanceGroup'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateInstanceGroup', u'createInstanceGroup'], u'length': 255, u'type': u'uuid', u'description': u'Instance group ID'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'new instance group name'}], u'requiredparams': [u'id'], u'description': u'Updates a vm group'}, u'autoscalepolicy': {u'name': u'updateAutoScalePolicy', u'related': [], u'isasync': True, u'params': [{u'name': u'duration', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the duration for which the conditions have to be true before action is taken'}, {u'name': u'id', u'required': True, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale policy'}, {u'name': u'quiettime', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the cool down period for which the policy should not be evaluated after the action has been taken'}, {u'name': u'conditionids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the list of IDs of the conditions that are being evaluated on every interval'}], u'requiredparams': [u'id'], u'description': u'Updates an existing autoscale policy.'}, u'serviceoffering': {u'name': u'updateServiceOffering', u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering'], u'isasync': False, u'params': [{u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the service offering, integer'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the service offering to be updated'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the service offering to be updated'}, {u'name': u'id', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering', u'updateServiceOffering'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the service offering to be updated'}], u'requiredparams': [u'id'], u'description': u'Updates a service offering.'}, u'storagepool': {u'name': u'updateStoragePool', u'related': [u'cancelStorageMaintenance', u'createStoragePool', u'listStoragePools'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'cancelStorageMaintenance', u'updateStoragePool', u'createStoragePool', u'listStoragePools'], u'length': 255, u'type': u'uuid', u'description': u'the Id of the storage pool'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma-separated list of tags for the storage pool'}], u'requiredparams': [u'id'], u'description': u'Updates a storage pool.'}, u'hypervisorcapabilities': {u'name': u'updateHypervisorCapabilities', u'related': [], u'isasync': False, u'params': [{u'name': u'securitygroupenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'set true to enable security group for this hypervisor.'}, {u'name': u'maxguestslimit', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the max number of Guest VMs per host for this hypervisor.'}, {u'name': u'id', u'required': False, u'related': [u'listHypervisorCapabilities'], u'length': 255, u'type': u'uuid', u'description': u'ID of the hypervisor capability'}], u'requiredparams': [], u'description': u'Updates a hypervisor capabilities.'}, u'template': {u'name': u'updateTemplate', u'related': [u'registerIso', u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'bootable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if image is bootable, false otherwise'}, {u'name': u'passwordenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the image supports the password reset feature; default is false'}, {u'name': u'format', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the format for the image'}, {u'name': u'ostypeid', u'required': False, u'related': [u'listOsTypes'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS type that best represents the OS of this image.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the image file'}, {u'name': u'id', u'required': True, u'related': [u'registerIso', u'updateTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the image file'}, {u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the template, integer'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the image'}], u'requiredparams': [u'id'], u'description': u'Updates attributes of a template.'}, u'defaultnicforvirtualmachine': {u'name': u'updateDefaultNicForVirtualMachine', u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'nicid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'NIC ID'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Virtual Machine ID'}], u'requiredparams': [u'nicid', u'virtualmachineid'], u'description': u'Changes the default NIC on a VM'}, u'traffictype': {u'name': u'updateTrafficType', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateTrafficType'], u'length': 255, u'type': u'uuid', u'description': u'traffic type id'}, {u'name': u'xennetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a XenServer host'}, {u'name': u'vmwarenetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a VMware host'}, {u'name': u'kvmnetworklabel', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The network name label of the physical device dedicated to this traffic on a KVM host'}], u'requiredparams': [u'id'], u'description': u'Updates traffic type of a physical network'}, u'host': {u'name': u'updateHost', u'related': [u'listHosts'], u'isasync': False, u'params': [{u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Change resource state of host, valid values are [Enable, Disable]. Operation may failed if host in states not allowing Enable/Disable'}, {u'name': u'oscategoryid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id of Os category to update the host with'}, {u'name': u'hosttags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of tags to be added to the host'}, {u'name': u'id', u'required': True, u'related': [u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the host to update'}, {u'name': u'url', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the new uri for the secondary storage: nfs://host/path'}], u'requiredparams': [u'id'], u'description': u'Updates a host.'}, u'user': {u'name': u'updateUser', u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser', u'updateUser'], u'length': 255, u'type': u'uuid', u'description': u'User uuid'}, {u'name': u'timezone', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.'}, {u'name': u'email', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'email'}, {u'name': u'usersecretkey', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The secret key for the user. Must be specified with userApiKey'}, {u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Unique username'}, {u'name': u'firstname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'first name'}, {u'name': u'lastname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'last name'}, {u'name': u'password', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Hashed password (default is MD5). If you wish to use any other hasing algorithm, you would need to write a custom authentication adapter'}, {u'name': u'userapikey', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The API key for the user. Must be specified with userSecretKey'}], u'requiredparams': [u'id'], u'description': u'Updates a user account'}, u'vpc': {u'name': u'updateVPC', u'related': [u'restartVPC', u'listVPCs'], u'isasync': True, u'params': [{u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the VPC'}, {u'name': u'id', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs'], u'length': 255, u'type': u'uuid', u'description': u'the id of the VPC'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the VPC'}], u'requiredparams': [], u'description': u'Updates a VPC'}, u'resourcecount': {u'name': u'updateResourceCount', u'related': [], u'isasync': False, u'params': [{u'name': u'resourcetype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Type of resource to update. If specifies valid values are 0, 1, 2, 3, and 4. If not specified will update all resource counts0 - Instance. Number of instances a user can create. 1 - IP. Number of public IP addresses a user can own. 2 - Volume. Number of disk volumes a user can create.3 - Snapshot. Number of snapshots a user can create.4 - Template. Number of templates that a user can register/create.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Update resource limits for project'}, {u'name': u'domainid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'If account parameter specified then updates resource counts for a specified account in this domain else update resource counts for all accounts & child domains in specified domain.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Update resource count for a specified account. Must be used with the domainId parameter.'}], u'requiredparams': [u'domainid'], u'description': u'Recalculate and update resource count for an account or domain.'}, u'storagenetworkiprange': {u'name': u'updateStorageNetworkIpRange', u'related': [], u'isasync': True, u'params': [{u'name': u'endip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ending IP address'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Optional. the vlan the ip range sits on'}, {u'name': u'netmask', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the netmask for storage network'}, {u'name': u'id', u'required': True, u'related': [u'updateStorageNetworkIpRange'], u'length': 255, u'type': u'uuid', u'description': u'UUID of storage network ip range'}, {u'name': u'startip', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the beginning IP address'}], u'requiredparams': [u'id'], u'description': u'Update a Storage network IP range, only allowed when no IPs in this range have been allocated.'}, u'configuration': {u'name': u'updateConfiguration', u'related': [u'listConfigurations'], u'isasync': False, u'params': [{u'name': u'value', u'required': False, u'related': [], u'length': 4095, u'type': u'string', u'description': u'the value of the configuration'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the configuration'}], u'requiredparams': [u'name'], u'description': u'Updates a configuration.'}, u'templatepermissions': {u'name': u'updateTemplatePermissions', u'related': [], u'isasync': False, u'params': [{u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true for featured template/iso, false otherwise'}, {u'name': u'isextractable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template/iso is extractable, false other wise. Can be set only by root admin'}, {u'name': u'projectids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'a comma delimited list of projects. If specified, "op" parameter has to be passed in.'}, {u'name': u'op', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'permission operator (add, remove, reset)'}, {u'name': u'id', u'required': True, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true for public template/iso, false for private templates/isos'}, {u'name': u'accounts', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'a comma delimited list of accounts. If specified, "op" parameter has to be passed in.'}], u'requiredparams': [u'id'], u'description': u'Updates a template visibility permissions. A public template is visible to all accounts within the same domain. A private template is visible only to the owner of the template. A priviledged template is a private template with account permissions added. Only accounts specified under the template permissions are visible to them.'}, u'autoscalevmprofile': {u'name': u'updateAutoScaleVmProfile', u'related': [u'listAutoScaleVmProfiles'], u'isasync': True, u'params': [{u'name': u'expungevmgraceperiod', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the time allowed for existing connections to get closed before a vm is destroyed'}, {u'name': u'autoscaleuserid', u'required': False, u'related': [u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the user used to launch and destroy the VMs'}, {u'name': u'templateid', u'required': False, u'related': [u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template of the auto deployed virtual machine'}, {u'name': u'id', u'required': True, u'related': [u'updateAutoScaleVmProfile', u'listAutoScaleVmProfiles'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale vm profile'}, {u'name': u'counterparam', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'counterparam list. Example: counterparam[0].name=snmpcommunity&counterparam[0].value=public&counterparam[1].name=snmpport&counterparam[1].value=161'}], u'requiredparams': [u'id'], u'description': u'Updates an existing autoscale vm profile.'}, u'account': {u'name': u'updateAccount', u'related': [u'markDefaultZoneForAccount', u'listAccounts', u'lockAccount'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount'], u'length': 255, u'type': u'uuid', u'description': u'Account id'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain where the account exists'}, {u'name': u'networkdomain', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"Network domain for the account's networks; empty string will update domainName with NULL value"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the current account name'}, {u'name': u'accountdetails', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'details for account used to store specific parameters'}, {u'name': u'newname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'new name for the account'}], u'requiredparams': [u'newname'], u'description': u'Updates account information for the authenticated user'}, u'networkoffering': {u'name': u'updateNetworkOffering', u'related': [], u'isasync': False, u'params': [{u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the network offering, integer'}, {u'name': u'id', u'required': False, u'related': [u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'the id of the network offering'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the display text of the network offering'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the network offering'}, {u'name': u'availability', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the availability of network offering. Default value is Required for Guest Virtual network offering; Optional for Guest Direct network offering'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'update state for the network offering'}], u'requiredparams': [], u'description': u'Updates a network offering.'}, u'vpncustomergateway': {u'name': u'updateVpnCustomerGateway', u'related': [u'createVpnCustomerGateway'], u'isasync': True, u'params': [{u'name': u'ikelifetime', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lifetime of phase 1 VPN connection to the customer gateway, in seconds'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the gateway. If used with the account parameter returns the gateway associated with the account for the specified domain.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of this customer gateway'}, {u'name': u'id', u'required': True, u'related': [u'updateVpnCustomerGateway', u'createVpnCustomerGateway'], u'length': 255, u'type': u'uuid', u'description': u'id of customer gateway'}, {u'name': u'esplifetime', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lifetime of phase 2 VPN connection to the customer gateway, in seconds'}, {u'name': u'ikepolicy', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'IKE policy of the customer gateway'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the gateway. Must be used with the domainId parameter.'}, {u'name': u'esppolicy', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'ESP policy of the customer gateway'}, {u'name': u'gateway', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'public ip address id of the customer gateway'}, {u'name': u'ipsecpsk', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'IPsec Preshared-Key of the customer gateway'}, {u'name': u'dpd', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'If DPD is enabled for VPN connection'}, {u'name': u'cidrlist', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'guest cidr of the customer gateway'}], u'requiredparams': [u'id', u'ikepolicy', u'esppolicy', u'gateway', u'ipsecpsk', u'cidrlist'], u'description': u'Update site to site vpn customer gateway'}, u'region': {u'name': u'updateRegion', u'related': [u'addRegion', u'listRegions'], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'updates region with this name'}, {u'name': u'endpoint', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'updates region with this end point'}, {u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Id of region to update'}], u'requiredparams': [u'id'], u'description': u'Updates a region'}, u'project': {u'name': u'updateProject', u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to be modified'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'display text of the project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'new Admin account for the project'}], u'requiredparams': [u'id'], u'description': u'Updates a project'}, u'physicalnetwork': {u'name': u'updatePhysicalNetwork', u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'isasync': True, u'params': [{u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the VLAN for the physical network'}, {u'name': u'id', u'required': True, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'physical network id'}, {u'name': u'networkspeed', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the speed for the physical network[1G/10G]'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'Tag the physical network'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enabled/Disabled'}], u'requiredparams': [u'id'], u'description': u'Updates a physical network'}, u'iso': {u'name': u'updateIso', u'related': [u'listIsos'], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the image file'}, {u'name': u'id', u'required': True, u'related': [u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the image file'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the image'}, {u'name': u'format', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the format for the image'}, {u'name': u'sortkey', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'sort key of the template, integer'}, {u'name': u'ostypeid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS type that best represents the OS of this image.'}, {u'name': u'passwordenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the image supports the password reset feature; default is false'}, {u'name': u'bootable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if image is bootable, false otherwise'}], u'requiredparams': [u'id'], u'description': u'Updates an ISO file.'}, u'networkserviceprovider': {u'name': u'updateNetworkServiceProvider', u'related': [], u'isasync': True, u'params': [{u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Enabled/Disabled/Shutdown the physical network service provider'}, {u'name': u'id', u'required': True, u'related': [u'updateNetworkServiceProvider'], u'length': 255, u'type': u'uuid', u'description': u'network service provider id'}, {u'name': u'servicelist', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'the list of services to be enabled for this physical network service provider'}], u'requiredparams': [u'id'], u'description': u'Updates a network serviceProvider of a physical network'}, u'autoscalevmgroup': {u'name': u'updateAutoScaleVmGroup', u'related': [], u'isasync': True, u'params': [{u'name': u'scaledownpolicyids', u'required': False, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'list', u'description': u'list of scaledown autoscale policies'}, {u'name': u'interval', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the frequency at which the conditions have to be evaluated'}, {u'name': u'minmembers', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the minimum number of members in the vmgroup, the number of instances in the vm group will be equal to or more than this number.'}, {u'name': u'maxmembers', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the maximum number of members in the vmgroup, The number of instances in the vm group will be equal to or less than this number.'}, {u'name': u'id', u'required': True, u'related': [u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale group'}, {u'name': u'scaleuppolicyids', u'required': False, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'list', u'description': u'list of scaleup autoscale policies'}], u'requiredparams': [u'id'], u'description': u'Updates an existing autoscale vm group.'}}, u'disable': {u'account': {u'name': u'disableAccount', u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount'], u'isasync': True, u'params': [{u'name': u'lock', u'required': True, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'If true, only lock the account; else disable the account'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Disables specified account.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'Disables specified account in this domain.'}, {u'name': u'id', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount', u'disableAccount'], u'length': 255, u'type': u'uuid', u'description': u'Account id'}], u'requiredparams': [u'lock'], u'description': u'Disables an account'}, u'autoscalevmgroup': {u'name': u'disableAutoScaleVmGroup', u'related': [u'listAutoScaleVmGroups', u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listAutoScaleVmGroups', u'createAutoScaleVmGroup', u'disableAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale group'}], u'requiredparams': [u'id'], u'description': u'Disables an AutoScale Vm Group'}, u'cisconexusvsm': {u'name': u'disableCiscoNexusVSM', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableCiscoNexusVSM'], u'length': 255, u'type': u'uuid', u'description': u'Id of the Cisco Nexus 1000v VSM device to be deleted'}], u'requiredparams': [u'id'], u'description': u'disable a Cisco Nexus VSM device'}, u'staticnat': {u'name': u'disableStaticNat', u'related': [], u'isasync': True, u'params': [{u'name': u'ipaddressid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the public IP address id for which static nat feature is being disableed'}], u'requiredparams': [u'ipaddressid'], u'description': u'Disables static rule for given ip address'}, u'user': {u'name': u'disableUser', u'related': [u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableUser', u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'Disables user by user ID.'}], u'requiredparams': [u'id'], u'description': u'Disables a user account'}}, u'detach': {u'volume': {u'name': u'detachVolume', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': False, u'related': [u'detachVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'deviceid', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the device ID on the virtual machine where volume is detached from'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'listVirtualMachines'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine where the volume is detached from'}], u'requiredparams': [], u'description': u'Detaches a disk volume from a virtual machine.'}, u'iso': {u'name': u'detachIso', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'virtualmachineid', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'virtualmachineid'], u'description': u'Detaches any ISO file (if any) currently attached to a virtual machine.'}}, u'generate': {u'usagerecords': {u'name': u'generateUsageRecords', u'related': [], u'isasync': False, u'params': [{u'name': u'enddate', u'required': True, u'related': [], u'length': 255, u'type': u'date', u'description': u'End date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'List events for the specified domain.'}, {u'name': u'startdate', u'required': True, u'related': [], u'length': 255, u'type': u'date', u'description': u'Start date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.'}], u'requiredparams': [u'enddate', u'startdate'], u'description': u'Generates usage records. This will generate records only if there any records to be generated, i.e if the scheduled usage job was not run or failed'}}, u'change': {u'serviceforvirtualmachine': {u'name': u'changeServiceForVirtualMachine', u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the service offering ID to apply to the virtual machine'}], u'requiredparams': [u'id', u'serviceofferingid'], u'description': u'Changes the service offering for a virtual machine. The virtual machine must be in a "Stopped" state for this command to take effect.'}, u'serviceforsystemvm': {u'name': u'changeServiceForSystemVm', u'related': [u'rebootSystemVm', u'listSystemVms'], u'isasync': False, u'params': [{u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering'], u'length': 255, u'type': u'uuid', u'description': u'the service offering ID to apply to the system vm'}, {u'name': u'id', u'required': True, u'related': [u'rebootSystemVm', u'listSystemVms', u'changeServiceForSystemVm'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the system vm'}], u'requiredparams': [u'serviceofferingid', u'id'], u'description': u'Changes the service offering for a system vm (console proxy or secondary storage). The system vm must be in a "Stopped" state for this command to take effect.'}, u'serviceforrouter': {u'name': u'changeServiceForRouter', u'related': [u'destroyRouter', u'rebootRouter', u'startRouter'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'changeServiceForRouter', u'destroyRouter', u'rebootRouter', u'startRouter'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the router'}, {u'name': u'serviceofferingid', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings', u'createServiceOffering', u'updateServiceOffering'], u'length': 255, u'type': u'uuid', u'description': u'the service offering ID to apply to the domain router'}], u'requiredparams': [u'id', u'serviceofferingid'], u'description': u'Upgrades domain router to a new service offering'}}, u'reset': {u'apilimit': {u'name': u'resetApiLimit', u'related': [], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the acount whose limit to be reset'}], u'requiredparams': [], u'description': u'Reset api count'}, u'sshkeyforvirtualmachine': {u'name': u'resetSSHKeyForVirtualMachine', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'an optional project for the ssh key'}, {u'name': u'keypair', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the ssh key pair used to login to the virtual machine'}, {u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the ssh key. Must be used with domainId.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.'}], u'requiredparams': [u'keypair', u'id'], u'description': u'Resets the SSH Key for virtual machine. The virtual machine must be in a "Stopped" state. [async]'}, u'passwordforvirtualmachine': {u'name': u'resetPasswordForVirtualMachine', u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the virtual machine'}], u'requiredparams': [u'id'], u'description': u'Resets the password for virtual machine. The virtual machine must be in a "Stopped" state and the template must already support this feature for this command to take effect. [async]'}, u'vpnconnection': {u'name': u'resetVpnConnection', u'related': [u'listVpnConnections'], u'isasync': True, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for connection. Must be used with domainId.'}, {u'name': u'id', u'required': True, u'related': [u'listVpnConnections', u'resetVpnConnection'], u'length': 255, u'type': u'uuid', u'description': u'id of vpn connection'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for connection. If the account parameter is used, domainId must also be used.'}], u'requiredparams': [u'id'], u'description': u'Reset site to site vpn connection'}}, u'register': {u'userkeys': {u'name': u'registerUserKeys', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'lockUser', u'listUsers', u'enableUser', u'createUser'], u'length': 255, u'type': u'uuid', u'description': u'User id'}], u'requiredparams': [u'id'], u'description': u'This command allows a user to register for the developer API, returning a secret key and an API key. This request is made through the integration API port, so it is a privileged command and must be made on behalf of a user. It is up to the implementer just how the username and password are entered, and then how that translates to an integration API request. Both secret key and API key should be returned to the user'}, u'iso': {u'name': u'registerIso', u'related': [u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'ostypeid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS Type that best represents the OS of this ISO. If the iso is bootable this parameter needs to be passed'}, {u'name': u'checksum', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the MD5 checksum value of this ISO'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the ISO'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId. If the account parameter is used, domainId must also be used.'}, {u'name': u'bootable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this ISO is bootable. If not passed explicitly its assumed to be true'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'Register iso for the project'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if you want to register the ISO to be publicly available to all users, false otherwise.'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone you wish to register the ISO to.'}, {u'name': u'isextractable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the iso or its derivatives are extractable; default is false'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the ISO. This is usually used for display purposes.'}, {u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if you want this ISO to be featured'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL to where the ISO is currently being hosted'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account name. Must be used with domainId.'}], u'requiredparams': [u'name', u'zoneid', u'displaytext', u'url'], u'description': u'Registers an existing ISO into the CloudStack Cloud.'}, u'sshkeypair': {u'name': u'registerSSHKeyPair', u'related': [u'createSSHKeyPair', u'listSSHKeyPairs'], u'isasync': False, u'params': [{u'name': u'publickey', u'required': True, u'related': [], u'length': 5120, u'type': u'string', u'description': u'Public key material of the keypair'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the ssh key. If the account parameter is used, domainId must also be used.'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the keypair'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'an optional project for the ssh key'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the ssh key. Must be used with domainId.'}], u'requiredparams': [u'publickey', u'name'], u'description': u'Register a public key in a keypair under a certain name'}, u'template': {u'name': u'registerTemplate', u'related': [u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'isextractable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template or its derivatives are extractable; default is false'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone the template is to be hosted on'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId. If the account parameter is used, domainId must also be used.'}, {u'name': u'checksum', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the MD5 checksum value of this template'}, {u'name': u'templatetag', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the tag for this template.'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template is available to all accounts; default is true'}, {u'name': u'passwordenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template supports the password reset feature; default is false'}, {u'name': u'displaytext', u'required': True, u'related': [], u'length': 4096, u'type': u'string', u'description': u'the display text of the template. This is usually used for display purposes.'}, {u'name': u'sshkeyenabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the template supports the sshkey upload feature; default is false'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'Register template for the project'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the template'}, {u'name': u'isfeatured', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this template is a featured template, false otherwise'}, {u'name': u'format', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the format for the template. Possible values include QCOW2, RAW, and VHD.'}, {u'name': u'requireshvm', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this template requires HVM'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional accountName. Must be used with domainId.'}, {u'name': u'ostypeid', u'required': True, u'related': [u'listOsTypes'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the OS Type that best represents the OS of this template.'}, {u'name': u'hypervisor', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the target hypervisor for the template'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL of where the template is hosted. Possible URL include http:// and https://'}, {u'name': u'bits', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'32 or 64 bits support. 64 by default'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'Template details in key/value pairs.'}], u'requiredparams': [u'zoneid', u'displaytext', u'name', u'format', u'ostypeid', u'hypervisor', u'url'], u'description': u'Registers an existing template into the CloudStack cloud. '}}, u'list': {u'instancegroups': {u'name': u'listInstanceGroups', u'related': [u'updateInstanceGroup', u'createInstanceGroup'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listInstanceGroups', u'updateInstanceGroup', u'createInstanceGroup'], u'length': 255, u'type': u'uuid', u'description': u'list instance groups by ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list instance groups by name'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists vm groups'}, u'physicalnetworks': {u'name': u'listPhysicalNetworks', u'related': [], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the physical network'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listPhysicalNetworks'], u'length': 255, u'type': u'uuid', u'description': u'list physical network by id'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'search by name'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists physical networks'}, u'networks': {u'name': u'listNetworks', u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'issystem', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if network is system, false otherwise'}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'List networks by VPC'}, {u'name': u'acltype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list networks by ACL (access control list) type. Supported values are Account and Domain'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'specifyipranges', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only networks which support specifying ip ranges'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the network'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'restartrequired', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list networks by restartRequired'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the type of the network. Supported values are: Isolated and Shared'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'list networks by physical network id'}, {u'name': u'supportedservices', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list networks supporting certain services'}, {u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'type of the traffic'}, {u'name': u'id', u'required': False, u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'list networks by id'}, {u'name': u'canusefordeploy', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list networks available for vm deployment'}, {u'name': u'forvpc', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the network belongs to vpc'}], u'requiredparams': [], u'description': u'Lists all available networks.'}, u'capabilities': {u'name': u'listCapabilities', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'Lists capabilities'}, u'clusters': {u'name': u'listClusters', u'related': [u'updateCluster'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listClusters', u'updateCluster'], u'length': 255, u'type': u'uuid', u'description': u'lists clusters by the cluster ID'}, {u'name': u'managedstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'whether this cluster is managed by cloudstack'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists clusters by hypervisor type'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists clusters by allocation state'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'lists clusters by Zone ID'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists clusters by the cluster name'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'clustertype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists clusters by cluster type'}, {u'name': u'showcapacities', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'flag to display the capacity of the clusters'}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'lists clusters by Pod ID'}], u'requiredparams': [], u'description': u'Lists clusters.'}, u'resourcelimits': {u'name': u'listResourceLimits', u'related': [u'updateResourceLimit'], u'isasync': False, u'params': [{u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'resourcetype', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'Type of resource to update. Values are 0, 1, 2, 3, and 4. 0 - Instance. Number of instances a user can create. 1 - IP. Number of public IP addresses a user can own. 2 - Volume. Number of disk volumes a user can create.3 - Snapshot. Number of snapshots a user can create.4 - Template. Number of templates that a user can register/create.'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'Lists resource limits by ID.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists resource limits.'}, u'firewallrules': {u'name': u'listFirewallRules', u'related': [u'createEgressFirewallRule', u'createFirewallRule', u'listEgressFirewallRules'], u'isasync': False, u'params': [{u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'ipaddressid', u'required': False, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the id of IP address of the firwall services'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists all firewall rules for an IP address.'}, u'supportednetworkservices': {u'name': u'listSupportedNetworkServices', u'related': [], u'isasync': False, u'params': [{u'name': u'service', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'network service name to list providers and capabilities of'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'provider', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'network service provider name'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists all network services provided by CloudStack or for the given Provider.'}, u'loadbalancerrules': {u'name': u'listLoadBalancerRules', u'related': [u'createLoadBalancerRule', u'updateLoadBalancerRule'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the availability zone ID'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine of the load balancer rule'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'id', u'required': False, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'publicipid', u'required': False, u'related': [u'restartNetwork', u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'the public IP address id of the load balancer rule '}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the load balancer rule'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists load balancer rules.'}, u'autoscalepolicies': {u'name': u'listAutoScalePolicies', u'related': [u'createAutoScalePolicy', u'updateAutoScalePolicy'], u'isasync': False, u'params': [{u'name': u'action', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the action to be executed if all the conditions evaluate to true for the specified duration.'}, {u'name': u'id', u'required': False, u'related': [u'createAutoScalePolicy', u'updateAutoScalePolicy', u'listAutoScalePolicies'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale policy'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'vmgroupid', u'required': False, u'related': [u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale vm group'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'conditionid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the condition of the policy'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists autoscale policies.'}, u'niciranvpdevices': {u'name': u'listNiciraNvpDevices', u'related': [u'addNiciraNvpDevice'], u'isasync': False, u'params': [{u'name': u'nvpdeviceid', u'required': False, u'related': [u'addNiciraNvpDevice', u'listNiciraNvpDevices'], u'length': 255, u'type': u'uuid', u'description': u'nicira nvp device ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists Nicira NVP devices'}, u'f5loadbalancernetworks': {u'name': u'listF5LoadBalancerNetworks', u'related': [u'createNetwork', u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'lbdeviceid', u'required': True, u'related': [u'configureF5LoadBalancer', u'addF5LoadBalancer', u'listF5LoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'f5 load balancer device ID'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'lbdeviceid'], u'description': u'lists network that are using a F5 load balancer device'}, u'templatepermissions': {u'name': u'listTemplatePermissions', u'related': [u'listIsoPermissions'], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIsoPermissions', u'listTemplatePermissions'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}], u'requiredparams': [u'id'], u'description': u'List template visibility and all accounts that have permissions to view this template.'}, u'projects': {u'name': u'listProjects', u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List projects by tags (key/value pairs)'}, {u'name': u'id', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list projects by project ID'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list projects by name'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list projects by state'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list projects by display text'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists projects and provides detailed information for listed projects'}, u'systemvms': {u'name': u'listSystemVms', u'related': [u'rebootSystemVm'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the system VM'}, {u'name': u'hostid', u'required': False, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'the host ID of the system VM'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the state of the system VM'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'storageid', u'required': False, u'related': [u'cancelStorageMaintenance'], u'length': 255, u'type': u'uuid', u'description': u"the storage ID where vm's volumes belong to"}, {u'name': u'systemvmtype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the system VM type. Possible types are "consoleproxy" and "secondarystoragevm".'}, {u'name': u'podid', u'required': False, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID of the system VM'}, {u'name': u'id', u'required': False, u'related': [u'rebootSystemVm', u'listSystemVms'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the system VM'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the system VM'}], u'requiredparams': [], u'description': u'List system virtual machines.'}, u'portforwardingrules': {u'name': u'listPortForwardingRules', u'related': [u'listIpForwardingRules', u'createPortForwardingRule'], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'id', u'required': False, u'related': [u'listIpForwardingRules', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'ipaddressid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id of IP address of the port forwarding services'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists all port forwarding rules for an IP address.'}, u'hypervisors': {u'name': u'listHypervisors', u'related': [], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the zone id for listing hypervisors.'}], u'requiredparams': [], u'description': u'List hypervisors'}, u'publicipaddresses': {u'name': u'listPublicIpAddresses', u'related': [u'restartNetwork', u'associateIpAddress'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'lists all public IP addresses by Zone ID'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'allocatedonly', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'limits search results to allocated public IP addresses'}, {u'name': u'id', u'required': False, u'related': [u'restartNetwork', u'listPublicIpAddresses', u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'lists ip address by id'}, {u'name': u'forloadbalancing', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list only ips used for load balancing'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isstaticnat', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list only static nat ip addresses'}, {u'name': u'issourcenat', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list only source nat ip addresses'}, {u'name': u'vlanid', u'required': False, u'related': [u'listVlanIpRanges'], u'length': 255, u'type': u'uuid', u'description': u'lists all public IP addresses by VLAN ID'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists the specified IP address'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'lists all public IP addresses by physical network id'}, {u'name': u'associatednetworkid', u'required': False, u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'lists all public IP addresses associated to the network specified'}, {u'name': u'forvirtualnetwork', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the virtual network for the IP address'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'List ips belonging to the VPC'}], u'requiredparams': [], u'description': u'Lists all public ip addresses'}, u'vpngateways': {u'name': u'listVpnGateways', u'related': [u'createVpnGateway'], u'isasync': False, u'params': [{u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'id', u'required': False, u'related': [u'createVpnGateway', u'listVpnGateways'], u'length': 255, u'type': u'uuid', u'description': u'id of the vpn gateway'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'id of vpc'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists site 2 site vpn gateways'}, u'loadbalancerruleinstances': {u'name': u'listLoadBalancerRuleInstances', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'applied', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if listing all virtual machines currently applied to the load balancer rule; default is true'}, {u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}], u'requiredparams': [u'id'], u'description': u'List all virtual machine instances that are assigned to a load balancer rule.'}, u'hosts': {u'name': u'listHosts', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'podid', u'required': False, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the host'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the state of the host'}, {u'name': u'resourcestate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list hosts by resource state. Resource state represents current state determined by admin of host, valule can be one of [Enabled, Disabled, Unmanaged, PrepareForMaintenance, ErrorInMaintenance, Maintenance, Error]'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the host'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the host'}, {u'name': u'virtualmachineid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'lists hosts in the same cluster as this VM and flag hosts with enough CPU/RAm to host this VM'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'lists hosts existing in particular cluster'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the host type'}, {u'name': u'id', u'required': False, u'related': [u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'the id of the host'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma separated list of host details requested, value can be a list of [ min, all, capacity, events, stats]'}, {u'name': u'hahost', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, list only hosts dedicated to HA'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists hosts.'}, u'pools': {u'name': u'listPools', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'List Pool'}, u'counters': {u'name': u'listCounters', u'related': [], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'source', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Source of the counter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'listCounters'], u'length': 255, u'type': u'uuid', u'description': u'ID of the Counter.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the counter.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'List the counters'}, u'configurations': {u'name': u'listConfigurations', u'related': [], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists configuration by name'}, {u'name': u'category', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists configurations by category'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all configurations.'}, u'usagerecords': {u'name': u'listUsageRecords', u'related': [], u'isasync': False, u'params': [{u'name': u'enddate', u'required': True, u'related': [], u'length': 255, u'type': u'date', u'description': u'End date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.'}, {u'name': u'startdate', u'required': True, u'related': [], u'length': 255, u'type': u'date', u'description': u'Start date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'List usage records for the specified usage type'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'List usage records for specified project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List usage records for the specified user.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'List usage records for the specified domain.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'accountid', u'required': False, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount'], u'length': 255, u'type': u'uuid', u'description': u'List usage records for the specified account'}], u'requiredparams': [u'enddate', u'startdate'], u'description': u'Lists usage records for accounts'}, u'storagepools': {u'name': u'listStoragePools', u'related': [u'cancelStorageMaintenance'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID for the storage pool'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'path', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the storage pool path'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list storage pools belongig to the specific cluster'}, {u'name': u'id', u'required': False, u'related': [u'cancelStorageMaintenance', u'listStoragePools'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the storage pool'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the IP address for the storage pool'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the storage pool'}, {u'name': u'podid', u'required': False, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID for the storage pool'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists storage pools.'}, u'vpncustomergateways': {u'name': u'listVpnCustomerGateways', u'related': [u'updateVpnCustomerGateway', u'createVpnCustomerGateway'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'updateVpnCustomerGateway', u'createVpnCustomerGateway', u'listVpnCustomerGateways'], u'length': 255, u'type': u'uuid', u'description': u'id of the customer gateway'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}], u'requiredparams': [], u'description': u'Lists site to site vpn customer gateways'}, u'zones': {u'name': u'listZones', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone'}, {u'name': u'available', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if you want to retrieve all available Zones. False if you only want to return the Zones from which you have at least one VM. Default is false.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the zone'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain associated with the zone'}, {u'name': u'showcapacities', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'flag to display the capacity of the zones'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists zones'}, u'serviceofferings': {u'name': u'listServiceOfferings', u'related': [u'updateHypervisorCapabilities'], u'isasync': False, u'params': [{u'name': u'systemvmtype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the system VM type. Possible types are "consoleproxy", "secondarystoragevm" or "domainrouter".'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain associated with the service offering'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the service offering'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine. Pass this in if you want to see the available service offering that a virtual machine can be changed to.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'issystem', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'is this a system vm offering'}, {u'name': u'id', u'required': False, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'length': 255, u'type': u'uuid', u'description': u'ID of the service offering'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all available service offerings.'}, u'externalfirewalls': {u'name': u'listExternalFirewalls', u'related': [u'addExternalFirewall'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'zoneid', u'required': True, u'related': [u'listZones'], u'length': 255, u'type': u'uuid', u'description': u'zone Id'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'zoneid'], u'description': u'List external firewall appliances.'}, u'networkserviceproviders': {u'name': u'listNetworkServiceProviders', u'related': [u'addNetworkServiceProvider', u'listTrafficTypes', u'updateNetworkServiceProvider'], u'isasync': False, u'params': [{u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list providers by state'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list providers by name'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists network serviceproviders for a given physical network.'}, u'capacity': {u'name': u'listCapacity', u'related': [], u'isasync': False, u'params': [{u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'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.'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'lists capacity by the Cluster ID'}, {u'name': u'sortby', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Sort the results. Available values: Usage'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'fetchlatest', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'recalculate capacities and fetch the latest'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'lists capacity by the Zone ID'}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'lists capacity by the Pod ID'}], u'requiredparams': [], u'description': u'Lists all the system wide capacities.'}, u'diskofferings': {u'name': u'listDiskOfferings', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'ID of the disk offering'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the disk offering'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the domain of the disk offering.'}], u'requiredparams': [], u'description': u'Lists all available disk offerings.'}, u'lbstickinesspolicies': {u'name': u'listLBStickinessPolicies', u'related': [u'createLBStickinessPolicy'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'lbruleid', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [u'lbruleid'], u'description': u'Lists LBStickiness policies.'}, u'srxfirewallnetworks': {u'name': u'listSrxFirewallNetworks', u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'isasync': False, u'params': [{u'name': u'lbdeviceid', u'required': True, u'related': [u'addSrxFirewall'], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'lbdeviceid'], u'description': u'lists network that are using SRX firewall device'}, u'securitygroups': {u'name': u'listSecurityGroups', u'related': [], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'id', u'required': False, u'related': [u'listSecurityGroups'], u'length': 255, u'type': u'uuid', u'description': u'list the security group by the id provided'}, {u'name': u'securitygroupname', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists security groups by name'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'lists security groups by virtual machine id'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists security groups'}, u'conditions': {u'name': u'listConditions', u'related': [u'listCounters', u'createCounter'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'ID of the Condition.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'counterid', u'required': False, u'related': [u'listConditions', u'listCounters', u'createCounter'], u'length': 255, u'type': u'uuid', u'description': u'Counter-id of the condition.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'policyid', u'required': False, u'related': [u'createAutoScalePolicy', u'updateAutoScalePolicy'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the policy'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}], u'requiredparams': [], u'description': u'List Conditions for the specific user'}, u'swifts': {u'name': u'listSwifts', u'related': [u'addHost', u'updateHost', u'listHosts', u'listExternalLoadBalancers'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'the id of the swift'}], u'requiredparams': [], u'description': u'List Swift.'}, u'hypervisorcapabilities': {u'name': u'listHypervisorCapabilities', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listHypervisorCapabilities'], u'length': 255, u'type': u'uuid', u'description': u'ID of the hypervisor capability'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the hypervisor for which to restrict the search'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists all hypervisor capabilities.'}, u'tags': {u'name': u'listTags', u'related': [], u'isasync': False, u'params': [{u'name': u'resourceid', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by resource id'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'resourcetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by resource type'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'key', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by key'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'customer', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by customer name'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'value', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by value'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'List resource tag(s)'}, u'routers': {u'name': u'listRouters', u'related': [u'changeServiceForRouter', u'stopRouter', u'destroyRouter', u'rebootRouter', u'startRouter'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the state of the router'}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'List networks by VPC'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID of the router'}, {u'name': u'hostid', u'required': False, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'the host ID of the router'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the router'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the router'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'id', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'addNicToVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk router'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'networkid', u'required': False, u'related': [u'createNetwork', u'listNiciraNvpDeviceNetworks', u'updateNetwork', u'listF5LoadBalancerNetworks', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'list by network id'}, {u'name': u'forvpc', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true is passed for this parameter, list only VPC routers'}], u'requiredparams': [], u'description': u'List routers.'}, u'traffictypes': {u'name': u'listTrafficTypes', u'related': [u'addNetworkServiceProvider', u'updateNetworkServiceProvider'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'physicalnetworkid', u'required': True, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'physicalnetworkid'], u'description': u'Lists traffic types of a given physical network.'}, u'projectinvitations': {u'name': u'listProjectInvitations', u'related': [], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'activeonly', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'if true, list only active invitations - having Pending state and ones that are not timed out yet'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list by project id'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list invitations by state'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'id', u'required': False, u'related': [u'listProjectInvitations'], u'length': 255, u'type': u'uuid', u'description': u'list invitations by id'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists projects and provides detailed information for listed projects'}, u'isos': {u'name': u'listIsos', u'related': [], u'isasync': False, u'params': [{u'name': u'bootable', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the ISO is bootable, false otherwise'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list all isos by name'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'id', u'required': False, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'list ISO by id'}, {u'name': u'ispublic', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if the ISO is publicly available to all users, false otherwise.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isofilter', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'possible values are "featured", "self", "selfexecutable","sharedexecutable","executable", and "community". * featured : templates that have been marked as featured and public. * self : templates that have been registered or created by the calling user. * selfexecutable : same as self, but only returns templates that can be used to deploy a new VM. * sharedexecutable : templates ready to be deployed that have been granted to the calling user by another user. * executable : templates that are owned by the calling user, or public templates, that can be used to deploy a VM. * community : templates that have been marked as public but not featured. * all : all templates (only usable by admins).'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the hypervisor for which to restrict the search'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'isready', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if this ISO is ready to be deployed'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all available ISO files.'}, u'users': {u'name': u'listUsers', u'related': [], u'isasync': False, u'params': [{u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List user by the username'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'accounttype', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'List users by account type. Valid types include admin, domain-admin, read-only-admin, or user.'}, {u'name': u'id', u'required': False, u'related': [u'listUsers'], u'length': 255, u'type': u'uuid', u'description': u'List user by ID.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List users by state of the user account.'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists user accounts'}, u'sshkeypairs': {u'name': u'listSSHKeyPairs', u'related': [], u'isasync': False, u'params': [{u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'fingerprint', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'A public key fingerprint to look for'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'A key pair name to look for'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}], u'requiredparams': [], u'description': u'List registered keypairs'}, u'privategateways': {u'name': u'listPrivateGateways', u'related': [u'createPrivateGateway'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'createPrivateGateway', u'listPrivateGateways'], u'length': 255, u'type': u'uuid', u'description': u'list private gateway by id'}, {u'name': u'ipaddress', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list gateways by ip address'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'list gateways by vpc'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list gateways by state'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list gateways by vlan'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}], u'requiredparams': [], u'description': u'List private gateways'}, u'usagetypes': {u'name': u'listUsageTypes', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'List Usage Types'}, u'domainchildren': {u'name': u'listDomainChildren', u'related': [u'createDomain'], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list children domains by name'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list children domain by parent domain ID.'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'to return the entire tree, use the value "true". To return the first level children, use the value "false".'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all children domains belonging to a specified domain'}, u'domains': {u'name': u'listDomains', u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'List domain by domain ID.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List domain by domain name.'}, {u'name': u'level', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'List domains by domain level.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}], u'requiredparams': [], u'description': u'Lists domains and provides detailed information for listed domains'}, u'externalloadbalancers': {u'name': u'listExternalLoadBalancers', u'related': [u'addHost', u'updateHost', u'listHosts'], u'isasync': False, u'params': [{u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'zone Id'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists F5 external load balancer appliances added in a zone.'}, u'netscalerloadbalancers': {u'name': u'listNetscalerLoadBalancers', u'related': [], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'lbdeviceid', u'required': False, u'related': [u'listNetscalerLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'lists netscaler load balancer devices'}, u's3s': {u'name': u'listS3s', u'related': [u'addS3'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists S3s'}, u'bigswitchvnsdevices': {u'name': u'listBigSwitchVnsDevices', u'related': [u'addBigSwitchVnsDevice'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vnsdeviceid', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'bigswitch vns device ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}], u'requiredparams': [], u'description': u'Lists BigSwitch Vns devices'}, u'accounts': {u'name': u'listAccounts', u'related': [u'markDefaultZoneForAccount', u'lockAccount'], u'isasync': False, u'params': [{u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list accounts by state. Valid states are enabled, disabled, and locked.'}, {u'name': u'iscleanuprequired', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list accounts by cleanuprequred attribute (values are true or false)'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'accounttype', u'required': False, u'related': [], u'length': 255, u'type': u'long', u'description': u'list accounts by account type. Valid account types are 1 (admin), 2 (domain-admin), and 0 (user).'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'markDefaultZoneForAccount', u'listAccounts', u'lockAccount'], u'length': 255, u'type': u'uuid', u'description': u'list account by account ID'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list account by account name'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [], u'description': u'Lists accounts and provides detailed account information for listed accounts'}, u'networkdevice': {u'name': u'listNetworkDevice', u'related': [u'addNetworkDevice'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'networkdevicetype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Network device type, now supports ExternalDhcp, PxeServer, NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer, F5BigIpLoadBalancer, JuniperSRXFirewall'}, {u'name': u'networkdeviceparameterlist', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'parameters for network device'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'List network devices'}, u'vlanipranges': {u'name': u'listVlanIpRanges', u'related': [], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'networkid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'network id of the VLAN IP range'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the domain ID with which the VLAN IP range is associated. If used with the account parameter, returns all VLAN IP ranges for that account in the specified domain.'}, {u'name': u'id', u'required': False, u'related': [u'listVlanIpRanges'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the VLAN IP range'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks'], u'length': 255, u'type': u'uuid', u'description': u'physical network id of the VLAN IP range'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'project who will own the VLAN'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account with which the VLAN IP range is associated. Must be used with the domainId parameter.'}, {u'name': u'vlan', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the ID or VID of the VLAN. Default is an "untagged" VLAN.'}, {u'name': u'podid', u'required': False, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the Pod ID of the VLAN IP range'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Zone ID of the VLAN IP range'}, {u'name': u'forvirtualnetwork', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if VLAN is of Virtual type, false if Direct'}], u'requiredparams': [], u'description': u'Lists all VLAN IP ranges.'}, u'traffictypeimplementors': {u'name': u'listTrafficTypeImplementors', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'Optional. The network traffic type, if specified, return its implementor. Otherwise, return all traffic types with their implementor'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists implementors of implementor of a network traffic type or implementors of all network traffic types'}, u'storagenetworkiprange': {u'name': u'listStorageNetworkIpRange', u'related': [u'updateStorageNetworkIpRange'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'optional parameter. Zone uuid, if specicied and both pod uuid and range uuid are absent, using it to search the range.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'listStorageNetworkIpRange', u'updateStorageNetworkIpRange'], u'length': 255, u'type': u'uuid', u'description': u'optional parameter. Storaget network IP range uuid, if specicied, using it to search the range.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'podid', u'required': False, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'optional parameter. Pod uuid, if specicied and range uuid is absent, using it to search the range.'}], u'requiredparams': [], u'description': u'List a storage network IP range.'}, u'isopermissions': {u'name': u'listIsoPermissions', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIsoPermissions'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}], u'requiredparams': [u'id'], u'description': u'List iso visibility and all accounts that have permissions to view this iso.'}, u'snapshotpolicies': {u'name': u'listSnapshotPolicies', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'volumeid', u'required': True, u'related': [u'detachVolume', u'uploadVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [u'volumeid'], u'description': u'Lists snapshot policies.'}, u'autoscalevmgroups': {u'name': u'listAutoScaleVmGroups', u'related': [u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'isasync': False, u'params': [{u'name': u'policyid', u'required': False, u'related': [u'createAutoScalePolicy', u'updateAutoScalePolicy', u'listAutoScalePolicies'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the policy'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'vmprofileid', u'required': False, u'related': [u'updateAutoScaleVmProfile', u'createAutoScaleVmProfile', u'listAutoScaleVmProfiles'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the profile'}, {u'name': u'lbruleid', u'required': False, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the loadbalancer'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the availability zone ID'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'id', u'required': False, u'related': [u'listAutoScaleVmGroups', u'createAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale vm group'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists autoscale vm groups.'}, u'projectaccounts': {u'name': u'listProjectAccounts', u'related': [u'createProject'], u'isasync': False, u'params': [{u'name': u'projectid', u'required': True, u'related': [u'createProject', u'listProjectAccounts'], u'length': 255, u'type': u'uuid', u'description': u'id of the project'}, {u'name': u'role', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list accounts of the project by role'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list accounts of the project by account name'}], u'requiredparams': [u'projectid'], u'description': u"Lists project's accounts"}, u'autoscalevmprofiles': {u'name': u'listAutoScaleVmProfiles', u'related': [], u'isasync': False, u'params': [{u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'id', u'required': False, u'related': [u'listAutoScaleVmProfiles'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale vm profile'}, {u'name': u'templateid', u'required': False, u'related': [u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the templateid of the autoscale vm profile'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'otherdeployparams', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the otherdeployparameters of the autoscale vm profile'}], u'requiredparams': [], u'description': u'Lists autoscale vm profiles.'}, u'apis': {u'name': u'listApis', u'related': [], u'isasync': False, u'params': [{u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'API name'}], u'requiredparams': [], u'description': u'lists all available apis on the server, provided by the Api Discovery plugin'}, u'vpcs': {u'name': u'listVPCs', u'related': [u'restartVPC'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'domainid', u'required': False, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by name of the VPC'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'cidr', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u"list by cidr of the VPC. All VPC guest networks' cidrs should be within this CIDR"}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'restartrequired', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list VPCs by restartRequired option'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list VPCs by state'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by display text of the VPC'}, {u'name': u'id', u'required': False, u'related': [u'restartVPC', u'listVPCs'], u'length': 255, u'type': u'uuid', u'description': u'list VPC by id'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list by zone'}, {u'name': u'supportedservices', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list VPC supporting certain services'}, {u'name': u'vpcofferingid', u'required': False, u'related': [u'listVPCOfferings', u'createVPCOffering'], u'length': 255, u'type': u'uuid', u'description': u'list by ID of the VPC offering'}], u'requiredparams': [], u'description': u'Lists VPCs'}, u'f5loadbalancers': {u'name': u'listF5LoadBalancers', u'related': [u'configureF5LoadBalancer'], u'isasync': False, u'params': [{u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'updatePhysicalNetwork', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'lbdeviceid', u'required': False, u'related': [u'configureF5LoadBalancer', u'listF5LoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'f5 load balancer device ID'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'lists F5 load balancer devices'}, u'snapshots': {u'name': u'listSnapshots', u'related': [], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'id', u'required': False, u'related': [u'listSnapshots'], u'length': 255, u'type': u'uuid', u'description': u'lists snapshot by snapshot ID'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'intervaltype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'valid values are HOURLY, DAILY, WEEKLY, and MONTHLY.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'volumeid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'lists snapshot by snapshot name'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'snapshottype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'valid values are MANUAL or RECURRING.'}], u'requiredparams': [], u'description': u'Lists all available snapshots for the account.'}, u'networkofferings': {u'name': u'listNetworkOfferings', u'related': [u'createNetworkOffering', u'updateNetworkOffering'], u'isasync': False, u'params': [{u'name': u'isdefault', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only default network offerings. Default value is false'}, {u'name': u'sourcenatsupported', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only netwok offerings where source nat is supported, false otherwise'}, {u'name': u'supportedservices', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list network offerings supporting certain services'}, {u'name': u'networkid', u'required': False, u'related': [u'createNetwork', u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network. Pass this in if you want to see the available network offering that a network can be changed to.'}, {u'name': u'specifyipranges', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only network offerings which support specifying ip ranges'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network offerings by name'}, {u'name': u'id', u'required': False, u'related': [u'listNetworkOfferings', u'createNetworkOffering', u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'list network offerings by id'}, {u'name': u'specifyvlan', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the tags for the network offering.'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'list netowrk offerings available for network creation in specific zone'}, {u'name': u'forvpc', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'the network offering can be used only for network creation inside the VPC'}, {u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by traffic type'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'guestiptype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network offerings by guest type: Shared or Isolated'}, {u'name': u'istagged', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if offering has tags specified'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 4096, u'type': u'string', u'description': u'list network offerings by tags'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network offerings by display text'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network offerings by state'}, {u'name': u'availability', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the availability of network offering. Default value is Required'}], u'requiredparams': [], u'description': u'Lists all available network offerings.'}, u'virtualmachines': {u'name': u'listVirtualMachines', u'related': [], u'isasync': False, u'params': [{u'name': u'templateid', u'required': False, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'list vms by template'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'networkid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list by network id'}, {u'name': u'storageid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u"the storage ID where vm's volumes belong to"}, {u'name': u'isoid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list vms by iso'}, {u'name': u'vpcid', u'required': False, u'related': [u'restartVPC'], u'length': 255, u'type': u'uuid', u'description': u'list vms by vpc'}, {u'name': u'podid', u'required': False, u'related': [u'updatePod'], u'length': 255, u'type': u'uuid', u'description': u'the pod ID'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the virtual machine'}, {u'name': u'details', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'comma separated list of host details requested, value can be a list of [all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min]. If no parameter is passed in, the details will be defaulted to all'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the target hypervisor for the template'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'groupid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the group ID'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the availability zone ID'}, {u'name': u'hostid', u'required': False, u'related': [u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}, {u'name': u'id', u'required': False, u'related': [u'listVirtualMachines'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'forvirtualnetwork', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list by network type; true if need to list vms using Virtual Network, false otherwise'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'state of the virtual machine'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'List the virtual machines owned by the account.'}, u'netscalerloadbalancernetworks': {u'name': u'listNetscalerLoadBalancerNetworks', u'related': [], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'lbdeviceid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}], u'requiredparams': [u'lbdeviceid'], u'description': u'lists network that are using a netscaler load balancer device'}, u'oscategories': {u'name': u'listOsCategories', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listOsCategories'], u'length': 255, u'type': u'uuid', u'description': u'list Os category by id'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list os category by name'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists all supported OS categories for this cloud.'}, u'virtualrouterelements': {u'name': u'listVirtualRouterElements', u'related': [u'createVirtualRouterElement', u'configureVirtualRouterElement'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'nspid', u'required': False, u'related': [u'addNetworkServiceProvider', u'listTrafficTypes', u'updateNetworkServiceProvider'], u'length': 255, u'type': u'uuid', u'description': u'list virtual router elements by network service provider id'}, {u'name': u'id', u'required': False, u'related': [u'createVirtualRouterElement', u'configureVirtualRouterElement', u'listVirtualRouterElements'], u'length': 255, u'type': u'uuid', u'description': u'list virtual router elements by id'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'enabled', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'list network offerings by enabled state'}], u'requiredparams': [], u'description': u'Lists all available virtual router elements.'}, u'lunsonfiler': {u'name': u'listLunsOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'poolname'], u'description': u'List LUN'}, u'asyncjobs': {u'name': u'listAsyncJobs', u'related': [u'queryAsyncJobResult'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'startdate', u'required': False, u'related': [], u'length': 255, u'type': u'tzdate', u'description': u'the start date of the async job'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}], u'requiredparams': [], u'description': u'Lists all pending asynchronous jobs for the account.'}, u'ostypes': {u'name': u'listOsTypes', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [u'listOsTypes'], u'length': 255, u'type': u'uuid', u'description': u'list by Os type Id'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'oscategoryid', u'required': False, u'related': [u'listOsCategories'], u'length': 255, u'type': u'uuid', u'description': u'list by Os Category id'}, {u'name': u'description', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list os by description'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all supported OS types for this cloud.'}, u'networkacls': {u'name': u'listNetworkACLs', u'related': [u'createNetworkACL'], u'isasync': False, u'params': [{u'name': u'traffictype', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list network ACLs by traffic type - Ingress or Egress'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'Lists network ACL with the specified ID.'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'networkid', u'required': False, u'related': [u'createNetwork', u'listNiciraNvpDeviceNetworks', u'updateNetwork', u'listF5LoadBalancerNetworks', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'length': 255, u'type': u'uuid', u'description': u'list network ACLs by network Id'}], u'requiredparams': [], u'description': u'Lists all network ACLs'}, u'volumesonfiler': {u'name': u'listVolumesOnFiler', u'related': [], u'isasync': False, u'params': [{u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'poolname'], u'description': u'List Volumes'}, u'eventtypes': {u'name': u'listEventTypes', u'related': [], u'isasync': False, u'params': [], u'requiredparams': [], u'description': u'List Event Types'}, u'remoteaccessvpns': {u'name': u'listRemoteAccessVpns', u'related': [u'createRemoteAccessVpn'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'publicipid', u'required': True, u'related': [u'restartNetwork', u'listPublicIpAddresses', u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'public ip address id of the vpn server'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}], u'requiredparams': [u'publicipid'], u'description': u'Lists remote access vpns'}, u'alerts': {u'name': u'listAlerts', u'related': [], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list by alert type'}, {u'name': u'id', u'required': False, u'related': [u'listAlerts'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the alert'}], u'requiredparams': [], u'description': u'Lists all alerts.'}, u'regions': {u'name': u'listRegions', u'related': [u'addRegion'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'List Region by region ID.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List Region by region name.'}], u'requiredparams': [], u'description': u'Lists Regions'}, u'vpcofferings': {u'name': u'listVPCOfferings', u'related': [], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listVPCOfferings'], u'length': 255, u'type': u'uuid', u'description': u'list VPC offerings by id'}, {u'name': u'state', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list VPC offerings by state'}, {u'name': u'supportedservices', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list VPC offerings supporting certain services'}, {u'name': u'displaytext', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list VPC offerings by display text'}, {u'name': u'isdefault', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if need to list only default VPC offerings. Default value is false'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list VPC offerings by name'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists VPC offerings'}, u'niciranvpdevicenetworks': {u'name': u'listNiciraNvpDeviceNetworks', u'related': [u'createNetwork', u'updateNetwork', u'listF5LoadBalancerNetworks', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks', u'listNetworks'], u'isasync': False, u'params': [{u'name': u'nvpdeviceid', u'required': True, u'related': [u'addNiciraNvpDevice', u'listNiciraNvpDevices'], u'length': 255, u'type': u'uuid', u'description': u'nicira nvp device ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [u'nvpdeviceid'], u'description': u'lists network that are using a nicira nvp device'}, u'events': {u'name': u'listEvents', u'related': [], u'isasync': False, u'params': [{u'name': u'startdate', u'required': False, u'related': [], u'length': 255, u'type': u'date', u'description': u'the start date range of the list you want to retrieve (use format "yyyy-MM-dd" or the new format "yyyy-MM-dd HH:mm:ss")'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'enddate', u'required': False, u'related': [], u'length': 255, u'type': u'date', u'description': u'the end date range of the list you want to retrieve (use format "yyyy-MM-dd" or the new format "yyyy-MM-dd HH:mm:ss")'}, {u'name': u'duration', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the duration of the event'}, {u'name': u'id', u'required': False, u'related': [u'listEvents'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the event'}, {u'name': u'level', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the event level (INFO, WARN, ERROR)'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'entrytime', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'the time the event was entered'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the event type (see event types)'}], u'requiredparams': [], u'description': u'A command to list events.'}, u'templates': {u'name': u'listTemplates', u'related': [u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'isasync': False, u'params': [{u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'templatefilter', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'possible values are "featured", "self", "selfexecutable","sharedexecutable","executable", and "community". * featured : templates that have been marked as featured and public. * self : templates that have been registered or created by the calling user. * selfexecutable : same as self, but only returns templates that can be used to deploy a new VM. * sharedexecutable : templates ready to be deployed that have been granted to the calling user by another user. * executable : templates that are owned by the calling user, or public templates, that can be used to deploy a VM. * community : templates that have been marked as public but not featured. * all : all templates (only usable by admins).'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listTemplates', u'registerIso', u'updateTemplate', u'prepareTemplate', u'copyIso', u'updateIso', u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the template ID'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the template name'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'hypervisor', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the hypervisor for which to restrict the search'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'list templates by zoneId'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}], u'requiredparams': [u'templatefilter'], u'description': u'List all public, private, and privileged templates.'}, u'cisconexusvsms': {u'name': u'listCiscoNexusVSMs', u'related': [u'disableCiscoNexusVSM', u'enableCiscoNexusVSM'], u'isasync': False, u'params': [{u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'clusterid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Id of the CloudStack cluster in which the Cisco Nexus 1000v VSM appliance.'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'Id of the CloudStack cluster in which the Cisco Nexus 1000v VSM appliance.'}], u'requiredparams': [], u'description': u'Retrieves a Cisco Nexus 1000v Virtual Switch Manager device associated with a Cluster'}, u'ipforwardingrules': {u'name': u'listIpForwardingRules', u'related': [], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'id', u'required': False, u'related': [u'listIpForwardingRules'], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'listVirtualMachines', u'destroyVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Lists all rules applied to the specified Vm.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'ipaddressid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list the rule belonging to this public ip address'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}], u'requiredparams': [], u'description': u'List the ip forwarding rules'}, u'srxfirewalls': {u'name': u'listSrxFirewalls', u'related': [u'addSrxFirewall'], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'physicalnetworkid', u'required': False, u'related': [u'listPhysicalNetworks', u'createPhysicalNetwork'], u'length': 255, u'type': u'uuid', u'description': u'the Physical Network ID'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'fwdeviceid', u'required': False, u'related': [u'listSrxFirewalls', u'addSrxFirewall'], u'length': 255, u'type': u'uuid', u'description': u'SRX firewall device ID'}], u'requiredparams': [], u'description': u'lists SRX firewall devices in a physical network'}, u'vpnconnections': {u'name': u'listVpnConnections', u'related': [], u'isasync': False, u'params': [{u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vpcid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'id of vpc'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'id', u'required': False, u'related': [u'listVpnConnections'], u'length': 255, u'type': u'uuid', u'description': u'id of the vpn connection'}], u'requiredparams': [], u'description': u'Lists site to site vpn connection gateways'}, u'trafficmonitors': {u'name': u'listTrafficMonitors', u'related': [], u'isasync': False, u'params': [{u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'zoneid', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'zone Id'}], u'requiredparams': [u'zoneid'], u'description': u'List traffic monitor Hosts.'}, u'vpnusers': {u'name': u'listVpnUsers', u'related': [], u'isasync': False, u'params': [{u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'id', u'required': False, u'related': [u'listVpnUsers'], u'length': 255, u'type': u'uuid', u'description': u'The uuid of the Vpn user'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'username', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the username of the vpn user.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}], u'requiredparams': [], u'description': u'Lists vpn users'}, u'egressfirewallrules': {u'name': u'listEgressFirewallRules', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'networkid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id network network for the egress firwall services'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Lists rule with the specified ID.'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'ipaddressid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the id of IP address of the firwall services'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}], u'requiredparams': [], u'description': u'Lists all egress firewall rules for network id.'}, u'staticroutes': {u'name': u'listStaticRoutes', u'related': [u'createStaticRoute'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'gatewayid', u'required': False, u'related': [u'createPrivateGateway'], u'length': 255, u'type': u'uuid', u'description': u'list static routes by gateway id'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'vpcid', u'required': False, u'related': [u'updateVPC', u'restartVPC', u'listVPCs', u'createVPC'], u'length': 255, u'type': u'uuid', u'description': u'list static routes by vpc id'}, {u'name': u'id', u'required': False, u'related': [u'createStaticRoute', u'listStaticRoutes'], u'length': 255, u'type': u'uuid', u'description': u'list static route by id'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}], u'requiredparams': [], u'description': u'Lists all static routes'}, u'volumes': {u'name': u'listVolumes', u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'uploadVolume', u'createVolume'], u'isasync': False, u'params': [{u'name': u'isrecursive', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'defaults to false, but if true, lists all resources from the parent specified by the domainId till leaves.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the disk volume'}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'listProjects', u'suspendProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'list objects by project'}, {u'name': u'hostid', u'required': False, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addSecondaryStorage', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers', u'prepareHostForMaintenance'], u'length': 255, u'type': u'uuid', u'description': u'list volumes on specified host'}, {u'name': u'id', u'required': False, u'related': [u'migrateVolume', u'detachVolume', u'resizeVolume', u'attachVolume', u'listVolumes', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the disk volume'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'List resources by tags (key/value pairs)'}, {u'name': u'zoneid', u'required': False, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the availability zone'}, {u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'list only resources belonging to the domain specified'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list resources by account. Must be used with the domainId parameter.'}, {u'name': u'virtualmachineid', u'required': False, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'rebootVirtualMachine', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'attachIso', u'listLoadBalancerRuleInstances', u'deployVirtualMachine', u'detachIso', u'resetSSHKeyForVirtualMachine', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the virtual machine'}, {u'name': u'type', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the type of disk volume'}, {u'name': u'listall', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u"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"}, {u'name': u'podid', u'required': False, u'related': [u'createPod', u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the pod id the disk volume belongs to'}], u'requiredparams': [], u'description': u'Lists all volumes.'}, u'pods': {u'name': u'listPods', u'related': [u'updatePod'], u'isasync': False, u'params': [{u'name': u'showcapacities', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'flag to display the capacity of the pods'}, {u'name': u'allocationstate', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list pods by allocation state'}, {u'name': u'pagesize', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'list Pods by Zone ID'}, {u'name': u'id', u'required': False, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'list Pods by ID'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'list Pods by name'}, {u'name': u'page', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u''}, {u'name': u'keyword', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'List by keyword'}], u'requiredparams': [], u'description': u'Lists all Pods.'}}, u'upload': {u'volume': {u'name': u'uploadVolume', u'related': [u'detachVolume'], u'isasync': True, u'params': [{u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the name of the volume'}, {u'name': u'format', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the format for the volume. Possible values include QCOW2, OVA, and VHD.'}, {u'name': u'url', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'the URL of where the volume is hosted. Possible URL include http:// and https://'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional accountName. Must be used with domainId.'}, {u'name': u'domainid', u'required': False, u'related': [u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId. If the account parameter is used, domainId must also be used.'}, {u'name': u'checksum', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the MD5 checksum value of this volume'}, {u'name': u'zoneid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone the volume is to be hosted on'}], u'requiredparams': [u'name', u'format', u'url', u'zoneid'], u'description': u'Uploads a data disk.'}, u'customcertificate': {u'name': u'uploadCustomCertificate', u'related': [], u'isasync': True, u'params': [{u'name': u'domainsuffix', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'DNS domain suffix that the certificate is granted for.'}, {u'name': u'certificate', u'required': True, u'related': [], u'length': 65535, u'type': u'string', u'description': u'The certificate to be uploaded.'}, {u'name': u'privatekey', u'required': False, u'related': [], u'length': 65535, u'type': u'string', u'description': u'The private key for the attached certificate.'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'A name / alias for the certificate.'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'integer', u'description': u'An integer providing the location in a chain that the certificate will hold. Usually, this can be left empty. When creating a chain, the top level certificate should have an ID of 1, with each step in the chain incrementing by one. Example, CA with id = 1, Intermediate CA with id = 2, Site certificate with ID = 3'}], u'requiredparams': [u'domainsuffix', u'certificate'], u'description': u'Uploads a custom certificate for the console proxy VMs to use for SSL. Can be used to upload a single certificate signed by a known CA. Can also be used, through multiple calls, to upload a chain of certificates from CA to the custom certificate itself.'}}, u'remove': {u'region': {u'name': u'removeRegion', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'integer', u'description': u'ID of the region to delete'}], u'requiredparams': [u'id'], u'description': u'Removes specified region'}, u'nicfromvirtualmachine': {u'name': u'removeNicFromVirtualMachine', u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': True, u'params': [{u'name': u'nicid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'NIC ID'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'startVirtualMachine', u'updateDefaultNicForVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'resetPasswordForVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'removeNicFromVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'Virtual Machine ID'}], u'requiredparams': [u'nicid', u'virtualmachineid'], u'description': u'Removes VM from specified network by deleting a NIC'}, u'fromloadbalancerrule': {u'name': u'removeFromLoadBalancerRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIpForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the load balancer rule'}, {u'name': u'virtualmachineids', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'list', u'description': u'the list of IDs of the virtual machines that are being removed from the load balancer rule (i.e. virtualMachineIds=1,2,3)'}], u'requiredparams': [u'id', u'virtualmachineids'], u'description': u'Removes a virtual machine or a list of virtual machines from a load balancer rule.'}, u'vpnuser': {u'name': u'removeVpnUser', u'related': [], u'isasync': True, u'params': [{u'name': u'domainid', u'required': False, u'related': [u'updateDomain', u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'an optional domainId for the vpn user. If the account parameter is used, domainId must also be used.'}, {u'name': u'projectid', u'required': False, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'remove vpn user from the project'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'an optional account for the vpn user. Must be used with domainId.'}, {u'name': u'username', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'username for the vpn user'}], u'requiredparams': [u'username'], u'description': u'Removes vpn user'}}, u'asyncapis': [u'createCondition', u'reconnectHost', u'copyTemplate', u'deleteBigSwitchVnsDevice', u'addNicToVirtualMachine', u'extractVolume', u'addAccountToProject', u'deleteEgressFirewallRule', u'deleteCiscoNexusVSM', u'createVpnConnection', u'suspendProject', u'addF5LoadBalancer', u'deleteAutoScaleVmGroup', u'authorizeSecurityGroupIngress', u'addNetscalerLoadBalancer', u'deleteDomain', u'configureNetscalerLoadBalancer', u'disableAutoScaleVmGroup', u'authorizeSecurityGroupEgress', u'createTemplate', u'migrateVolume', u'updatePhysicalNetwork', u'prepareHostForMaintenance', u'deletePrivateGateway', u'deleteStaticRoute', u'deleteTrafficType', u'deleteLoadBalancerRule', u'attachIso', u'destroySystemVm', u'deletePortForwardingRule', u'enableStorageMaintenance', u'stopRouter', u'configureSrxFirewall', u'attachVolume', u'updateVPCOffering', u'resetSSHKeyForVirtualMachine', u'updateProjectInvitation', u'createTags', u'enableAutoScaleVmGroup', u'deleteTags', u'deleteAccountFromProject', u'removeVpnUser', u'updateVpnCustomerGateway', u'stopSystemVm', u'uploadCustomCertificate', u'restartNetwork', u'createAutoScaleVmProfile', u'rebootVirtualMachine', u'enableCiscoNexusVSM', u'cancelHostMaintenance', u'deleteStorageNetworkIpRange', u'deleteFirewallRule', u'deleteVpnConnection', u'startSystemVm', u'deleteF5LoadBalancer', u'deleteNiciraNvpDevice', u'updateProject', u'deleteNetwork', u'deleteProject', u'deleteNetscalerLoadBalancer', u'deleteIpForwardingRule', u'addTrafficType', u'disableUser', u'resizeVolume', u'configureVirtualRouterElement', u'createStaticRoute', u'deleteProjectInvitation', u'migrateSystemVm', u'activateProject', u'removeNicFromVirtualMachine', u'revokeSecurityGroupIngress', u'updateDefaultNicForVirtualMachine', u'disableStaticNat', u'createNetworkACL', u'createVPC', u'configureF5LoadBalancer', u'disassociateIpAddress', u'createIpForwardingRule', u'createVolume', u'resetPasswordForVirtualMachine', u'assignToLoadBalancerRule', u'startRouter', u'extractIso', u'deleteRemoteAccessVpn', u'resetVpnConnection', u'createRemoteAccessVpn', u'extractTemplate', u'startVirtualMachine', u'detachIso', u'updateVPC', u'deleteAccount', u'associateIpAddress', u'updateAutoScaleVmProfile', u'disableAccount', u'updatePortForwardingRule', u'migrateVirtualMachine', u'createStorageNetworkIpRange', u'cancelStorageMaintenance', u'deployVirtualMachine', u'removeFromLoadBalancerRule', u'revokeSecurityGroupEgress', u'deleteCondition', u'createPortForwardingRule', u'addVpnUser', u'createVPCOffering', u'createEgressFirewallRule', u'deleteLBStickinessPolicy', u'destroyRouter', u'createPrivateGateway', u'disableCiscoNexusVSM', u'deleteAutoScaleVmProfile', u'updateTrafficType', u'deleteSnapshot', u'createProject', u'createLoadBalancerRule', u'addSrxFirewall', u'addNiciraNvpDevice', u'createAutoScalePolicy', u'restoreVirtualMachine', u'copyIso', u'uploadVolume', u'createLBStickinessPolicy', u'stopVirtualMachine', u'createCounter', u'createSnapshot', u'destroyVirtualMachine', u'updateNetwork', u'deleteVpnGateway', u'createAutoScaleVmGroup', u'rebootRouter', u'deleteNetworkServiceProvider', u'deleteIso', u'createVpnCustomerGateway', u'createFirewallRule', u'deleteAutoScalePolicy', u'deleteSrxFirewall', u'addNetworkServiceProvider', u'rebootSystemVm', u'detachVolume', u'deleteNetworkACL', u'markDefaultZoneForAccount', u'deleteVPC', u'restartVPC', u'updateAutoScaleVmGroup', u'updateLoadBalancerRule', u'createPhysicalNetwork', u'deleteTemplate', u'deletePhysicalNetwork', u'deleteVpnCustomerGateway', u'deleteVPCOffering', u'createVirtualRouterElement', u'updateAutoScalePolicy', u'addBigSwitchVnsDevice', u'createVpnGateway', u'updateNetworkServiceProvider', u'deleteCounter', u'updateStorageNetworkIpRange'], u'assign': {u'toloadbalancerrule': {u'name': u'assignToLoadBalancerRule', u'related': [], u'isasync': True, u'params': [{u'name': u'virtualmachineids', u'required': True, u'related': [u'startVirtualMachine', u'updateVirtualMachine', u'stopVirtualMachine', u'recoverVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'migrateVirtualMachine', u'changeServiceForVirtualMachine', u'deployVirtualMachine', u'detachIso', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'list', u'description': u'the list of IDs of the virtual machine that are being assigned to the load balancer rule(i.e. virtualMachineIds=1,2,3)'}, {u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}], u'requiredparams': [u'virtualmachineids', u'id'], u'description': u'Assigns virtual machine or a list of virtual machines to a load balancer rule.'}, u'virtualmachine': {u'name': u'assignVirtualMachine', u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'isasync': False, u'params': [{u'name': u'networkids', u'required': False, u'related': [u'updateNetwork', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'list', u'description': u'list of new network ids in which the moved VM will participate. In case no network ids are provided the VM will be part of the default network for that zone. In case there is no network yet created for the new account the default network will be created.'}, {u'name': u'domainid', u'required': True, u'related': [u'listDomainChildren', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'domain id of the new VM owner.'}, {u'name': u'securitygroupids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of security group ids to be applied on the virtual machine. In case no security groups are provided the VM is part of the default security group.'}, {u'name': u'account', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'account name of the new VM owner.'}, {u'name': u'virtualmachineid', u'required': True, u'related': [u'updateVirtualMachine', u'stopVirtualMachine', u'assignVirtualMachine', u'listVirtualMachines', u'destroyVirtualMachine', u'restoreVirtualMachine'], u'length': 255, u'type': u'uuid', u'description': u'id of the VM to be moved'}], u'requiredparams': [u'domainid', u'account', u'virtualmachineid'], u'description': u'Assign a VM from one account to another under the same domain. This API is available for Basic zones with security groups and Advance zones with guest networks. The VM is restricted to move between accounts under same domain.'}}, u'delete': {u'loadbalancerrule': {u'name': u'deleteLoadBalancerRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the load balancer rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a load balancer rule.'}, u'domain': {u'name': u'deleteDomain', u'related': [], u'isasync': True, u'params': [{u'name': u'cleanup', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'true if all domain resources (child domains, accounts) have to be cleaned up, false otherwise'}, {u'name': u'id', u'required': True, u'related': [u'updateDomain', u'listDomainChildren', u'listDomains', u'createDomain'], u'length': 255, u'type': u'uuid', u'description': u'ID of domain to delete'}], u'requiredparams': [u'id'], u'description': u'Deletes a specified domain'}, u'instancegroup': {u'name': u'deleteInstanceGroup', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the instance group'}], u'requiredparams': [u'id'], u'description': u'Deletes a vm group'}, u'diskoffering': {u'name': u'deleteDiskOffering', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateDiskOffering', u'createDiskOffering', u'listDiskOfferings'], u'length': 255, u'type': u'uuid', u'description': u'ID of the disk offering'}], u'requiredparams': [u'id'], u'description': u'Updates a disk offering.'}, u'externalloadbalancer': {u'name': u'deleteExternalLoadBalancer', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listSwifts', u'addHost', u'cancelHostMaintenance', u'addBaremetalHost', u'updateHost', u'addSwift', u'listHosts', u'listExternalLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'Id of the external loadbalancer appliance.'}], u'requiredparams': [u'id'], u'description': u'Deletes a F5 external load balancer appliance added in a zone.'}, u'securitygroup': {u'name': u'deleteSecurityGroup', u'related': [], u'isasync': False, u'params': [{u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the domain ID of account owning the security group'}, {u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'The ID of the security group. Mutually exclusive with name parameter'}, {u'name': u'name', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'The ID of the security group. Mutually exclusive with id parameter'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account of the security group. Must be specified with domain ID'}, {u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the project of the security group'}], u'requiredparams': [], u'description': u'Deletes security group'}, u'portforwardingrule': {u'name': u'deletePortForwardingRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the port forwarding rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a port forwarding rule'}, u'cluster': {u'name': u'deleteCluster', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the cluster ID'}], u'requiredparams': [u'id'], u'description': u'Deletes a cluster.'}, u'accountfromproject': {u'name': u'deleteAccountFromProject', u'related': [], u'isasync': True, u'params': [{u'name': u'projectid', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to remove the account from'}, {u'name': u'account', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'name of the account to be removed from the project'}], u'requiredparams': [u'projectid', u'account'], u'description': u'Deletes account from the project'}, u'networkdevice': {u'name': u'deleteNetworkDevice', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'addHost', u'updateHost', u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'Id of network device to delete'}], u'requiredparams': [u'id'], u'description': u'Deletes network device.'}, u'firewallrule': {u'name': u'deleteFirewallRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the firewall rule'}], u'requiredparams': [u'id'], u'description': u'Deletes a firewall rule'}, u'pod': {u'name': u'deletePod', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePod', u'listPods'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Pod'}], u'requiredparams': [u'id'], u'description': u'Deletes a Pod.'}, u'ipforwardingrule': {u'name': u'deleteIpForwardingRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the id of the forwarding rule'}], u'requiredparams': [u'id'], u'description': u'Deletes an ip forwarding rule'}, u'vpnconnection': {u'name': u'deleteVpnConnection', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listVpnConnections', u'resetVpnConnection'], u'length': 255, u'type': u'uuid', u'description': u'id of vpn connection'}], u'requiredparams': [u'id'], u'description': u'Delete site to site vpn connection'}, u'lbstickinesspolicy': {u'name': u'deleteLBStickinessPolicy', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createLBStickinessPolicy'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the LB stickiness policy'}], u'requiredparams': [u'id'], u'description': u'Deletes a LB stickiness policy.'}, u'vpcoffering': {u'name': u'deleteVPCOffering', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the VPC offering'}], u'requiredparams': [u'id'], u'description': u'Deletes VPC offering'}, u'network': {u'name': u'deleteNetwork', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateNetwork', u'listSrxFirewallNetworks', u'listNetscalerLoadBalancerNetworks'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network'}], u'requiredparams': [u'id'], u'description': u'Deletes a network'}, u'zone': {u'name': u'deleteZone', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateZone', u'listZones', u'createZone'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Zone'}], u'requiredparams': [u'id'], u'description': u'Deletes a Zone.'}, u'remoteaccessvpn': {u'name': u'deleteRemoteAccessVpn', u'related': [], u'isasync': True, u'params': [{u'name': u'publicipid', u'required': True, u'related': [u'associateIpAddress'], u'length': 255, u'type': u'uuid', u'description': u'public ip address id of the vpn server'}], u'requiredparams': [u'publicipid'], u'description': u'Destroys a l2tp/ipsec remote access vpn'}, u'storagenetworkiprange': {u'name': u'deleteStorageNetworkIpRange', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listStorageNetworkIpRange', u'createStorageNetworkIpRange', u'updateStorageNetworkIpRange'], u'length': 255, u'type': u'uuid', u'description': u'the uuid of the storage network ip range'}], u'requiredparams': [u'id'], u'description': u'Deletes a storage network IP Range.'}, u'bigswitchvnsdevice': {u'name': u'deleteBigSwitchVnsDevice', u'related': [], u'isasync': True, u'params': [{u'name': u'vnsdeviceid', u'required': True, u'related': [], u'length': 255, u'type': u'long', u'description': u'BigSwitch device ID'}], u'requiredparams': [u'vnsdeviceid'], u'description': u' delete a bigswitch vns device'}, u'projectinvitation': {u'name': u'deleteProjectInvitation', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listProjectInvitations'], u'length': 255, u'type': u'uuid', u'description': u'id of the invitation'}], u'requiredparams': [u'id'], u'description': u'Accepts or declines project invitation'}, u'autoscalepolicy': {u'name': u'deleteAutoScalePolicy', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateAutoScalePolicy'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale policy'}], u'requiredparams': [u'id'], u'description': u'Deletes a autoscale policy.'}, u'niciranvpdevice': {u'name': u'deleteNiciraNvpDevice', u'related': [], u'isasync': True, u'params': [{u'name': u'nvpdeviceid', u'required': True, u'related': [u'addNiciraNvpDevice', u'listNiciraNvpDevices'], u'length': 255, u'type': u'uuid', u'description': u'Nicira device ID'}], u'requiredparams': [u'nvpdeviceid'], u'description': u' delete a nicira nvp device'}, u'serviceoffering': {u'name': u'deleteServiceOffering', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'updateHypervisorCapabilities', u'listServiceOfferings'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the service offering'}], u'requiredparams': [u'id'], u'description': u'Deletes a service offering.'}, u'condition': {u'name': u'deleteCondition', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the condition.'}], u'requiredparams': [u'id'], u'description': u'Removes a condition'}, u'storagepool': {u'name': u'deleteStoragePool', u'related': [], u'isasync': False, u'params': [{u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force destroy storage pool (force expunge volumes in Destroyed state as a part of pool removal)'}, {u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'Storage pool id'}], u'requiredparams': [u'id'], u'description': u'Deletes a storage pool.'}, u'vpngateway': {u'name': u'deleteVpnGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createVpnGateway'], u'length': 255, u'type': u'uuid', u'description': u'id of customer gateway'}], u'requiredparams': [u'id'], u'description': u'Delete site to site vpn gateway'}, u'snapshot': {u'name': u'deleteSnapshot', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createSnapshot', u'listSnapshots'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the snapshot'}], u'requiredparams': [u'id'], u'description': u'Deletes a snapshot of a disk volume.'}, u'autoscalevmgroup': {u'name': u'deleteAutoScaleVmGroup', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listAutoScaleVmGroups', u'createAutoScaleVmGroup', u'disableAutoScaleVmGroup', u'enableAutoScaleVmGroup', u'updateAutoScaleVmGroup'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale group'}], u'requiredparams': [u'id'], u'description': u'Deletes a autoscale vm group.'}, u'trafficmonitor': {u'name': u'deleteTrafficMonitor', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'Id of the Traffic Monitor Host.'}], u'requiredparams': [u'id'], u'description': u'Deletes an traffic monitor host.'}, u'networkacl': {u'name': u'deleteNetworkACL', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network ACL'}], u'requiredparams': [u'id'], u'description': u'Deletes a Network ACL'}, u'template': {u'name': u'deleteTemplate', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the template'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of zone of the template'}], u'requiredparams': [u'id'], u'description': u'Deletes a template from the system. All virtual machines using the deleted template will not be affected.'}, u'tags': {u'name': u'deleteTags', u'related': [], u'isasync': True, u'params': [{u'name': u'resourceids', u'required': True, u'related': [], u'length': 255, u'type': u'list', u'description': u'Delete tags for resource id(s)'}, {u'name': u'tags', u'required': False, u'related': [], u'length': 255, u'type': u'map', u'description': u'Delete tags matching key/value pairs'}, {u'name': u'resourcetype', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Delete tag by resource type'}], u'requiredparams': [u'resourceids', u'resourcetype'], u'description': u'Deleting resource tag(s)'}, u'snapshotpolicies': {u'name': u'deleteSnapshotPolicies', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the Id of the snapshot policy'}, {u'name': u'ids', u'required': False, u'related': [], u'length': 255, u'type': u'list', u'description': u'list of snapshots policy IDs separated by comma'}], u'requiredparams': [], u'description': u'Deletes snapshot policies for the account.'}, u'privategateway': {u'name': u'deletePrivateGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createPrivateGateway', u'listPrivateGateways'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the private gateway'}], u'requiredparams': [u'id'], u'description': u'Deletes a Private gateway'}, u'traffictype': {u'name': u'deleteTrafficType', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'addTrafficType', u'updateTrafficType'], u'length': 255, u'type': u'uuid', u'description': u'traffic type id'}], u'requiredparams': [u'id'], u'description': u'Deletes traffic type of a physical network'}, u'host': {u'name': u'deleteHost', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the host ID'}, {u'name': u'forcedestroylocalstorage', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force destroy local storage on this host. All VMs created on this local storage will be destroyed'}, {u'name': u'forced', u'required': False, u'related': [], u'length': 255, u'type': u'boolean', u'description': u'Force delete the host. All HA enabled vms running on the host will be put to HA; HA disabled ones will be stopped'}], u'requiredparams': [u'id'], u'description': u'Deletes a host.'}, u'staticroute': {u'name': u'deleteStaticRoute', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createStaticRoute', u'listStaticRoutes'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the static route'}], u'requiredparams': [u'id'], u'description': u'Deletes a static route'}, u'vpc': {u'name': u'deleteVPC', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'restartVPC'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the VPC'}], u'requiredparams': [u'id'], u'description': u'Deletes a VPC'}, u'srxfirewall': {u'name': u'deleteSrxFirewall', u'related': [], u'isasync': True, u'params': [{u'name': u'fwdeviceid', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'srx firewall device ID'}], u'requiredparams': [u'fwdeviceid'], u'description': u' delete a SRX firewall device'}, u'externalfirewall': {u'name': u'deleteExternalFirewall', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listHosts'], u'length': 255, u'type': u'uuid', u'description': u'Id of the external firewall appliance.'}], u'requiredparams': [u'id'], u'description': u'Deletes an external firewall appliance.'}, u'pool': {u'name': u'deletePool', u'related': [], u'isasync': False, u'params': [{u'name': u'poolname', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'pool name.'}], u'requiredparams': [u'poolname'], u'description': u'Delete a pool'}, u'autoscalevmprofile': {u'name': u'deleteAutoScaleVmProfile', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listAutoScaleVmProfiles'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the autoscale profile'}], u'requiredparams': [u'id'], u'description': u'Deletes a autoscale vm profile.'}, u'volume': {u'name': u'deleteVolume', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'detachVolume', u'resizeVolume', u'uploadVolume', u'createVolume'], u'length': 255, u'type': u'uuid', u'description': u'The ID of the disk volume'}], u'requiredparams': [u'id'], u'description': u'Deletes a detached disk volume.'}, u'account': {u'name': u'deleteAccount', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'markDefaultZoneForAccount', u'updateAccount', u'listAccounts', u'lockAccount', u'disableAccount'], u'length': 255, u'type': u'uuid', u'description': u'Account id'}], u'requiredparams': [u'id'], u'description': u'Deletes a account, and all users associated with this account'}, u'cisconexusvsm': {u'name': u'deleteCiscoNexusVSM', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'disableCiscoNexusVSM', u'listCiscoNexusVSMs', u'enableCiscoNexusVSM'], u'length': 255, u'type': u'uuid', u'description': u'Id of the Cisco Nexus 1000v VSM device to be deleted'}], u'requiredparams': [u'id'], u'description': u' delete a Cisco Nexus VSM device'}, u'netscalerloadbalancer': {u'name': u'deleteNetscalerLoadBalancer', u'related': [], u'isasync': True, u'params': [{u'name': u'lbdeviceid', u'required': True, u'related': [u'listNetscalerLoadBalancers'], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}], u'requiredparams': [u'lbdeviceid'], u'description': u' delete a netscaler load balancer device'}, u'networkoffering': {u'name': u'deleteNetworkOffering', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'createNetworkOffering', u'updateNetworkOffering'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network offering'}], u'requiredparams': [u'id'], u'description': u'Deletes a network offering.'}, u'vpncustomergateway': {u'name': u'deleteVpnCustomerGateway', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'id of customer gateway'}], u'requiredparams': [u'id'], u'description': u'Delete site to site vpn customer gateway'}, u'counter': {u'name': u'deleteCounter', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the counter'}], u'requiredparams': [u'id'], u'description': u'Deletes a counter'}, u'physicalnetwork': {u'name': u'deletePhysicalNetwork', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the Physical network'}], u'requiredparams': [u'id'], u'description': u'Deletes a Physical Network.'}, u'project': {u'name': u'deleteProject', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'createProject', u'listProjectAccounts', u'activateProject'], u'length': 255, u'type': u'uuid', u'description': u'id of the project to be deleted'}], u'requiredparams': [u'id'], u'description': u'Deletes a project'}, u'vlaniprange': {u'name': u'deleteVlanIpRange', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'listVlanIpRanges'], u'length': 255, u'type': u'uuid', u'description': u'the id of the VLAN IP range'}], u'requiredparams': [u'id'], u'description': u'Creates a VLAN IP range.'}, u'f5loadbalancer': {u'name': u'deleteF5LoadBalancer', u'related': [], u'isasync': True, u'params': [{u'name': u'lbdeviceid', u'required': True, u'related': [u'configureF5LoadBalancer'], u'length': 255, u'type': u'uuid', u'description': u'netscaler load balancer device ID'}], u'requiredparams': [u'lbdeviceid'], u'description': u' delete a F5 load balancer device'}, u'iso': {u'name': u'deleteIso', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'listIsos'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the ISO file'}, {u'name': u'zoneid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the ID of the zone of the ISO file. If not specified, the ISO will be deleted from all the zones'}], u'requiredparams': [u'id'], u'description': u'Deletes an ISO file.'}, u'egressfirewallrule': {u'name': u'deleteEgressFirewallRule', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'updatePortForwardingRule', u'listIpForwardingRules', u'createIpForwardingRule', u'listPortForwardingRules', u'createPortForwardingRule'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the firewall rule'}], u'requiredparams': [u'id'], u'description': u'Deletes an ggress firewall rule'}, u'networkserviceprovider': {u'name': u'deleteNetworkServiceProvider', u'related': [], u'isasync': True, u'params': [{u'name': u'id', u'required': True, u'related': [u'addNetworkServiceProvider', u'listTrafficTypes', u'updateNetworkServiceProvider'], u'length': 255, u'type': u'uuid', u'description': u'the ID of the network service provider'}], u'requiredparams': [u'id'], u'description': u'Deletes a Network Service Provider.'}, u'sshkeypair': {u'name': u'deleteSSHKeyPair', u'related': [], u'isasync': False, u'params': [{u'name': u'projectid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the project associated with keypair'}, {u'name': u'domainid', u'required': False, u'related': [], u'length': 255, u'type': u'uuid', u'description': u'the domain ID associated with the keypair'}, {u'name': u'name', u'required': True, u'related': [], u'length': 255, u'type': u'string', u'description': u'Name of the keypair'}, {u'name': u'account', u'required': False, u'related': [], u'length': 255, u'type': u'string', u'description': u'the account associated with the keypair. Must be used with the domainId parameter.'}], u'requiredparams': [u'name'], u'description': u'Deletes a keypair by name'}, u'user': {u'name': u'deleteUser', u'related': [], u'isasync': False, u'params': [{u'name': u'id', u'required': True, u'related': [u'lockUser', u'listUsers'], u'length': 255, u'type': u'uuid', u'description': u'id of the user to be deleted'}], u'requiredparams': [u'id'], u'description': u'Deletes a user for an account'}}}
diff --git a/tools/pom.xml b/tools/pom.xml
index ffa363d..00f055a 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/tools/utils/cloud-image-downloader.sh b/tools/utils/cloud-image-downloader.sh
new file mode 100755
index 0000000..90f2349
--- /dev/null
+++ b/tools/utils/cloud-image-downloader.sh
@@ -0,0 +1,259 @@
+#!/usr/bin/env bash
+# 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.
+
+#-------------------------------------------------------------------------------
+# Configuration
+#-------------------------------------------------------------------------------
+# This section contains the variables you might want to change.
+
+# The temporary directory where files will be downloaded.
+# It's a good practice to create a unique temporary directory for each script run.
+TEMP_DIR=$(mktemp -d)
+
+# The BASE destination directory for the downloaded image files.
+# Subdirectories for each distro will be created inside this one.
+# Make sure this directory exists before running the script.
+# Must be executed by the cloudstack user on machine hosting the public download site.
+# It will be publicly available at https://download.cloudstack.org/templates/cloud-images/
+DEST_DIR="${HOME}/repository/templates/cloud-images"
+
+# The directory where log files will be stored.
+# Make sure this directory exists.
+LOG_DIR="${HOME}/log/cloud-image-downloader"
+LOG_FILE="${LOG_DIR}/cloud-image-downloader_$(date +%Y%m%d_%H%M%S).log"
+LOG_RETENTION_DAYS=30
+
+LOGGER_TAG="cloud-image-downloader"
+LOGGER_FACILITY="user"
+LOGGER_AVAILABLE=false
+
+log_message() {
+ local priority=$1
+ shift
+ local message="$*"
+ local timestamp=$(date +'%Y-%m-%d %H:%M:%S')
+
+ # Log to file
+ echo "${timestamp} [${priority}] ${message}" | tee -a "${LOG_FILE}"
+
+ # Log to syslog using logger utility
+ if [ "${LOGGER_AVAILABLE}" = true ]; then
+ logger -t "${LOGGER_TAG}" -p "${LOGGER_FACILITY}.${priority}" -- "${message}"
+ fi
+}
+
+log_info() {
+ log_message "info" "$@"
+}
+
+log_warn() {
+ log_message "warning" "$@"
+}
+
+log_error() {
+ log_message "err" "$@"
+}
+
+cleanup_old_logs() {
+ log_info "Cleaning up log files older than ${LOG_RETENTION_DAYS} days..."
+
+ if [ ! -d "$LOG_DIR" ]; then
+ log_warn "Log directory does not exist: $LOG_DIR"
+ return
+ fi
+
+ local deleted_count=0
+
+ # Find and delete log files older than retention period
+ while IFS= read -r -d '' log_file; do
+ rm -f "$log_file"
+ deleted_count=$((deleted_count + 1))
+ done < <(find "$LOG_DIR" -name "*.log" -type f -mtime +${LOG_RETENTION_DAYS} -print0 2>/dev/null)
+
+ if [ $deleted_count -gt 0 ]; then
+ log_info "Deleted $deleted_count old log file(s)"
+ else
+ log_info "No old log files to delete"
+ fi
+}
+
+#-------------------------------------------------------------------------------
+# Image Definitions
+#-------------------------------------------------------------------------------
+# To add a new image, you must add an entry to BOTH arrays below.
+
+# 1. Add the destination filename and the download URL.
+declare -A IMAGE_URLS=(
+ ["Rocky-9-GenericCloud.latest.x86_64.qcow2"]="https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2"
+ ["Rocky-9-GenericCloud.latest.aarch64.qcow2"]="https://dl.rockylinux.org/pub/rocky/9/images/aarch64/Rocky-9-GenericCloud.latest.aarch64.qcow2"
+ ["Rocky-8-GenericCloud.latest.x86_64.qcow2"]="https://dl.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud.latest.x86_64.qcow2"
+ ["Rocky-8-GenericCloud.latest.aarch64.qcow2"]="https://dl.rockylinux.org/pub/rocky/8/images/aarch64/Rocky-8-GenericCloud.latest.aarch64.qcow2"
+ ["openSUSE-Leap-15.5-Minimal-VM.x86_64-Cloud.qcow2"]="https://download.opensuse.org/distribution/leap/15.5/appliances/openSUSE-Leap-15.5-Minimal-VM.x86_64-Cloud.qcow2"
+ ["openSUSE-Leap-15.5-Minimal-VM.aarch64-Cloud.qcow2"]="https://download.opensuse.org/distribution/leap/15.5/appliances/openSUSE-Leap-15.5-Minimal-VM.aarch64-Cloud.qcow2"
+ ["debian-12-genericcloud-amd64.qcow2"]="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2"
+ ["debian-12-genericcloud-arm64.qcow2"]="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-arm64.qcow2"
+ ["ubuntu-24.04-server-cloudimg-amd64.img"]="https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
+ ["ubuntu-24.04-server-cloudimg-arm64.img"]="https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-arm64.img"
+ ["ubuntu-22.04-server-cloudimg-amd64.img"]="https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img"
+ ["ubuntu-22.04-server-cloudimg-arm64.img"]="https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"
+ ["ubuntu-20.04-server-cloudimg-amd64.img"]="https://cloud-images.ubuntu.com/releases/20.04/release/ubuntu-20.04-server-cloudimg-amd64.img"
+ ["ubuntu-20.04-server-cloudimg-arm64.img"]="https://cloud-images.ubuntu.com/releases/20.04/release/ubuntu-20.04-server-cloudimg-arm64.img"
+ ["OL9U5_x86_64-kvm-b259.qcow2"]="https://yum.oracle.com/templates/OracleLinux/OL9/u5/x86_64/OL9U5_x86_64-kvm-b259.qcow2"
+ ["OL9U5_aarch64-kvm-b126.qcow2"]="https://yum.oracle.com/templates/OracleLinux/OL9/u5/aarch64/OL9U5_aarch64-kvm-b126.qcow2"
+ ["OL8U10_x86_64-kvm-b258.qcow2"]="https://yum.oracle.com/templates/OracleLinux/OL8/u10/x86_64/OL8U10_x86_64-kvm-b258.qcow2"
+ ["OL8U10_aarch64-kvm-b122.qcow2"]="https://yum.oracle.com/templates/OracleLinux/OL8/u10/aarch64/OL8U10_aarch64-kvm-b122.qcow2"
+)
+
+# 2. Add the destination filename and its corresponding distribution subdirectory name.
+declare -A IMAGE_DISTROS=(
+ ["Rocky-9-GenericCloud.latest.x86_64.qcow2"]="rockylinux"
+ ["Rocky-9-GenericCloud.latest.aarch64.qcow2"]="rockylinux"
+ ["Rocky-8-GenericCloud.latest.x86_64.qcow2"]="rockylinux"
+ ["Rocky-8-GenericCloud.latest.aarch64.qcow2"]="rockylinux"
+ ["openSUSE-Leap-15.5-Minimal-VM.x86_64-Cloud.qcow2"]="opensuse"
+ ["openSUSE-Leap-15.5-Minimal-VM.aarch64-Cloud.qcow2"]="opensuse"
+ ["debian-12-genericcloud-amd64.qcow2"]="debian"
+ ["debian-12-genericcloud-arm64.qcow2"]="debian"
+ ["ubuntu-24.04-server-cloudimg-amd64.img"]="ubuntu"
+ ["ubuntu-24.04-server-cloudimg-arm64.img"]="ubuntu"
+ ["ubuntu-22.04-server-cloudimg-amd64.img"]="ubuntu"
+ ["ubuntu-22.04-server-cloudimg-arm64.img"]="ubuntu"
+ ["ubuntu-20.04-server-cloudimg-amd64.img"]="ubuntu"
+ ["ubuntu-20.04-server-cloudimg-arm64.img"]="ubuntu"
+ ["OL9U5_x86_64-kvm-b259.qcow2"]="oraclelinux"
+ ["OL9U5_aarch64-kvm-b126.qcow2"]="oraclelinux"
+ ["OL8U10_x86_64-kvm-b258.qcow2"]="oraclelinux"
+ ["OL8U10_aarch64-kvm-b122.qcow2"]="oraclelinux"
+)
+
+#-------------------------------------------------------------------------------
+# Cleanup Handler
+#-------------------------------------------------------------------------------
+
+cleanup_on_exit() {
+ local exit_code=$?
+ if [ -d "$TEMP_DIR" ]; then
+ rm -rf "$TEMP_DIR"
+ log_info "Temporary directory $TEMP_DIR removed."
+ fi
+
+ if [ $exit_code -ne 0 ]; then
+ log_error "Script exited with error code: $exit_code"
+ fi
+}
+
+trap cleanup_on_exit EXIT INT TERM
+
+#-------------------------------------------------------------------------------
+# Main Script Logic
+#-------------------------------------------------------------------------------
+
+if command -v logger &> /dev/null; then
+ LOGGER_AVAILABLE=true
+fi
+
+# Ensure base destination and log directories exist
+mkdir -p "$DEST_DIR"
+mkdir -p "$LOG_DIR"
+
+# Clean up old logs first
+cleanup_old_logs
+
+log_info "Starting image download process."
+log_info "Temporary directory: $TEMP_DIR"
+log_info "Base destination directory: $DEST_DIR"
+log_info "Log file: $LOG_FILE"
+
+# Inform about logger status
+if [ "${LOGGER_AVAILABLE}" = true ]; then
+ log_info "Syslog logging enabled (tag: ${LOGGER_TAG})"
+else
+ log_warn "Syslog logging disabled - logger utility not found"
+fi
+
+# Loop through the image URLs
+for filename in "${!IMAGE_URLS[@]}"; do
+ url="${IMAGE_URLS[$filename]}"
+ distro="${IMAGE_DISTROS[$filename]}"
+
+ # Check if a distro is defined for the file
+ if [ -z "$distro" ]; then
+ log_error "No distribution directory defined for $filename. Skipping."
+ continue
+ fi
+
+ distro_dest_dir="${DEST_DIR}/${distro}"
+ temp_filepath="${TEMP_DIR}/${filename}"
+ dest_filepath="${distro_dest_dir}/${filename}"
+
+ log_info "--------------------------------------------------"
+ log_info "Starting download for: $filename"
+ log_info "URL: $url"
+
+ # Download the file to the temporary directory
+ wget --progress=bar:force:noscroll -O "$temp_filepath" "$url"
+ download_status=$?
+
+ if [ $download_status -ne 0 ]; then
+ # Handle download failure
+ log_error "Failed to download $filename from $url. wget exit code: $download_status"
+ else
+ # Handle download success
+ log_info "Successfully downloaded $filename to temporary location."
+
+ # Ensure the specific distro directory exists
+ log_info "Ensuring destination directory exists: $distro_dest_dir"
+ mkdir -p "$distro_dest_dir"
+
+ # Move the file to the destination directory, replacing any existing file
+ log_info "Moving $filename to $dest_filepath"
+ mv -f "$temp_filepath" "$dest_filepath"
+ move_status=$?
+
+ if [ $move_status -ne 0 ]; then
+ log_error "Failed to move $filename to $dest_filepath. mv exit code: $move_status"
+ else
+ log_info "Successfully moved $filename."
+ fi
+ fi
+done
+
+log_info "Generate checksum"
+# Create md5 checksum
+checksum_file="md5sum.txt"
+sha512_checksum_file="sha512sum.txt"
+
+cd "$DEST_DIR"
+find . -type f ! -iname '*.txt' -exec md5sum {} \; > "$checksum_file"
+checksum_status=$?
+if [ $checksum_status -ne 0 ]; then
+ log_error "Failed to create md5 checksum. md5sum exit code: $checksum_status"
+else
+ log_info "Successfully created checksum file: $checksum_file"
+fi
+
+find . -type f ! -iname '*.txt' -exec sha512sum {} \; > "$sha512_checksum_file"
+sha512_checksum_status=$?
+if [ $sha512_checksum_status -ne 0 ]; then
+ log_error "Failed to create sha512 checksum. sha512sum exit code: $sha512_checksum_status"
+else
+ log_info "Successfully created checksum file: $sha512_checksum_file"
+fi
+
+log_info "--------------------------------------------------"
+log_info "Image download process finished."
diff --git a/ui/public/locales/de_DE.json b/ui/public/locales/de_DE.json
index d99ba41..2fee920 100644
--- a/ui/public/locales/de_DE.json
+++ b/ui/public/locales/de_DE.json
@@ -2078,7 +2078,7 @@
"message.success.create.internallb": "Interne LB erfolgreich erstellt",
"message.success.create.isolated.network": "Isoliertes Netzwerk erfolgreich erstellt",
"message.success.create.keypair": "SSH-Schlüsselpaar erfolgreich erstellt",
-"message.success.create.kubernetes.cluter": "Kubernetes Cluster erfolgreich erstellt",
+"message.success.create.kubernetes.cluster": "Kubernetes Cluster erfolgreich erstellt",
"message.success.create.l2.network": "L2 Netzwerk erfolgreich erstellt",
"message.success.create.volume": "Speicher erfolgreich erstellt",
"message.success.delete": "Erfolgreich gelöscht",
diff --git a/ui/public/locales/el_GR.json b/ui/public/locales/el_GR.json
index 3c0cd6a..bb90661 100644
--- a/ui/public/locales/el_GR.json
+++ b/ui/public/locales/el_GR.json
@@ -2570,7 +2570,7 @@
"message.success.create.internallb": "Η εσωτερική lb ολοκληρώθηκε με επιτυχία",
"message.success.create.isolated.network": "Δημιουργήθηκε με επιτυχία απομονωμένο δίκτυο",
"message.success.create.keypair": "Δημιουργήθηκε με επιτυχία ζεύγος κλειδιών SSH",
-"message.success.create.kubernetes.cluter": "Δημιουργήθηκε με επιτυχία την ομάδαΚυβερνητών",
+"message.success.create.kubernetes.cluster": "Δημιουργήθηκε με επιτυχία την ομάδαΚυβερνητών",
"message.success.create.l2.network": "Δημιουργήθηκε με επιτυχία το δίκτυο L2",
"message.success.create.snapshot.from.vmsnapshot": "Επιτυχής δημιουργία στιγμιότυπου από στιγμιότυπο εικονικής μηχανής",
"message.success.create.user": "Ο χρήστης δημιουργήθηκε με επιτυχία",
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 0a9539a..2054699 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -74,7 +74,7 @@
"label.action.cancel.maintenance.mode": "Cancel maintenance mode",
"label.action.change.password": "Change password",
"label.action.clear.webhook.deliveries": "Clear deliveries",
-"label.action.delete.webhook.deliveries": "Delete deliveries",
+"label.action.clear.webhook.filters": "Clear filters",
"label.action.change.primary.storage.scope": "Change Primary Storage scope",
"label.action.configure.stickiness": "Stickiness",
"label.action.configure.storage.access.group": "Update storage access group",
@@ -118,6 +118,8 @@
"label.action.delete.user": "Delete User",
"label.action.delete.vgpu.profile": "Delete vGPU profile",
"label.action.delete.volume": "Delete Volume",
+"label.action.delete.webhook.deliveries": "Delete Deliveries",
+"label.action.delete.webhook.filters": "Delete Filters",
"label.action.delete.zone": "Delete Zone",
"label.action.destroy.instance": "Destroy Instance",
"label.action.destroy.systemvm": "Destroy System VM",
@@ -292,8 +294,10 @@
"label.add.isolated.network": "Add Isolated Network",
"label.add.kubernetes.cluster": "Add Kubernetes Cluster",
"label.add.acl.name": "ACL name",
+"label.add.latest.kubernetes.iso": "Add latest Kubernetes ISO",
"label.add.ldap.account": "Add LDAP Account",
"label.add.logical.router": "Add Logical Router to this Network",
+"label.add.minimum.required.compute.offering": "Add minimum required Compute Offering",
"label.add.more": "Add more",
"label.add.nodes": "Add Nodes to Kubernetes Cluster",
"label.add.netscaler.device": "Add Netscaler Device",
@@ -358,6 +362,7 @@
"label.add.vpn.customer.gateway": "Add VPN Customer Gateway",
"label.add.vpn.gateway": "Add VPN Gateway",
"label.add.vpn.user": "Add VPN User",
+"label.add.webhook.filter": "Add Webhook Filter",
"label.add.zone": "Add Zone",
"label.adding": "Adding",
"label.adding.user": "Adding User...",
@@ -639,6 +644,7 @@
"label.consoleproxy": "Console proxy",
"label.console.proxy": "Console proxy",
"label.console.proxy.vm": "Console proxy VM",
+"label.contains": "Contains",
"label.continue": "Continue",
"label.continue.install": "Continue with installation",
"label.controlnodes": "Control nodes",
@@ -811,11 +817,12 @@
"label.delete.tungsten.service.group": "Delete Service Group",
"label.delete.volumes": "Data volumes to be deleted",
"label.delete.vpn.connection": "Delete VPN connection",
-"label.delete.vpn.customer.gateway": "Delete VPN customer gateway",
+"label.delete.vpn.customer.gateway": "Delete VPN Customer Gateway",
"label.delete.vpn.gateway": "Delete VPN gateway",
"label.delete.vpn.user": "Delete VPN User",
"label.delete.webhook": "Delete Webhook",
"label.delete.webhook.delivery": "Delete Webhook Delivery",
+"label.delete.webhook.filter": "Delete Webhook Filter",
"label.deleteconfirm": "Please confirm that you would like to delete this",
"label.deleting": "Deleting",
"label.deleting.failed": "Deleting failed",
@@ -1045,8 +1052,10 @@
"label.event.timeline": "Event timeline",
"label.events": "Events",
"label.every": "Every",
+"label.exact": "Exact",
"label.example": "Example",
"label.example.plugin": "ExamplePlugin",
+"label.exclude": "Exclude",
"label.existing": "Existing",
"label.execute": "Execute",
"label.expunge": "Expunge",
@@ -1085,6 +1094,7 @@
"label.shared.filesystems": "Shared FileSystems",
"label.filesystem": "Filesystem",
"label.filter": "Filter",
+"label.filters": "Filters",
"label.filter.annotations.all": "All comments",
"label.filter.annotations.self": "Created by me",
"label.filterby": "Filter by",
@@ -1099,6 +1109,7 @@
"label.firstname": "First name",
"label.firstname.lower": "firstname",
"label.fix.errors": "Fix errors",
+"label.fix.global.setting": "Fix Global Setting",
"label.fixed": "Fixed Offering",
"label.for": "for",
"label.forcks": "For CKS",
@@ -1132,6 +1143,9 @@
"label.globo.dns.configuration": "GloboDNS configuration",
"label.glustervolume": "Volume",
"label.go.back": "Go back",
+"label.go.to.compute.offerings": "Go to Compute Offerings",
+"label.go.to.global.settings": "Go to Global Settings",
+"label.go.to.kubernetes.isos": "Go to Kubernetes ISOs",
"label.gpu": "GPU",
"label.gpucardid": "GPU Card",
"label.gpucardname": "GPU Card",
@@ -1263,6 +1277,7 @@
"label.import.volume": "Import Volume",
"label.inactive": "Inactive",
"label.inbuilt": "Inbuilt",
+"label.include": "Include",
"label.in.progress": "in progress",
"label.in.progress.for": "in progress for",
"label.info": "Info",
@@ -1271,8 +1286,8 @@
"label.ingest.instance": "Ingest Instance",
"label.ingress": "Ingress",
"label.ingress.rule": "Ingress Rule",
-"label.initial": "Inital",
-"label.initialized": "Initalized",
+"label.initial": "Initial",
+"label.initialized": "Initialized",
"label.insideportprofile": "Inside port profile",
"label.installwizard.addzoneintro.title": "Let's add a Zone",
"label.installwizard.subtitle": "This guide will aid you in setting up your CloudStack™ installation",
@@ -1462,6 +1477,7 @@
"label.lbruleid": "Load balancer ID",
"label.lbtype": "Load balancer type",
"label.ldap": "LDAP",
+"label.ldapdomain": "LDAP Domain",
"label.ldap.configuration": "LDAP Configuration",
"label.ldap.group.name": "LDAP Group",
"label.level": "Level",
@@ -1529,6 +1545,7 @@
"label.management.server.peers": "Peers",
"label.managementservers": "Number of management servers",
"label.matchall": "Match all",
+"label.matchtype": "Match Type",
"label.max": "Max.",
"label.max.primary.storage": "Max. primary (GiB)",
"label.max.secondary.storage": "Max. secondary (GiB)",
@@ -1970,7 +1987,7 @@
"label.publicnetwork": "Public Network",
"label.publicport": "Public port",
"label.purgeresources": "Purge Resources",
-"label.purge.usage.records.success": "Successfuly purged usage records",
+"label.purge.usage.records.success": "Successfully purged usage records",
"label.purge.usage.records.error": "Failed while purging usage records",
"label.purpose": "Purpose",
"label.qostype": "QoS type",
@@ -2435,6 +2452,7 @@
"label.storagepool.tooltip": "Destination Storage Pool. Volume should be located in this Storage Pool",
"label.storagetags": "Storage tags",
"label.storagetype": "Storage type",
+"label.storageip": "Storage IP address",
"label.strict": "Strict",
"label.subdomainaccess": "Subdomain access",
"label.submit": "Submit",
@@ -2445,6 +2463,7 @@
"label.success.migrations": "Successful migrations",
"label.success.set": "Successfully set",
"label.success.updated": "Successfully updated",
+"label.suffix": "Suffix",
"label.suitability": "Suitability",
"label.suitable": "Suitable",
"label.summary": "Summary",
@@ -2597,6 +2616,7 @@
"label.undefined": "Undefined",
"label.unit": "Usage unit",
"label.unknown": "Unknown",
+"label.unlink.domain.from.ldap": "Unlink the Domain from LDAP",
"label.unlimited": "Unlimited",
"label.unmanaged": "Unmanaged",
"label.unmanage.instance": "Unmanage Instance",
@@ -2625,6 +2645,7 @@
"label.update.to": "updated to",
"label.update.traffic.label": "Update traffic labels",
"label.update.vmware.datacenter": "Update VMWare datacenter",
+"label.update.vpn.customer.gateway": "Update VPN Customer Gateway",
"label.update.webhook": "Update Webhook",
"label.updating": "Updating",
"label.upgrade.router.newer.template": "Upgrade router to use newer Template",
@@ -2635,7 +2656,7 @@
"label.upload.icon": "Upload icon",
"label.upload.iso.from.local": "Upload ISO from local",
"label.upload.resource.icon": "Upload icon",
-"label.upload.ssl.certificate": "Upload SSL cerficicate",
+"label.upload.ssl.certificate": "Upload SSL certificate",
"label.upload.template.from.local": "Upload Template from local",
"label.upload.volume": "Upload volume",
"label.upload.volume.from.local": "Upload Volume from local",
@@ -3050,12 +3071,17 @@
"message.add.ip.v6.firewall.rule.failed": "Failed to add IPv6 firewall rule",
"message.add.ip.v6.firewall.rule.processing": "Adding IPv6 firewall rule...",
"message.add.ip.v6.firewall.rule.success": "Added IPv6 firewall rule",
+"message.advisory.cks.endpoint.url.not.configured": "Endpoint URL which will be used by Kubernetes clusters is not configured correctly",
+"message.advisory.cks.min.offering": "No suitable Compute Offering found for Kubernetes cluster nodes with minimum required resources (2 vCPU, 2 GB RAM)",
+"message.advisory.cks.version.check": "No Kubernetes version found that can be used to deploy a Kubernetes cluster",
"message.redeliver.webhook.delivery": "Redeliver this Webhook delivery",
"message.remove.ip.v6.firewall.rule.failed": "Failed to remove IPv6 firewall rule",
"message.remove.ip.v6.firewall.rule.processing": "Removing IPv6 firewall rule...",
"message.remove.ip.v6.firewall.rule.success": "Removed IPv6 firewall rule",
"message.remove.sslcert.failed": "Failed to remove SSL certificate from load balancer",
"message.remove.sslcert.processing": "Removing SSL certificate from load balancer...",
+"message.add.latest.kubernetes.iso.failed": "Failed to add latest Kubernetes ISO",
+"message.add.minimum.required.compute.offering.kubernetes.cluster.failed": "Failed to add minimum required Compute Offering for Kubernetes cluster nodes",
"message.add.netris.controller": "Add Netris Provider",
"message.add.nsx.controller": "Add NSX Provider",
"message.add.network": "Add a new network for Zone: <b><span id=\"zone_name\"></span></b>",
@@ -3091,14 +3117,18 @@
"message.add.volume": "Please fill in the following data to add a new volume.",
"message.add.vpn.connection.failed": "Adding VPN connection failed",
"message.add.vpn.connection.processing": "Adding VPN Connection...",
-"message.add.vpn.customer.gateway": "Adding VPN customer gateway",
-"message.add.vpn.customer.gateway.processing": "Creation of VPN customer gateway is in progress",
+"message.add.vpn.customer.gateway": "Adding VPN Customer Gateway",
+"message.add.vpn.customer.gateway.processing": "Creation of VPN Customer Gateway is in progress",
"message.add.vpn.gateway": "Please confirm that you want to add a VPN Gateway.",
"message.add.vpn.gateway.failed": "Adding VPN gateway failed",
"message.add.vpn.gateway.processing": "Adding VPN gateway...",
+"message.added.latest.kubernetes.iso": "Latest Kubernetes ISO added successfully",
+"message.added.minimum.required.compute.offering.kubernetes.cluster": "Minimum required Compute Offering for Kubernetes cluster nodes added successfully",
"message.added.vpc.offering": "Added VPC offering",
"message.adding.firewall.policy": "Adding Firewall Policy",
"message.adding.host": "Adding host",
+"message.adding.latest.kubernetes.iso": "Adding latest Kubernetes ISO",
+"message.adding.minimum.required.compute.offering.kubernetes.cluster": "Adding minimum required Compute Offering for Kubernetes cluster nodes",
"message.adding.netscaler.device": "Adding Netscaler device",
"message.adding.netscaler.provider": "Adding Netscaler provider",
"message.adding.nodes.to.cluster": "Adding nodes to Kubernetes cluster",
@@ -3240,7 +3270,7 @@
"message.create.volume.failed": "Failed to create Volume.",
"message.create.volume.processing": "Volume creation in progress",
"message.create.vpc.offering": "VPC offering created.",
-"message.create.vpn.customer.gateway.failed": "VPN customer gateway creation failed.",
+"message.create.vpn.customer.gateway.failed": "VPN Customer Gateway creation failed.",
"message.creating.autoscale.vmgroup": "Creating AutoScaling Group",
"message.creating.autoscale.vmprofile": "Creating AutoScale Instance profile",
"message.creating.autoscale.scaledown.conditions": "Creating ScaleDown conditions",
@@ -3291,11 +3321,12 @@
"message.delete.tungsten.tag": "Are you sure you want to remove this Tag from this Policy?",
"message.delete.user": "Please confirm that you would like to delete this User.",
"message.delete.vpn.connection": "Please confirm that you want to delete VPN connection.",
-"message.delete.vpn.customer.gateway": "Please confirm that you want to delete this VPN customer gateway.",
+"message.delete.vpn.customer.gateway": "Please confirm that you want to delete this VPN Customer Gateway.",
"message.delete.vpn.gateway": "Please confirm that you want to delete this VPN Gateway.",
"message.delete.vpn.gateway.failed": "Failed to delete VPN Gateway.",
"message.delete.webhook": "Please confirm that you want to delete this Webhook.",
"message.delete.webhook.delivery": "Please confirm that you want to delete this Webhook delivery.",
+"message.delete.webhook.filter": "Please confirm that you want to delete this Webhook filter.",
"message.deleting.firewall.policy": "Deleting Firewall Policy",
"message.deleting.node": "Deleting Node",
"message.deleting.vm": "Deleting Instance",
@@ -3535,6 +3566,8 @@
"message.failed.to.remove": "Failed to remove",
"message.forgot.password.success": "An email has been sent to your email address with instructions on how to reset your password.",
"message.generate.keys": "Please confirm that you would like to generate new API/Secret keys for this User.",
+"message.global.setting.updated": "Global Setting updated successfully.",
+"message.global.setting.update.failed": "Failed to update Global Setting.",
"message.chart.statistic.info": "The shown charts are self-adjustable, that means, if the value gets close to the limit or overpass it, it will grow to adjust the shown value",
"message.chart.statistic.info.hypervisor.additionals": "The metrics data depend on the hypervisor plugin used for each hypervisor. The behavior can vary across different hypervisors. For instance, with KVM, metrics are real-time statistics provided by libvirt. In contrast, with VMware, the metrics are averaged data for a given time interval controlled by configuration.",
"message.guest.traffic.in.advanced.zone": "Guest Network traffic is communication between end-user Instances. Specify a range of VLAN IDs or VXLAN Network identifiers (VNIs) to carry guest traffic for each physical Network.",
@@ -3833,13 +3866,13 @@
"message.success.add.tungsten.routing.policy": "Successfully added Tungsten-Fabric routing policy",
"message.success.add.vpc": "Successfully added a Virtual Private Cloud",
"message.success.add.vpc.network": "Successfully added a VPC network",
-"message.success.add.vpn.customer.gateway": "Successfully added VPN customer gateway",
+"message.success.add.vpn.customer.gateway": "Successfully added VPN Customer Gateway",
"message.success.add.vpn.gateway": "Successfully added VPN gateway",
+"message.success.add.webhook.filter": "Successfully added Webhook Filter",
"message.success.assign.sslcert": "Successfully assigned SSL certificate",
"message.success.assign.vm": "Successfully assigned Instance",
"message.success.apply.network.policy": "Successfully applied Network Policy",
"message.success.apply.tungsten.tag": "Successfully applied Tag",
-"message.success.asign.vm": "Successfully assigned Instance",
"message.success.assigned.vms": "Successfully assigned Instances",
"message.success.certificate.upload": "Certificate successfully uploaded",
"message.success.change.affinity.group": "Successfully changed affinity groups",
@@ -3848,6 +3881,7 @@
"message.success.change.password": "Successfully changed password for User",
"message.success.change.host.password": "Successfully changed password for host \"{name}\"",
"message.success.clear.webhook.deliveries": "Successfully cleared webhook deliveries",
+"message.success.clear.webhook.filters": "Successfully cleared webhook filters",
"message.success.change.scope": "Successfully changed scope for storage pool",
"message.success.config.backup.schedule": "Successfully configured Instance backup schedule",
"message.success.config.health.monitor": "Successfully Configure Health Monitor",
@@ -3862,7 +3896,7 @@
"message.success.create.internallb": "Successfully created Internal Load Balancer",
"message.success.create.isolated.network": "Successfully created isolated Network",
"message.success.create.keypair": "Successfully created SSH key pair",
-"message.success.create.kubernetes.cluter": "Successfully created Kubernetes Cluster",
+"message.success.create.kubernetes.cluster": "Successfully created Kubernetes Cluster",
"message.success.create.l2.network": "Successfully created L2 Network",
"message.success.create.snapshot.from.vmsnapshot": "Successfully created Snapshot from Instance Snapshot",
"message.success.create.template": "Successfully created Template",
@@ -3938,7 +3972,7 @@
"message.success.unmanage.gpu.devices": "Successfully unmanaged GPU device(s)",
"message.success.unmanage.instance": "Successfully unmanaged Instance",
"message.success.unmanage.volume": "Successfully unmanaged Volume",
-"message.success.unregister.extension": "Successfull unregistered Extension",
+"message.success.unregister.extension": "Successfully unregistered Extension",
"message.success.update.account": "Successfully updated Account",
"message.success.update.bgp.peer": "Successfully updated BGP peer",
"message.success.update.bucket": "Successfully updated bucket",
@@ -3958,6 +3992,7 @@
"message.success.update.network": "Successfully updated Network",
"message.success.update.template": "Successfully updated Template",
"message.success.update.user": "Successfully updated User",
+"message.success.update.vpn.customer.gateway": "Successfully updated VPN Customer Gateway",
"message.success.upgrade.kubernetes": "Successfully upgraded Kubernetes Cluster",
"message.success.upload": "Successfully uploaded",
"message.success.upload.description": "This ISO file has been uploaded. Please check its status in the Templates menu.",
@@ -3985,6 +4020,9 @@
"message.update.condition.failed": "Failed to update condition",
"message.update.condition.processing": "Updating condition...",
"message.update.failed": "Update failed",
+"message.update.vpn.customer.gateway": "Update VPN Customer Gateway",
+"message.update.vpn.customer.gateway.failed": "Updating the VPN Customer Gateway failed",
+"message.update.vpn.customer.gateway.processing": "Updating VPN Customer Gateway...",
"message.test.webhook.delivery": "Test delivery to the Webhook with an optional payload",
"message.two.factor.authorization.failed": "Unable to verify 2FA with provided code, please retry.",
"message.two.fa.auth": "Open the two-factor authentication app on your mobile device to view your authentication code.",
@@ -4072,6 +4110,11 @@
"message.volumes.managed": "Volumes controlled by CloudStack.",
"message.volumes.unmanaged": "Volumes not controlled by CloudStack.",
"message.vpc.restart.required": "Restart is required for VPC(s). Click here to view VPC(s) which require restart.",
+"message.vpn.customer.gateway.contains.excluded.obsolete.parameters": "This VPN Customer Gateway contains cryptographic parameters that are marked as excluded or obsolete by the Administrator. Consider changing them using the Update VPN Customer Gateway form.",
+"message.vpn.customer.gateway.excluded.parameter": " is marked as excluded. Please choose another value.",
+"message.vpn.customer.gateway.obsolete.parameter": " is marked as obsolete/insecure. Please choose another value.",
+"message.vpn.customer.gateway.obsolete.parameter.tooltip": "This parameter value is marked as obsolete/insecure.",
+"message.vr.alert.upon.network.offering.creation.l2": "As virtual routers are not created for L2 Networks, the compute offering will not be used.",
"message.vr.alert.upon.network.offering.creation.others": "As none of the obligatory services for creating a virtual router (VPN, DHCP, DNS, Firewall, LB, UserData, SourceNat, StaticNat, PortForwarding) are enabled, the virtual router will not be created and the compute offering will not be used.",
"message.warn.change.primary.storage.scope": "This feature is tested and supported for the following configurations:<br>KVM - NFS/Ceph - DefaultPrimary<br>VMware - NFS - DefaultPrimary<br>*There might be extra steps involved to make it work for other configurations.",
"message.warn.filetype": "jpg, jpeg, png, bmp and svg are the only supported image formats.",
diff --git a/ui/public/locales/ja_JP.json b/ui/public/locales/ja_JP.json
index 734a0ea..850264f 100644
--- a/ui/public/locales/ja_JP.json
+++ b/ui/public/locales/ja_JP.json
@@ -3328,7 +3328,7 @@
"message.success.create.internallb": "正常に作成された内部LB",
"message.success.create.isolated.network": "正常に作成された隔離ネットワーク",
"message.success.create.keypair": "SSHキーペアが正常に作成されました",
- "message.success.create.kubernetes.cluter": "正常に作成されたKubernetesクラスター",
+ "message.success.create.kubernetes.cluster": "正常に作成されたKubernetesクラスター",
"message.success.create.l2.network": "正常に作成されたL2ネットワーク",
"message.success.create.snapshot.from.vmsnapshot": "VMスナップショットからスナップショットを正常に作成しました",
"message.success.create.user": "正常に作成されたユーザー",
diff --git a/ui/public/locales/ko_KR.json b/ui/public/locales/ko_KR.json
index 1f20c95..a951b85 100644
--- a/ui/public/locales/ko_KR.json
+++ b/ui/public/locales/ko_KR.json
@@ -2196,7 +2196,7 @@
"message.success.create.internallb": "\ub0b4\ubd80 LB\ub97c \uc0dd\uc131\ud588\uc2b5\ub2c8\ub2e4.",
"message.success.create.isolated.network": "isolated \ub124\ud2b8\uc6cc\ud06c\ub97c \uc0dd\uc131\ud588\uc2b5\ub2c8\ub2e4.",
"message.success.create.keypair": "SSH \ud0a4 \uc30d\uc744 \uc0dd\uc131\ud588\uc2b5\ub2c8\ub2e4.",
-"message.success.create.kubernetes.cluter": "\ucfe0\ubc84\ub124\ud14c\uc2a4 \ud074\ub7ec\uc2a4\ud130\ub97c \uc0dd\uc131\ud588\uc2b5\ub2c8\ub2e4.",
+"message.success.create.kubernetes.cluster": "\ucfe0\ubc84\ub124\ud14c\uc2a4 \ud074\ub7ec\uc2a4\ud130\ub97c \uc0dd\uc131\ud588\uc2b5\ub2c8\ub2e4.",
"message.success.create.l2.network": "L2 \ub124\ud2b8\uc6cc\ud06c\ub97c \uc0dd\uc131\ud588\uc2b5\ub2c8\ub2e4.",
"message.success.create.snapshot.from.vmsnapshot": "VM \uc2a4\ub0c5\uc0f7\uc5d0\uc11c \uc2a4\ub0c5\uc0f7\uc744 \uc0dd\uc131\ud588\uc2b5\ub2c8\ub2e4.",
"message.success.create.user": "\uc0ac\uc6a9\uc790\uac00 \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.",
diff --git a/ui/public/locales/pt_BR.json b/ui/public/locales/pt_BR.json
index c82a9e3..59123a5 100644
--- a/ui/public/locales/pt_BR.json
+++ b/ui/public/locales/pt_BR.json
@@ -1592,6 +1592,7 @@
"label.storagepool": "Pool de armazenamento",
"label.storagetags": "Tags de armazenamento",
"label.storagetype": "Tipo de armazenamento",
+"label.storageip": "Endere\u00e7o IP na rede de armazenamento",
"label.strict": "Rigoroso",
"label.subdomainaccess": "acesso ao subdom\u00ednio",
"label.submit": "Enviar",
@@ -2410,7 +2411,7 @@
"message.success.create.internallb": "LB interno criado com sucesso",
"message.success.create.isolated.network": "Rede isolada criada com sucesso",
"message.success.create.keypair": "Par de chaves SSH criado com sucesso",
-"message.success.create.kubernetes.cluter": "Cluster Kubernetes criado com sucesso",
+"message.success.create.kubernetes.cluster": "Cluster Kubernetes criado com sucesso",
"message.success.create.l2.network": "Rede L2 criada com sucesso",
"message.success.create.snapshot.from.vmsnapshot": "Snapshot de volume a partir da snapshot de VM criada com sucesso",
"message.success.create.user": "Usu\u00e1rio criado com sucesso",
diff --git a/ui/public/locales/te.json b/ui/public/locales/te.json
index 5f89bbf..ed72626 100644
--- a/ui/public/locales/te.json
+++ b/ui/public/locales/te.json
@@ -3451,7 +3451,6 @@
"message.success.assign.vm": "విజయవంతంగా కేటాయించబడిన ఉదాహరణ",
"message.success.apply.network.policy": "నెట్వర్క్ పాలసీ విజయవంతంగా వర్తింపజేయబడింది",
"message.success.apply.tungsten.tag": "ట్యాగ్ విజయవంతంగా వర్తింపజేయబడింది",
- "message.success.asign.vm": "విజయవంతంగా కేటాయించబడిన ఉదాహరణ",
"message.success.assigned.vms": "సందర్భాలు విజయవంతంగా కేటాయించబడ్డాయి",
"message.success.certificate.upload": "సర్టిఫికెట్ విజయవంతంగా అప్లోడ్ చేయబడింది",
"message.success.change.affinity.group": "అనుబంధ సమూహాలు విజయవంతంగా మార్చబడ్డాయి",
@@ -3472,7 +3471,7 @@
"message.success.create.internallb": "ఇంటర్నల్ లోడ్ బ్యాలెన్సర్ విజయవంతంగా సృష్టించబడింది",
"message.success.create.isolated.network": "ఐసోలేటెడ్ నెట్వర్క్ విజయవంతంగా సృష్టించబడింది",
"message.success.create.keypair": "SSH కీ జత విజయవంతంగా సృష్టించబడింది",
- "message.success.create.kubernetes.cluter": "Kubernetes క్లస్టర్ విజయవంతంగా సృష్టించబడింది",
+ "message.success.create.kubernetes.cluster": "Kubernetes క్లస్టర్ విజయవంతంగా సృష్టించబడింది",
"message.success.create.l2.network": "L2 నెట్వర్క్ విజయవంతంగా సృష్టించబడింది",
"message.success.create.snapshot.from.vmsnapshot": "ఇన్స్టాన్స్ స్నాప్షాట్ నుండి స్నాప్షాట్ విజయవంతంగా సృష్టించబడింది",
"message.success.create.template": "టెంప్లేట్ విజయవంతంగా సృష్టించబడింది",
diff --git a/ui/public/locales/zh_CN.json b/ui/public/locales/zh_CN.json
index 0214936..4b68a2e 100644
--- a/ui/public/locales/zh_CN.json
+++ b/ui/public/locales/zh_CN.json
@@ -3792,7 +3792,7 @@
"message.success.create.internallb": "\u5DF2\u6210\u529F\u521B\u5EFA\u5185\u90E8LB",
"message.success.create.isolated.network": "\u5DF2\u6210\u529F\u521B\u5EFA\u9694\u79BB\u7F51\u7EDC",
"message.success.create.keypair": "\u5DF2\u6210\u529F\u521B\u5EFA SSH \u5BC6\u94A5\u5BF9",
- "message.success.create.kubernetes.cluter": "\u5DF2\u6210\u529F\u521B\u5EFA Kubernetes \u96C6\u7FA4",
+ "message.success.create.kubernetes.cluster": "\u5DF2\u6210\u529F\u521B\u5EFA Kubernetes \u96C6\u7FA4",
"message.success.create.l2.network": "\u5DF2\u6210\u529F\u521B\u5EFA L2 \u7F51\u7EDC",
"message.success.create.snapshot.from.vmsnapshot": "\u5DF2\u6210\u529F\u4ECE\u865A\u62DF\u673A\u5FEB\u7167\u521B\u5EFA\u5FEB\u7167",
"message.success.create.user": "\u5DF2\u6210\u529F\u521B\u5EFA\u7528\u6237",
diff --git a/ui/src/api/index.js b/ui/src/api/index.js
index 0c8e8e9..5ec73a0 100644
--- a/ui/src/api/index.js
+++ b/ui/src/api/index.js
@@ -140,3 +140,7 @@
}
})
}
+
+export function getBaseUrl () {
+ return vueProps.axios.defaults.baseURL
+}
diff --git a/ui/src/assets/icons/kubernetes.svg b/ui/src/assets/icons/kubernetes.svg
new file mode 100644
index 0000000..51d8f49
--- /dev/null
+++ b/ui/src/assets/icons/kubernetes.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 50 50"><path d="M 25 2.2773438 C 24.477218 2.2775288 23.954975 2.3938208 23.472656 2.6269531 L 8.0117188 10.091797 C 7.0499738 10.555895 6.3506462 11.43495 6.1132812 12.476562 L 2.2929688 29.259766 C 2.0568878 30.29908 2.3056798 31.391792 2.96875 32.226562 L 13.671875 45.683594 C 14.338066 46.521569 15.352133 47.009766 16.421875 47.009766 L 33.578125 47.009766 C 34.647867 47.009766 35.661934 46.521569 36.328125 45.683594 L 47.03125 32.228516 L 47.03125 32.226562 C 47.694185 31.39248 47.944721 30.300911 47.708984 29.261719 A 1.0001 1.0001 0 0 0 47.708984 29.259766 L 43.886719 12.476562 A 1.0001 1.0001 0 0 0 43.886719 12.474609 C 43.649412 11.434647 42.950464 10.556829 41.988281 10.091797 L 26.529297 2.6269531 A 1.0001 1.0001 0 0 0 26.527344 2.625 C 26.044986 2.3928828 25.522782 2.2771587 25 2.2773438 z M 25 4.2773438 C 25.224653 4.2774147 25.44878 4.3272999 25.658203 4.4277344 L 41.119141 11.892578 C 41.534958 12.093546 41.834807 12.469885 41.9375 12.919922 L 45.757812 29.703125 C 45.859943 30.153346 45.753012 30.622684 45.466797 30.982422 L 34.763672 44.439453 C 34.475863 44.801477 34.040383 45.009766 33.578125 45.009766 L 16.421875 45.009766 C 15.959617 45.009766 15.526091 44.801477 15.238281 44.439453 L 4.5351562 30.982422 C 4.2482266 30.621193 4.1402683 30.151811 4.2421875 29.703125 L 8.0644531 12.921875 C 8.1670882 12.471488 8.4666043 12.094433 8.8808594 11.894531 A 1.0001 1.0001 0 0 0 8.8808594 11.892578 L 24.341797 4.4277344 C 24.550169 4.3270161 24.775347 4.2772728 25 4.2773438 z M 24.992188 8.484375 C 24.851094 8.4846875 24.707812 8.5128125 24.570312 8.5703125 C 24.020312 8.8103125 23.76 9.45 24 10 C 24.23 10.54 24.309141 11.079141 24.369141 11.619141 C 24.389141 11.899141 24.400625 12.169453 24.390625 12.439453 C 24.420625 12.709453 24.280078 12.98 24.080078 13.25 C 23.870078 13.52 23.850312 13.790547 23.820312 14.060547 C 21.076091 14.329904 18.605618 15.53251 16.716797 17.339844 L 16.699219 17.330078 C 16.469219 17.180078 16.250391 17.029531 15.900391 17.019531 C 15.570391 16.999531 15.270078 16.940234 15.080078 16.740234 C 14.870078 16.580234 14.660703 16.400938 14.470703 16.210938 C 14.080703 15.830937 13.709453 15.420391 13.439453 14.900391 C 13.309453 14.650391 13.069297 14.449375 12.779297 14.359375 C 12.199297 14.199375 11.599688 14.529375 11.429688 15.109375 C 11.259688 15.679375 11.599687 16.289219 12.179688 16.449219 C 12.739688 16.619219 13.209922 16.899219 13.669922 17.199219 C 13.889922 17.349219 14.100547 17.509453 14.310547 17.689453 C 14.540547 17.839453 14.66 18.119453 14.75 18.439453 C 14.815992 18.759984 14.999921 18.945416 15.179688 19.125 C 13.81088 21.074269 13 23.443157 13 26 C 13 26.422964 13.023472 26.840139 13.066406 27.251953 C 12.842073 27.330478 12.62004 27.415663 12.429688 27.640625 C 12.209687 27.890625 11.969219 28.089375 11.699219 28.109375 C 11.439219 28.179375 11.170391 28.229766 10.900391 28.259766 C 10.360391 28.329766 9.8102344 28.37 9.2402344 28.25 C 8.9602344 28.2 8.6503906 28.259453 8.4003906 28.439453 C 7.9103906 28.779453 7.800625 29.459219 8.140625 29.949219 C 8.490625 30.439219 9.1701562 30.560937 9.6601562 30.210938 C 10.140156 29.870938 10.649922 29.679766 11.169922 29.509766 C 11.429922 29.429766 11.690938 29.360547 11.960938 29.310547 C 12.220937 29.220547 12.510313 29.299688 12.820312 29.429688 C 13.077895 29.562633 13.305954 29.552045 13.53125 29.529297 C 14.411477 32.383087 16.336155 34.773926 18.849609 36.283203 C 18.763733 36.523485 18.683169 36.773884 18.759766 37.089844 C 18.819766 37.419844 18.829453 37.730938 18.689453 37.960938 C 18.579453 38.210938 18.460078 38.449453 18.330078 38.689453 C 18.050078 39.149453 17.750547 39.609766 17.310547 40.009766 C 17.100547 40.199766 16.959219 40.469297 16.949219 40.779297 C 16.929219 41.379297 17.4 41.880391 18 41.900391 C 18.6 41.920391 19.110859 41.449609 19.130859 40.849609 C 19.140859 40.259609 19.300469 39.740703 19.480469 39.220703 C 19.570469 38.970703 19.680781 38.720469 19.800781 38.480469 C 19.890781 38.220469 20.129922 38.029141 20.419922 37.869141 C 20.708796 37.720044 20.838739 37.509224 20.96875 37.287109 C 22.230991 37.739556 23.5843 38 25 38 C 26.439867 38 27.815298 37.730979 29.095703 37.263672 C 29.231135 37.494815 29.370326 37.714564 29.660156 37.869141 C 29.950156 38.039141 30.189297 38.220469 30.279297 38.480469 C 30.399297 38.730469 30.499844 38.980469 30.589844 39.230469 C 30.769844 39.750469 30.919453 40.269375 30.939453 40.859375 C 30.939453 41.149375 31.059062 41.430625 31.289062 41.640625 C 31.739062 42.040625 32.420078 42.010312 32.830078 41.570312 C 33.230078 41.120312 33.199766 40.439297 32.759766 40.029297 C 32.319766 39.639297 32.02 39.169219 31.75 38.699219 C 31.62 38.469219 31.500625 38.220469 31.390625 37.980469 C 31.250625 37.740469 31.260078 37.439375 31.330078 37.109375 C 31.410078 36.769375 31.320234 36.519766 31.240234 36.259766 L 31.232422 36.234375 C 33.725863 34.710051 35.625253 32.311926 36.486328 29.458984 L 36.519531 29.460938 C 36.799531 29.480937 37.069141 29.509844 37.369141 29.339844 C 37.669141 29.199844 37.970469 29.119219 38.230469 29.199219 C 38.490469 29.239219 38.759531 29.299141 39.019531 29.369141 C 39.539531 29.519141 40.060781 29.699297 40.550781 30.029297 C 40.790781 30.179297 41.090625 30.249687 41.390625 30.179688 C 41.980625 30.049688 42.350703 29.470625 42.220703 28.890625 C 42.090703 28.300625 41.509922 27.930547 40.919922 28.060547 C 40.339922 28.190547 39.8 28.169141 39.25 28.119141 C 38.98 28.089141 38.719219 28.050234 38.449219 27.990234 C 38.179219 27.970234 37.940938 27.790781 37.710938 27.550781 C 37.480938 27.280781 37.220937 27.210859 36.960938 27.130859 L 36.943359 27.125 C 36.978072 26.754075 37 26.379828 37 26 C 37 23.520714 36.243083 21.213679 34.949219 19.298828 C 35.13888 19.099219 35.330515 18.909707 35.400391 18.570312 C 35.490391 18.250312 35.609844 17.970312 35.839844 17.820312 C 36.039844 17.640313 36.260469 17.480312 36.480469 17.320312 C 36.930469 17.020312 37.400937 16.730312 37.960938 16.570312 C 38.240938 16.490313 38.479141 16.299531 38.619141 16.019531 C 38.899141 15.489531 38.690391 14.830547 38.150391 14.560547 C 37.620391 14.280547 36.959453 14.489297 36.689453 15.029297 C 36.419453 15.549297 36.049922 15.959844 35.669922 16.339844 C 35.469922 16.529844 35.270547 16.710859 35.060547 16.880859 C 34.870547 17.080859 34.570234 17.140156 34.240234 17.160156 C 33.890234 17.170156 33.669453 17.330469 33.439453 17.480469 C 31.532566 15.591338 28.997515 14.337129 26.179688 14.060547 C 26.149687 13.790547 26.129922 13.52 25.919922 13.25 C 25.719922 12.98 25.579375 12.709453 25.609375 12.439453 C 25.599375 12.169453 25.610859 11.899141 25.630859 11.619141 C 25.690859 11.079141 25.77 10.54 26 10 C 26.11 9.74 26.12 9.430625 26 9.140625 C 25.82 8.728125 25.415469 8.4834375 24.992188 8.484375 z M 23.558594 16.115234 L 23.509766 16.5 C 23.369766 17.58 23.269922 18.67 23.169922 19.75 C 23.109922 20.32 23.059531 20.900703 23.019531 21.470703 C 22.529531 21.120703 22.039531 20.749922 21.519531 20.419922 C 20.619531 19.809922 19.719062 19.199141 18.789062 18.619141 L 18.474609 18.423828 C 19.881084 17.211935 21.629049 16.393039 23.558594 16.115234 z M 26.441406 16.115234 C 28.449951 16.404413 30.258788 17.284 31.693359 18.578125 L 31.359375 18.789062 C 30.439375 19.379062 29.550391 19.989609 28.650391 20.599609 C 28.290391 20.839609 27.939609 21.089844 27.599609 21.339844 C 27.329609 21.529844 26.959453 21.359297 26.939453 21.029297 C 26.909453 20.599297 26.870078 20.18 26.830078 19.75 C 26.730078 18.67 26.630234 17.58 26.490234 16.5 L 26.441406 16.115234 z M 16.582031 20.607422 L 16.900391 20.939453 C 17.660391 21.729453 18.430937 22.489766 19.210938 23.259766 C 19.540937 23.589766 19.870937 23.900937 20.210938 24.210938 C 20.450937 24.430937 20.360781 24.820156 20.050781 24.910156 C 19.560781 25.060156 19.070078 25.199375 18.580078 25.359375 C 17.550078 25.699375 16.510469 26.020625 15.480469 26.390625 L 15.027344 26.548828 C 15.017439 26.365855 15 26.185504 15 26 C 15 24.009707 15.585092 22.163224 16.582031 20.607422 z M 33.537109 20.804688 C 34.458955 22.319179 35 24.0924 35 26 C 35 26.167032 34.98265 26.32915 34.974609 26.494141 L 34.619141 26.380859 C 33.579141 26.040859 32.540234 25.749219 31.490234 25.449219 C 30.810234 25.249219 30.129219 25.070391 29.449219 24.900391 C 29.959219 24.410391 30.490469 23.929687 30.980469 23.429688 C 31.750469 22.659688 32.519531 21.889844 33.269531 21.089844 L 33.537109 20.804688 z M 24.380859 24 L 25.599609 24 C 25.789609 24 25.970313 24.090469 26.070312 24.230469 L 26.849609 25.210938 C 26.959609 25.340937 27.000703 25.529219 26.970703 25.699219 L 26.689453 26.910156 C 26.659453 27.100156 26.529141 27.249844 26.369141 27.339844 L 25.25 27.859375 C 25.09 27.949375 24.890469 27.949375 24.730469 27.859375 L 23.609375 27.339844 C 23.449375 27.249844 23.309062 27.100156 23.289062 26.910156 L 23.009766 25.699219 C 22.979766 25.529219 23.020859 25.340938 23.130859 25.210938 L 23.910156 24.230469 C 24.010156 24.090469 24.190859 24 24.380859 24 z M 20.769531 28.769531 C 21.079531 28.719531 21.330938 29.030312 21.210938 29.320312 C 21.020937 29.820312 20.839922 30.310547 20.669922 30.810547 C 20.299922 31.840547 19.939609 32.860391 19.599609 33.900391 L 19.462891 34.330078 C 17.683095 33.146647 16.31612 31.405254 15.587891 29.355469 L 16.119141 29.310547 C 17.209141 29.210547 18.279141 29.079219 19.369141 28.949219 C 19.839141 28.899219 20.299531 28.829531 20.769531 28.769531 z M 29.410156 28.910156 C 29.880156 28.960156 30.340547 29.010781 30.810547 29.050781 C 31.900547 29.150781 32.980312 29.250312 34.070312 29.320312 L 34.417969 29.339844 C 33.702862 31.363494 32.36593 33.088437 30.623047 34.273438 L 30.509766 33.910156 C 30.179766 32.870156 29.820703 31.840312 29.470703 30.820312 C 29.310703 30.360312 29.150469 29.910938 28.980469 29.460938 C 28.870469 29.170938 29.110156 28.870156 29.410156 28.910156 z M 25.074219 30.882812 C 25.216719 30.882812 25.359453 30.954609 25.439453 31.099609 C 25.659453 31.519609 25.890859 31.929844 26.130859 32.339844 C 26.670859 33.279844 27.209063 34.230391 27.789062 35.150391 L 28.025391 35.533203 C 27.071252 35.83443 26.055471 36 25 36 C 23.976312 36 22.989581 35.844572 22.060547 35.560547 L 22.310547 35.160156 C 22.890547 34.240156 23.440234 33.299375 23.990234 32.359375 C 24.240234 31.949375 24.480937 31.529609 24.710938 31.099609 C 24.790937 30.954609 24.931719 30.882812 25.074219 30.882812 z"></path></svg>
\ No newline at end of file
diff --git a/ui/src/components/header/CreateMenu.vue b/ui/src/components/header/CreateMenu.vue
index 8c39ec5..aa1d020 100644
--- a/ui/src/components/header/CreateMenu.vue
+++ b/ui/src/components/header/CreateMenu.vue
@@ -26,7 +26,7 @@
<a-avatar :style="{ backgroundColor: $config.theme['@primary-color'] }">
<template #icon>
<render-icon v-if="(typeof menuItem.icon === 'string')" :icon="menuItem.icon" />
- <font-awesome-icon v-else :icon="menuItem.icon" />
+ <render-icon v-else :style="{fill:'#ffffff'}" :svg-icon=menuItem.icon />
</template>
</a-avatar>
</a-col>
@@ -50,6 +50,8 @@
<script>
+import kubernetesIcon from '@/assets/icons/kubernetes.svg?inline'
+
export default {
name: 'CreateMenu',
beforeCreate () {
@@ -65,7 +67,7 @@
api: 'createKubernetesCluster',
title: 'label.kubernetes',
subtitle: 'label.kubernetes.cluster.create',
- icon: ['fa-solid', 'fa-dharmachakra'],
+ icon: kubernetesIcon,
route: { path: '/kubernetes', query: { action: 'createKubernetesCluster' } }
},
{
diff --git a/ui/src/components/view/AdvisoriesView.vue b/ui/src/components/view/AdvisoriesView.vue
new file mode 100644
index 0000000..c668ec0
--- /dev/null
+++ b/ui/src/components/view/AdvisoriesView.vue
@@ -0,0 +1,161 @@
+// 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.
+
+<template>
+ <div>
+ <div v-for="advisory in advisories" :key="advisory.id" style="margin-bottom: 10px;">
+ <a-alert
+ :type="advisory.severity || 'info'"
+ :show-icon="true"
+ :closable="true"
+ :message="$t(advisory.message)"
+ @close="onAlertClose(advisory)">
+ <template #description>
+ <a-space direction="horizontal" size="small">
+ <span v-for="(action, idx) in advisory.actions" :key="idx">
+ <a-button
+ v-if="typeof action.show === 'function' ? action.show($store) : action.show"
+ size="small"
+ :type="(action.primary || advisory.actions.length === 1) ? 'primary' : 'default'"
+ @click="onAlertBtnClick(action, advisory)">
+ {{ $t(action.label) }}
+ </a-button>
+ </span>
+ </a-space>
+ </template>
+ </a-alert>
+ </div>
+ </div>
+</template>
+
+<script>
+
+const DISMISSED_ADVISORIES_KEY = 'dismissed_advisories'
+
+export default {
+ name: 'AdvisoriesView',
+ components: {
+ },
+ props: {},
+ data () {
+ return {
+ advisories: []
+ }
+ },
+ created () {
+ this.evaluateAdvisories()
+ },
+ computed: {
+ },
+ methods: {
+ async evaluateAdvisories () {
+ this.advisories = []
+ const metaAdvisories = this.$route.meta.advisories || []
+ const dismissedAdvisories = this.$localStorage.get(DISMISSED_ADVISORIES_KEY) || []
+ const advisoryPromises = metaAdvisories.map(async advisory => {
+ if (dismissedAdvisories.includes(advisory.id)) {
+ return null
+ }
+ const active = await Promise.resolve(advisory.condition(this.$store))
+ if (active) {
+ return advisory
+ } else if (advisory.dismissOnConditionFail) {
+ this.dismissAdvisory(advisory.id, true)
+ }
+ return null
+ })
+ const results = await Promise.all(advisoryPromises)
+ this.advisories = results.filter(a => a !== null)
+ },
+ onAlertClose (advisory) {
+ this.dismissAdvisory(advisory.id)
+ },
+ dismissAdvisory (advisoryId, skipUpdateLocal) {
+ let dismissedAdvisories = this.$localStorage.get(DISMISSED_ADVISORIES_KEY) || []
+ dismissedAdvisories = dismissedAdvisories.filter(id => id !== advisoryId)
+ dismissedAdvisories.push(advisoryId)
+ this.$localStorage.set(DISMISSED_ADVISORIES_KEY, dismissedAdvisories)
+ if (skipUpdateLocal) {
+ return
+ }
+ this.advisories = this.advisories.filter(advisory => advisory.id !== advisoryId)
+ },
+ undismissAdvisory (advisory, evaluate) {
+ let dismissedAdvisories = this.$localStorage.get(DISMISSED_ADVISORIES_KEY) || []
+ dismissedAdvisories = dismissedAdvisories.filter(id => id !== advisory.id)
+ this.$localStorage.set(DISMISSED_ADVISORIES_KEY, dismissedAdvisories)
+ if (evaluate) {
+ Promise.resolve(advisory.condition(this.$store)).then(active => {
+ if (active) {
+ this.advisories.push(advisory)
+ }
+ })
+ } else {
+ this.advisories.push(advisory)
+ }
+ },
+ handleAdvisoryActionError (action, advisory, evaluate) {
+ if (action.errorMessage) {
+ this.showActionMessage('error', advisory.id, action.errorMessage)
+ }
+ this.undismissAdvisory(advisory, evaluate)
+ },
+ handleAdvisoryActionResult (action, advisory, result) {
+ if (result && action.successMessage) {
+ this.showActionMessage('success', advisory.id, action.successMessage)
+ return
+ }
+ this.handleAdvisoryActionError(action, advisory, false)
+ },
+ showActionMessage (type, key, content) {
+ const data = {
+ content: this.$t(content),
+ key: key,
+ duration: type === 'loading' ? 0 : 3
+ }
+ if (type === 'loading') {
+ this.$message.loading(data)
+ } else if (type === 'success') {
+ this.$message.success(data)
+ } else if (type === 'error') {
+ this.$message.error(data)
+ } else {
+ this.$message.info(data)
+ }
+ },
+ onAlertBtnClick (action, advisory) {
+ this.dismissAdvisory(advisory.id)
+ if (typeof action.run !== 'function') {
+ return
+ }
+ if (action.loadingLabel) {
+ this.showActionMessage('loading', advisory.id, action.loadingLabel)
+ }
+ const result = action.run(this.$store, this.$router)
+ if (result instanceof Promise) {
+ result.then(success => {
+ this.handleAdvisoryActionResult(action, advisory, success)
+ }).catch(() => {
+ this.handleAdvisoryActionError(action, advisory, true)
+ })
+ } else {
+ this.handleAdvisoryActionResult(action, advisory, result)
+ }
+ }
+ }
+}
+</script>
diff --git a/ui/src/components/view/DateTimeFilter.vue b/ui/src/components/view/DateTimeFilter.vue
index efac3b4..80489a4 100644
--- a/ui/src/components/view/DateTimeFilter.vue
+++ b/ui/src/components/view/DateTimeFilter.vue
@@ -1,17 +1,17 @@
// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
+// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
+// 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
+// with the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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
+// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
diff --git a/ui/src/components/view/DedicateDomain.vue b/ui/src/components/view/DedicateDomain.vue
index 4b8cc31..a1d69dc 100644
--- a/ui/src/components/view/DedicateDomain.vue
+++ b/ui/src/components/view/DedicateDomain.vue
@@ -59,7 +59,7 @@
props: {
error: {
type: Boolean,
- requried: true
+ required: true
}
},
data () {
diff --git a/ui/src/components/view/DeployVMFromBackup.vue b/ui/src/components/view/DeployVMFromBackup.vue
index 55808db..cbf265b 100644
--- a/ui/src/components/view/DeployVMFromBackup.vue
+++ b/ui/src/components/view/DeployVMFromBackup.vue
@@ -975,6 +975,9 @@
}, {
id: 'aarch64',
description: 'ARM 64 bits (aarch64)'
+ }, {
+ id: 's390x',
+ description: 'IBM Z 64 bits (s390x)'
}
]
}
@@ -1589,7 +1592,7 @@
})
this.fetchBootTypes()
this.fetchBootModes()
- this.fetchInstaceGroups()
+ this.fetchInstanceGroups()
this.fetchIoPolicyTypes()
nextTick().then(() => {
['name', 'keyboard', 'boottype', 'bootmode', 'iothreadsenabled', 'iodriverpolicy', 'nicmultiqueuenumber', 'nicpackedvirtqueues'].forEach(this.fillValue)
@@ -1640,7 +1643,7 @@
{ id: 'storage_specific', description: 'storage_specific' }
]
},
- fetchInstaceGroups () {
+ fetchInstanceGroups () {
this.options.instanceGroups = []
getAPI('listInstanceGroups', {
account: this.$store.getters.project?.id ? null : this.$store.getters.userInfo.account,
@@ -2469,12 +2472,12 @@
configuration.cpunumber = 0
configuration.cpuspeed = 0
configuration.memory = 0
- for (var harwareItem of configuration.hardwareItems) {
- if (harwareItem.resourceType === 'Processor') {
- configuration.cpunumber = harwareItem.virtualQuantity
- configuration.cpuspeed = harwareItem.reservation
- } else if (harwareItem.resourceType === 'Memory') {
- configuration.memory = harwareItem.virtualQuantity
+ for (var hardwareItem of configuration.hardwareItems) {
+ if (hardwareItem.resourceType === 'Processor') {
+ configuration.cpunumber = hardwareItem.virtualQuantity
+ configuration.cpuspeed = hardwareItem.reservation
+ } else if (hardwareItem.resourceType === 'Memory') {
+ configuration.memory = hardwareItem.virtualQuantity
}
}
configurations.push(configuration)
diff --git a/ui/src/components/view/DetailsTab.vue b/ui/src/components/view/DetailsTab.vue
index 135ea73..4145eeb 100644
--- a/ui/src/components/view/DetailsTab.vue
+++ b/ui/src/components/view/DetailsTab.vue
@@ -64,8 +64,8 @@
</div>
<div v-else-if="$route.meta.name === 'backup' && item === 'volumes'">
<div v-for="(volume, idx) in JSON.parse(dataResource[item])" :key="idx">
- <router-link v-if="!dataResource['vmbackupofferingremoved']" :to="{ path: '/volume/' + volume.uuid }">{{ volume.type }} - {{ volume.path }}</router-link>
- <span v-else>{{ volume.type }} - {{ volume.path }}</span> ({{ parseFloat(volume.size / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB)
+ <router-link v-if="!dataResource['vmbackupofferingremoved']" :to="{ path: '/volume/' + volume.uuid }">{{ volume.type }} - {{ volume.uuid }}</router-link>
+ <span v-else>{{ volume.type }} - {{ volume.uuid }}</span> ({{ parseFloat(volume.size / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB)
</div>
</div>
<div v-else-if="$route.meta.name === 'computeoffering' && item === 'rootdisksize'">
diff --git a/ui/src/components/view/GPUDevicesTab.vue b/ui/src/components/view/GPUDevicesTab.vue
index ee67a81..4b37958 100644
--- a/ui/src/components/view/GPUDevicesTab.vue
+++ b/ui/src/components/view/GPUDevicesTab.vue
@@ -1,17 +1,17 @@
// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
+// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
+// 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
+// with the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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
+// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
diff --git a/ui/src/components/view/GPUSummaryTab.vue b/ui/src/components/view/GPUSummaryTab.vue
index 52553f1..a602335 100644
--- a/ui/src/components/view/GPUSummaryTab.vue
+++ b/ui/src/components/view/GPUSummaryTab.vue
@@ -1,18 +1,17 @@
-
// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
+// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
+// 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
+// with the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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
+// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
diff --git a/ui/src/components/view/GPUTab.vue b/ui/src/components/view/GPUTab.vue
index d2cd2f3..03096ea 100644
--- a/ui/src/components/view/GPUTab.vue
+++ b/ui/src/components/view/GPUTab.vue
@@ -1,17 +1,17 @@
// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
+// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
+// 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
+// with the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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
+// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
diff --git a/ui/src/components/view/InfoCard.vue b/ui/src/components/view/InfoCard.vue
index 0031d73..996e30e 100644
--- a/ui/src/components/view/InfoCard.vue
+++ b/ui/src/components/view/InfoCard.vue
@@ -1094,7 +1094,7 @@
return ['UserVm', 'Template', 'ISO', 'Volume', 'Snapshot', 'Backup', 'Network',
'LoadBalancer', 'PortForwardingRule', 'FirewallRule', 'SecurityGroup', 'SecurityGroupRule',
'PublicIpAddress', 'Project', 'Account', 'Vpc', 'NetworkACL', 'StaticRoute', 'VMSnapshot',
- 'RemoteAccessVpn', 'User', 'SnapshotPolicy', 'VpcOffering']
+ 'RemoteAccessVpn', 'User', 'SnapshotPolicy', 'VpcOffering', 'Domain']
},
name () {
return this.resource.displayname || this.resource.name || this.resource.displaytext || this.resource.username ||
diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue
index 7fd344d..d6f44cb 100644
--- a/ui/src/components/view/ListView.vue
+++ b/ui/src/components/view/ListView.vue
@@ -170,6 +170,14 @@
<warning-outlined style="color: #f5222d" />
</a-tooltip>
</span>
+ <span v-else-if="$route.path.startsWith('/vpncustomergateway')">
+
+ <a-tooltip
+ v-if="record.excludedparameters || record.obsoleteparameters"
+ :title="$t('message.vpn.customer.gateway.contains.excluded.obsolete.parameters')">
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ </a-tooltip>
+ </span>
</span>
<span
v-if="record.leaseduration !== undefined"
@@ -935,6 +943,16 @@
@pressEnter="saveValue(record)"
>
</a-input>
+ <template v-else-if="['webhook'].includes($route.path.split('/')[1])">
+ <span style="word-break: break-all">{{ text }}</span>
+ <QuickView
+ style="margin-left: 5px"
+ :actions="actions"
+ :resource="record"
+ :enabled="quickViewEnabled() && actions.length > 0"
+ @exec-action="$parent.execAction"
+ />
+ </template>
<div
v-else
style="width: 200px; word-break: break-all"
@@ -970,7 +988,7 @@
@onClick="$resetConfigurationValueConfirm(item, resetConfig)"
v-if="editableValueKey !== record.key"
icon="reload-outlined"
- :disabled="!('updateConfiguration' in $store.getters.apis)"
+ :disabled="!('resetConfiguration' in $store.getters.apis) || record.value === record.defaultvalue"
/>
</template>
<template v-if="column.key === 'gpuDeviceActions'">
@@ -1198,7 +1216,7 @@
'/project', '/account', 'buckets', 'objectstore',
'/zone', '/pod', '/cluster', '/host', '/storagepool', '/imagestore', '/systemvm', '/router', '/ilbvm', '/annotation',
'/computeoffering', '/systemoffering', '/diskoffering', '/backupoffering', '/networkoffering', '/vpcoffering',
- '/tungstenfabric', '/oauthsetting', '/guestos', '/guestoshypervisormapping', '/webhook', 'webhookdeliveries', '/quotatariff', '/sharedfs',
+ '/tungstenfabric', '/oauthsetting', '/guestos', '/guestoshypervisormapping', '/webhook', 'webhookdeliveries', 'webhookfilters', '/quotatariff', '/sharedfs',
'/ipv4subnets', '/managementserver', '/gpucard', '/gpudevices', '/vgpuprofile', '/extension', '/snapshotpolicy', '/backupschedule'].join('|'))
.test(this.$route.path)
},
diff --git a/ui/src/components/view/ResourceCountUsage.vue b/ui/src/components/view/ResourceCountUsage.vue
index 688a706..c74391f 100644
--- a/ui/src/components/view/ResourceCountUsage.vue
+++ b/ui/src/components/view/ResourceCountUsage.vue
@@ -40,7 +40,7 @@
v-if="taggedUsage[item]"
class="list-item__collapse"
@change="handleCollapseChange(item)">
- <a-collapse-panel key="1" :header="collpaseActive[item] ? $t('label.tagged.limits') : $t('label.tagged.limits') + ' - ' + this.tagData[item].tagsasstring">
+ <a-collapse-panel key="1" :header="collapseActive[item] ? $t('label.tagged.limits') : $t('label.tagged.limits') + ' - ' + this.tagData[item].tagsasstring">
<a-list
size="small"
:loading="loading"
@@ -96,7 +96,7 @@
],
taggedUsage: {},
tagData: {},
- collpaseActive: {}
+ collapseActive: {}
}
},
created () {
@@ -168,11 +168,11 @@
}
},
handleCollapseChange (type) {
- if (this.collpaseActive[type]) {
- this.collpaseActive[type] = null
+ if (this.collapseActive[type]) {
+ this.collapseActive[type] = null
return
}
- this.collpaseActive[type] = true
+ this.collapseActive[type] = true
}
}
}
diff --git a/ui/src/components/view/ResourceLimitTab.vue b/ui/src/components/view/ResourceLimitTab.vue
index 699c024..6f149fa 100644
--- a/ui/src/components/view/ResourceLimitTab.vue
+++ b/ui/src/components/view/ResourceLimitTab.vue
@@ -43,7 +43,7 @@
v-if="item.taggedresource && item.taggedresource.length > 0"
class="tagged-limit-collapse"
@change="handleCollapseChange(item.resourcetypename)">
- <a-collapse-panel key="1" :header="collpaseActive[item.resourcetypename] ? $t('label.tagged.limits') : $t('label.tagged.limits') + ' - ' + item.tagsasstring">
+ <a-collapse-panel key="1" :header="collapseActive[item.resourcetypename] ? $t('label.tagged.limits') : $t('label.tagged.limits') + ' - ' + item.tagsasstring">
<div v-for="(subItem, subItemIndex) in item.taggedresource" :key="subItemIndex">
<a-form-item
:v-bind="subItem.resourcetypename"
@@ -94,7 +94,7 @@
return {
formLoading: false,
dataResource: [],
- collpaseActive: {},
+ collapseActive: {},
resourceTypeIdNames: {}
}
},
@@ -259,11 +259,11 @@
})
},
handleCollapseChange (type) {
- if (this.collpaseActive[type]) {
- this.collpaseActive[type] = null
+ if (this.collapseActive[type]) {
+ this.collapseActive[type] = null
return
}
- this.collpaseActive[type] = true
+ this.collapseActive[type] = true
}
}
}
diff --git a/ui/src/components/view/SettingsTab.vue b/ui/src/components/view/SettingsTab.vue
index ab75bef..0e0ee33 100644
--- a/ui/src/components/view/SettingsTab.vue
+++ b/ui/src/components/view/SettingsTab.vue
@@ -26,7 +26,8 @@
<ConfigurationTable
:columns="columns"
:config="items"
- :resource="resource" />
+ :resource="resource"
+ @refresh-config="handleConfigRefresh" />
</a-col>
</div>
</template>
@@ -140,6 +141,13 @@
handleSearch (value) {
this.filter = value
this.fetchData()
+ },
+ handleConfigRefresh (name, updatedRecord) {
+ if (!name || !updatedRecord) return
+ const index = this.items.findIndex(item => item.name === name)
+ if (index !== -1) {
+ this.items.splice(index, 1, updatedRecord)
+ }
}
}
}
diff --git a/ui/src/components/view/TestWebhookDeliveryView.vue b/ui/src/components/view/TestWebhookDeliveryView.vue
index 4e3af23..364a7dc 100644
--- a/ui/src/components/view/TestWebhookDeliveryView.vue
+++ b/ui/src/components/view/TestWebhookDeliveryView.vue
@@ -126,7 +126,7 @@
collapseKey: undefined,
loading: false,
testDeliveryInterval: null,
- testDeliveryIntervalCouter: 0
+ testDeliveryIntervalCounter: 0
}
},
beforeCreate () {
@@ -154,8 +154,8 @@
return (duration > 0 ? duration / 1000.0 : 0) + ''
},
computedOverlayStyle () {
- var opacity = this.testDeliveryIntervalCouter <= 10.0 ? 0 : 0.3
- var width = this.testDeliveryIntervalCouter
+ var opacity = this.testDeliveryIntervalCounter <= 10.0 ? 0 : 0.3
+ var width = this.testDeliveryIntervalCounter
return 'opacity: ' + opacity + '; width: ' + width + '%;'
}
},
@@ -168,7 +168,7 @@
if (this.testDeliveryInterval) {
clearInterval(this.testDeliveryInterval)
}
- this.testDeliveryIntervalCouter = 0
+ this.testDeliveryIntervalCounter = 0
},
testWebhookDelivery () {
this.resetTestDeliveryInterval()
@@ -223,8 +223,8 @@
this.resetTestDeliveryInterval()
return
}
- this.testDeliveryIntervalCouter = this.testDeliveryIntervalCouter + 1
- if (this.testDeliveryIntervalCouter >= 100) {
+ this.testDeliveryIntervalCounter = this.testDeliveryIntervalCounter + 1
+ if (this.testDeliveryIntervalCounter >= 100) {
this.executeTestWebhookDeliveryOrReset()
}
}, this.timedDeliveryWait / 100)
diff --git a/ui/src/components/view/VgpuProfilesTab.vue b/ui/src/components/view/VgpuProfilesTab.vue
index b5c2af5..4480c4a 100644
--- a/ui/src/components/view/VgpuProfilesTab.vue
+++ b/ui/src/components/view/VgpuProfilesTab.vue
@@ -1,17 +1,17 @@
// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
+// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
+// 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
+// with the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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
+// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
diff --git a/ui/src/components/view/WebhookFiltersTab.vue b/ui/src/components/view/WebhookFiltersTab.vue
new file mode 100644
index 0000000..2d276e2
--- /dev/null
+++ b/ui/src/components/view/WebhookFiltersTab.vue
@@ -0,0 +1,416 @@
+// 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.
+
+<template>
+ <div>
+ <div class="add-row">
+ <a-form
+ :ref="addFormRef"
+ :model="addFilterForm"
+ :rules="addFormRules"
+ @finish="addFilter"
+ layout="vertical"
+ class="add-filter-form">
+ <a-row :gutter="16">
+ <a-col :span="12">
+ <a-form-item name="mode" ref="mode">
+ <template #label>
+ <tooltip-label :title="$t('label.mode')" :tooltip="addFilterApiParams.mode.description"/>
+ </template>
+ <a-radio-group v-model:value="addFilterForm.mode" button-style="solid">
+ <a-radio-button value="include">{{ $t('label.include') }}</a-radio-button>
+ <a-radio-button value="exclude">{{ $t('label.exclude') }}</a-radio-button>
+ </a-radio-group>
+ </a-form-item>
+ </a-col>
+
+ <a-col :span="12">
+ <a-form-item name="matchtype" ref="matchtype">
+ <template #label>
+ <tooltip-label :title="$t('label.matchtype')" :tooltip="addFilterApiParams.matchtype.description"/>
+ </template>
+ <a-select
+ style="margin-left: 0"
+ v-model:value="addFilterForm.matchtype"
+ placeholder="Select match type"
+ allow-clear>
+ <a-select-option value="exact">{{ $t('label.exact') }}</a-select-option>
+ <a-select-option value="prefix">{{ $t('label.prefix') }}</a-select-option>
+ <a-select-option value="suffix">{{ $t('label.suffix') }}</a-select-option>
+ <a-select-option value="contains">{{ $t('label.contains') }}</a-select-option>
+ </a-select>
+ </a-form-item>
+ </a-col>
+ </a-row>
+
+ <a-row :gutter="16" style="margin-top: 8px;">
+ <a-col :span="24">
+ <a-form-item name="value" ref="value">
+ <template #label>
+ <tooltip-label :title="$t('label.value')" :tooltip="addFilterApiParams.value.description"/>
+ </template>
+ <a-input v-model:value="addFilterForm.value" placeholder="Enter filter value" />
+ </a-form-item>
+ </a-col>
+ </a-row>
+
+ <a-row style="margin-top: 16px;">
+ <a-col :span="24" style="text-align: right;">
+ <a-space>
+ <a-button @click="resetAddFilterForm">{{ $t('label.reset') }}</a-button>
+ <a-button type="primary" ref="submit" @click="addFilter">{{ $t('label.add') }}</a-button>
+ </a-space>
+ </a-col>
+ </a-row>
+ </a-form>
+ </div>
+
+ <a-divider />
+ <a-button
+ v-if="('deleteWebhookFilter' in $store.getters.apis) && (selectedRowKeys && selectedRowKeys.length > 0)"
+ type="danger"
+ danger
+ style="width: 100%; margin-bottom: 15px"
+ @click="clearOrDeleteFiltersConfirmation()">
+ <template #icon><delete-outlined /></template>
+ {{ (selectedRowKeys && selectedRowKeys.length > 0) ? $t('label.action.delete.webhook.filters') : $t('label.action.clear.webhook.filters') }}
+ </a-button>
+ <list-view
+ :tabLoading="tabLoading"
+ :columns="columns"
+ :items="filters"
+ :actions="actions"
+ :columnKeys="columnKeys"
+ :explicitlyAllowRowSelection="true"
+ :selectedColumns="selectedColumnKeys"
+ ref="listview"
+ @update-selected-columns="updateSelectedColumns"
+ @refresh="this.fetchData"
+ @selection-change="updateSelectedRows"/>
+ <a-pagination
+ class="row-element"
+ style="margin-top: 10px"
+ size="small"
+ :current="page"
+ :pageSize="pageSize"
+ :total="totalCount"
+ :showTotal="total => `${$t('label.showing')} ${Math.min(total, 1+((page-1)*pageSize))}-${Math.min(page*pageSize, total)} ${$t('label.of')} ${total} ${$t('label.items')}`"
+ :pageSizeOptions="pageSizeOptions"
+ @change="changePage"
+ @showSizeChange="changePage"
+ showSizeChanger
+ showQuickJumper>
+ <template #buildOptionText="props">
+ <span>{{ props.value }} / {{ $t('label.page') }}</span>
+ </template>
+ </a-pagination>
+ </div>
+</template>
+
+<script>
+import { ref, reactive, toRaw } from 'vue'
+import { getAPI, postAPI } from '@/api'
+import { mixinForm } from '@/utils/mixin'
+import { genericCompare } from '@/utils/sort.js'
+import TooltipLabel from '@/components/widgets/TooltipLabel'
+import ListView from '@/components/view/ListView'
+
+export default {
+ name: 'WebhookFiltersTab',
+ mixins: [mixinForm],
+ components: {
+ TooltipLabel,
+ ListView
+ },
+ props: {
+ resource: {
+ type: Object,
+ required: true
+ },
+ loading: {
+ type: Boolean,
+ required: true
+ }
+ },
+ data () {
+ return {
+ tabLoading: false,
+ columnKeys: ['value', 'type', 'mode', 'matchtype'],
+ selectedColumnKeys: ['value', 'mode', 'matchtype'],
+ selectedRowKeys: [],
+ columns: [],
+ cols: [],
+ filters: [],
+ actions: [
+ {
+ api: 'deleteWebhookFilter',
+ icon: 'delete-outlined',
+ label: 'label.delete.webhook.filter',
+ message: 'message.delete.webhook.filter',
+ dataView: true,
+ popup: true
+ }
+ ],
+ page: 1,
+ pageSize: 20,
+ totalCount: 0
+ }
+ },
+ computed: {
+ pageSizeOptions () {
+ var sizes = [20, 50, 100, 200, this.$store.getters.defaultListViewPageSize]
+ if (this.device !== 'desktop') {
+ sizes.unshift(10)
+ }
+ return [...new Set(sizes)].sort(function (a, b) {
+ return a - b
+ }).map(String)
+ }
+ },
+ beforeCreate () {
+ this.addFilterApiParams = this.$getApiParams('addWebhookFilter')
+ },
+ created () {
+ this.updateColumns()
+ this.pageSize = this.pageSizeOptions[0] * 1
+ this.initAddFilterForm()
+ this.fetchData()
+ },
+ watch: {
+ resource: {
+ handler () {
+ this.fetchData()
+ }
+ }
+ },
+ methods: {
+ fetchData () {
+ if ('listview' in this.$refs && this.$refs.listview) {
+ this.$refs.listview.resetSelection()
+ }
+ this.fetchFilters()
+ },
+ fetchFilters () {
+ this.filters = []
+ if (!this.resource.id) {
+ return
+ }
+ const params = {
+ page: this.page,
+ pagesize: this.pageSize,
+ webhookid: this.resource.id,
+ listall: true
+ }
+ this.tabLoading = true
+ getAPI('listWebhookFilters', params).then(json => {
+ this.filters = []
+ this.totalCount = json?.listwebhookfiltersresponse?.count || 0
+ this.filters = json?.listwebhookfiltersresponse?.webhookfilter || []
+ this.tabLoading = false
+ })
+ },
+ changePage (page, pageSize) {
+ this.page = page
+ this.pageSize = pageSize
+ this.fetchFilters()
+ },
+ updateSelectedColumns (key) {
+ if (this.selectedColumnKeys.includes(key)) {
+ this.selectedColumnKeys = this.selectedColumnKeys.filter(x => x !== key)
+ } else {
+ this.selectedColumnKeys.push(key)
+ }
+ this.updateColumns()
+ },
+ updateColumns () {
+ this.columns = []
+ for (var columnKey of this.columnKeys) {
+ const key = columnKey
+ if (!this.selectedColumnKeys.includes(key)) continue
+ var title = this.$t('label.' + String(key).toLowerCase())
+ this.columns.push({
+ key: key,
+ title: title,
+ dataIndex: key,
+ sorter: (a, b) => { return genericCompare(a[key] || '', b[key] || '') }
+ })
+ }
+ if (this.columns.length > 0) {
+ this.columns[this.columns.length - 1].customFilterDropdown = true
+ }
+ },
+ initAddFilterForm () {
+ this.addFormRef = ref()
+ this.addFilterForm = reactive({
+ mode: 'include',
+ matchtype: 'exact',
+ value: null
+ })
+ this.addFormRules = reactive({
+ value: [{ required: true, message: this.$t('message.error.required.input') }]
+ })
+ },
+ resetAddFilterForm () {
+ if (this.addFormRef.value) {
+ this.addFormRef.value.resetFields()
+ }
+ },
+ addFilter (e) {
+ e.preventDefault()
+ if (this.tabLoading) return
+ console.log('Adding webhook filter with form:', this.addFilterForm)
+ this.addFormRef.value.validate().then(() => {
+ const formRaw = toRaw(this.addFilterForm)
+ const values = this.handleRemoveFields(formRaw)
+ const params = {
+ webhookid: this.resource.id,
+ mode: values.mode,
+ matchtype: values.matchtype,
+ value: values.value
+ }
+ console.log('Adding webhook filter with params:', params)
+ this.tabLoading = true
+ postAPI('addWebhookFilter', params).then(json => {
+ this.$notification.success({
+ message: this.$t('label.add.webhook.filter'),
+ description: this.$t('message.success.add.webhook.filter')
+ })
+ setTimeout(() => {
+ this.resetAddFilterForm()
+ }, 250)
+ }).catch(error => {
+ this.$notifyError(error)
+ }).finally(() => {
+ this.tabLoading = false
+ this.fetchFilters()
+ })
+ })
+ },
+ updateSelectedRows (keys) {
+ this.selectedRowKeys = keys
+ },
+ clearOrDeleteFiltersConfirmation () {
+ const self = this
+ const title = (this.selectedRowKeys && this.selectedRowKeys.length > 0)
+ ? this.$t('label.action.delete.webhook.filters')
+ : this.$t('label.action.clear.webhook.filters')
+ this.$confirm({
+ title: title,
+ okText: this.$t('label.ok'),
+ okType: 'danger',
+ cancelText: this.$t('label.cancel'),
+ onOk () {
+ if (self.selectedRowKeys && self.selectedRowKeys.length > 0) {
+ self.deletedSelectedFilters()
+ return
+ }
+ self.clearFilters()
+ }
+ })
+ },
+ deletedSelectedFilters () {
+ const promises = []
+ this.selectedRowKeys.forEach(id => {
+ const params = {
+ id: id
+ }
+ promises.push(new Promise((resolve, reject) => {
+ postAPI('deleteWebhookFilter', params).then(json => {
+ return resolve(id)
+ }).catch(error => {
+ return reject(error)
+ })
+ }))
+ })
+ const msg = this.$t('label.action.delete.webhook.filters')
+ this.$message.info({
+ content: msg,
+ duration: 3
+ })
+ this.tabLoading = true
+ Promise.all(promises).finally(() => {
+ this.tabLoading = false
+ this.fetchData()
+ })
+ },
+ clearFilters () {
+ const params = {
+ webhookid: this.resource.id
+ }
+ this.tabLoading = true
+ postAPI('deleteWebhookFilter', params).then(json => {
+ this.$message.success(this.$t('message.success.clear.webhook.filters'))
+ this.fetchData()
+ }).catch(error => {
+ this.$notifyError(error)
+ }).finally(() => {
+ this.tabLoading = false
+ })
+ },
+ deleteFilterConfirmation (item) {
+ const self = this
+ this.$confirm({
+ title: this.$t('label.delete.webhook.filter'),
+ okText: this.$t('label.ok'),
+ okType: 'primary',
+ cancelText: this.$t('label.cancel'),
+ onOk () {
+ self.deleteFilter(item)
+ }
+ })
+ },
+ deleteFilter (item) {
+ const params = {
+ id: item.id
+ }
+ this.tabLoading = true
+ postAPI('deleteWebhookFilter', params).then(json => {
+ const message = `${this.$t('message.success.delete')} ${this.$t('label.webhook.filter')}`
+ this.$message.success(message)
+ this.fetchData()
+ }).catch(error => {
+ this.$notifyError(error)
+ }).finally(() => {
+ this.tabLoading = false
+ })
+ },
+ execAction (action) {
+ if (action.api === 'deleteWebhookFilter') {
+ this.deleteFilterConfirmation(action.resource)
+ }
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.ant-tag {
+ padding: 0 7px 0 0;
+}
+.ant-select {
+ margin-left: 10px;
+}
+.info-icon {
+ margin: 0 10px 0 5px;
+}
+.filter-row {
+ margin-bottom: 2.5%;
+}
+.filter-row-inner {
+ margin-top: 3%;
+}
+</style>
diff --git a/ui/src/components/view/stats/ResourceStatsInfo.vue b/ui/src/components/view/stats/ResourceStatsInfo.vue
index 6898141..1042834 100644
--- a/ui/src/components/view/stats/ResourceStatsInfo.vue
+++ b/ui/src/components/view/stats/ResourceStatsInfo.vue
@@ -1,17 +1,17 @@
// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
+// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
+// 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
+// with the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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
+// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
diff --git a/ui/src/components/view/stats/ResourceStatsLineChart.vue b/ui/src/components/view/stats/ResourceStatsLineChart.vue
index fa15ea3..399e77b 100644
--- a/ui/src/components/view/stats/ResourceStatsLineChart.vue
+++ b/ui/src/components/view/stats/ResourceStatsLineChart.vue
@@ -1,17 +1,17 @@
// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
+// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
+// 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
+// with the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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
+// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
diff --git a/ui/src/config/router.js b/ui/src/config/router.js
index 08df799..3e5d867 100644
--- a/ui/src/config/router.js
+++ b/ui/src/config/router.js
@@ -81,6 +81,7 @@
filters: child.filters,
params: child.params ? child.params : {},
columns: child.columns,
+ advisories: !vueProps.$config.advisoriesDisabled ? child.advisories : undefined,
details: child.details,
searchFilters: child.searchFilters,
related: child.related,
@@ -180,6 +181,10 @@
map.meta.columns = section.columns
}
+ if (!vueProps.$config.advisoriesDisabled && section.advisories) {
+ map.meta.advisories = section.advisories
+ }
+
if (section.actions) {
map.meta.actions = section.actions
}
diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js
index 63d0e36..32e888b 100644
--- a/ui/src/config/section/compute.js
+++ b/ui/src/config/section/compute.js
@@ -18,6 +18,9 @@
import { shallowRef, defineAsyncComponent } from 'vue'
import store from '@/store'
import { isZoneCreated } from '@/utils/zone'
+import { getAPI, postAPI, getBaseUrl } from '@/api'
+import { getLatestKubernetesIsoParams } from '@/utils/acsrepo'
+import kubernetesIcon from '@/assets/icons/kubernetes.svg?inline'
export default {
name: 'compute',
@@ -551,7 +554,7 @@
{
name: 'kubernetes',
title: 'label.kubernetes',
- icon: ['fa-solid', 'fa-dharmachakra'],
+ icon: kubernetesIcon,
docHelp: 'plugins/cloudstack-kubernetes-service.html',
searchFilters: ['name', 'domainid', 'account', 'state'],
permission: ['listKubernetesClusters'],
@@ -581,6 +584,182 @@
}
],
resourceType: 'KubernetesCluster',
+ advisories: [
+ {
+ id: 'cks-min-offering',
+ severity: 'warning',
+ message: 'message.advisory.cks.min.offering',
+ docsHelp: 'plugins/cloudstack-kubernetes-service.html',
+ dismissOnConditionFail: true,
+ condition: async (store) => {
+ if (!('listServiceOfferings' in store.getters.apis)) {
+ return false
+ }
+ const params = {
+ cpunumber: 2,
+ memory: 2048,
+ issystem: false
+ }
+ try {
+ const json = await getAPI('listServiceOfferings', params)
+ const offerings = json?.listserviceofferingsresponse?.serviceoffering || []
+ return !offerings.some(o => !o.iscustomized)
+ } catch (error) {}
+ return false
+ },
+ actions: [
+ {
+ primary: true,
+ label: 'label.add.minimum.required.compute.offering',
+ loadingLabel: 'message.adding.minimum.required.compute.offering.kubernetes.cluster',
+ show: (store) => { return ('createServiceOffering' in store.getters.apis) },
+ run: async () => {
+ const params = {
+ name: 'CKS Instance',
+ cpunumber: 2,
+ cpuspeed: 1000,
+ memory: 2048,
+ iscustomized: false,
+ issystem: false
+ }
+ try {
+ const json = await postAPI('createServiceOffering', params)
+ if (json?.createserviceofferingresponse?.serviceoffering) {
+ return true
+ }
+ } catch (error) {}
+ return false
+ },
+ successMessage: 'message.added.minimum.required.compute.offering.kubernetes.cluster',
+ errorMessage: 'message.add.minimum.required.compute.offering.kubernetes.cluster.failed'
+ },
+ {
+ label: 'label.go.to.compute.offerings',
+ show: (store) => { return ('listServiceOfferings' in store.getters.apis) },
+ run: (store, router) => {
+ router.push({ name: 'computeoffering' })
+ return false
+ }
+ }
+ ]
+ },
+ {
+ id: 'cks-version-check',
+ severity: 'warning',
+ message: 'message.advisory.cks.version.check',
+ docsHelp: 'plugins/cloudstack-kubernetes-service.html',
+ dismissOnConditionFail: true,
+ condition: async (store) => {
+ const api = 'listKubernetesSupportedVersions'
+ if (!(api in store.getters.apis)) {
+ return false
+ }
+ try {
+ const json = await getAPI(api, {})
+ const versions = json?.listkubernetessupportedversionsresponse?.kubernetessupportedversion || []
+ return versions.length === 0
+ } catch (error) {}
+ return false
+ },
+ actions: [
+ {
+ primary: true,
+ label: 'label.add.latest.kubernetes.iso',
+ loadingLabel: 'message.adding.latest.kubernetes.iso',
+ show: (store) => { return ('addKubernetesSupportedVersion' in store.getters.apis) },
+ run: async () => {
+ let arch = 'x86_64'
+ if ('listClusters' in store.getters.apis) {
+ try {
+ const json = await getAPI('listClusters', { allocationstate: 'Enabled', page: 1, pagesize: 1 })
+ const cluster = json?.listclustersresponse?.cluster?.[0] || {}
+ arch = cluster.architecture || 'x86_64'
+ } catch (error) {}
+ }
+ const params = await getLatestKubernetesIsoParams(arch)
+ try {
+ const json = await postAPI('addKubernetesSupportedVersion', params)
+ if (json?.addkubernetessupportedversionresponse?.kubernetessupportedversion) {
+ return true
+ }
+ } catch (error) {}
+ return false
+ },
+ successMessage: 'message.added.latest.kubernetes.iso',
+ errorMessage: 'message.add.latest.kubernetes.iso.failed'
+ },
+ {
+ label: 'label.go.to.kubernetes.isos',
+ show: true,
+ run: (store, router) => {
+ router.push({ name: 'kubernetesiso' })
+ return false
+ }
+ }
+ ]
+ },
+ {
+ id: 'cks-endpoint-url',
+ severity: 'warning',
+ message: 'message.advisory.cks.endpoint.url.not.configured',
+ docsHelp: 'plugins/cloudstack-kubernetes-service.html',
+ dismissOnConditionFail: true,
+ condition: async (store) => {
+ if (!['Admin'].includes(store.getters.userInfo.roletype)) {
+ return false
+ }
+ let url = ''
+ const baseUrl = getBaseUrl()
+ if (baseUrl.startsWith('/')) {
+ url = window.location.origin + baseUrl
+ }
+ if (!url || url.startsWith('http://localhost')) {
+ return false
+ }
+ const params = {
+ name: 'endpoint.url'
+ }
+ const json = await getAPI('listConfigurations', params)
+ const configuration = json?.listconfigurationsresponse?.configuration?.[0] || {}
+ return !configuration.value || configuration.value.startsWith('http://localhost')
+ },
+ actions: [
+ {
+ primary: true,
+ label: 'label.fix.global.setting',
+ show: (store) => { return ('updateConfiguration' in store.getters.apis) },
+ run: async () => {
+ let url = ''
+ const baseUrl = getBaseUrl()
+ if (baseUrl.startsWith('/')) {
+ url = window.location.origin + baseUrl
+ }
+ const params = {
+ name: 'endpoint.url',
+ value: url
+ }
+ try {
+ const json = await postAPI('updateConfiguration', params)
+ if (json?.updateconfigurationresponse?.configuration) {
+ return true
+ }
+ } catch (error) {}
+ return false
+ },
+ successMessage: 'message.global.setting.updated',
+ errorMessage: 'message.global.setting.update.failed'
+ },
+ {
+ label: 'label.go.to.global.settings',
+ show: (store) => { return ('listConfigurations' in store.getters.apis) },
+ run: (store, router) => {
+ router.push({ name: 'globalsetting' })
+ return false
+ }
+ }
+ ]
+ }
+ ],
actions: [
{
api: 'createKubernetesCluster',
diff --git a/ui/src/config/section/domain.js b/ui/src/config/section/domain.js
index fbe20ef..706cbf8 100644
--- a/ui/src/config/section/domain.js
+++ b/ui/src/config/section/domain.js
@@ -144,7 +144,7 @@
docHelp: 'adminguide/accounts.html#using-an-ldap-server-for-user-authentication',
listView: true,
dataView: true,
- args: ['type', 'domainid', 'name', 'accounttype', 'admin'],
+ args: ['type', 'domainid', 'ldapdomain', 'accounttype', 'admin'],
mapping: {
type: {
options: ['GROUP', 'OU']
@@ -158,6 +158,20 @@
}
},
{
+ api: 'unlinkDomainFromLdap',
+ icon: 'ArrowsAltOutlined',
+ label: 'label.unlink.domain.from.ldap',
+ docHelp: 'adminguide/accounts.html#using-an-ldap-server-for-user-authentication',
+ listView: true,
+ dataView: true,
+ args: ['domainid'],
+ mapping: {
+ domainid: {
+ value: (record) => { return record.id }
+ }
+ }
+ },
+ {
api: 'deleteDomain',
icon: 'delete-outlined',
label: 'label.action.delete.domain',
diff --git a/ui/src/config/section/image.js b/ui/src/config/section/image.js
index d93e27c..bae4a40 100644
--- a/ui/src/config/section/image.js
+++ b/ui/src/config/section/image.js
@@ -18,6 +18,7 @@
import { shallowRef, defineAsyncComponent } from 'vue'
import store from '@/store'
import { isZoneCreated } from '@/utils/zone'
+import kubernetesIcon from '@/assets/icons/kubernetes.svg?inline'
export default {
name: 'image',
@@ -367,7 +368,7 @@
{
name: 'kubernetesiso',
title: 'label.kubernetes.isos',
- icon: ['fa-solid', 'fa-dharmachakra'],
+ icon: kubernetesIcon,
docHelp: 'plugins/cloudstack-kubernetes-service.html#kubernetes-supported-versions',
permission: ['listKubernetesSupportedVersions'],
searchFilters: ['zoneid', 'minimumsemanticversion', 'arch'],
diff --git a/ui/src/config/section/infra/systemVms.js b/ui/src/config/section/infra/systemVms.js
index 6e135cc..4a5879b 100644
--- a/ui/src/config/section/infra/systemVms.js
+++ b/ui/src/config/section/infra/systemVms.js
@@ -26,7 +26,7 @@
permission: ['listSystemVms'],
searchFilters: ['name', 'zoneid', 'podid', 'hostid', 'systemvmtype', 'storageid', 'arch'],
columns: ['name', 'state', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'version', 'hostname', 'arch', 'zonename'],
- details: ['name', 'id', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'gateway', 'hostname', 'arch', 'version', 'zonename', 'created', 'activeviewersessions', 'isdynamicallyscalable', 'hostcontrolstate'],
+ details: ['name', 'id', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'gateway', 'hostname', 'arch', 'version', 'zonename', 'created', 'activeviewersessions', 'isdynamicallyscalable', 'hostcontrolstate', 'storageip'],
resourceType: 'SystemVm',
filters: () => {
const filters = ['starting', 'running', 'stopping', 'stopped', 'destroyed', 'expunging', 'migrating', 'error', 'unknown', 'shutdown']
diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js
index acc7424..33b39d2 100644
--- a/ui/src/config/section/network.js
+++ b/ui/src/config/section/network.js
@@ -1266,15 +1266,11 @@
{
api: 'updateVpnCustomerGateway',
icon: 'edit-outlined',
- label: 'label.edit',
+ label: 'label.update.vpn.customer.gateway',
docHelp: 'adminguide/networking_and_traffic.html#updating-and-removing-a-vpn-customer-gateway',
dataView: true,
- args: ['name', 'gateway', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'ikelifetime', 'ikeversion', 'esppolicy', 'esplifetime', 'dpd', 'splitconnections', 'forceencap'],
- mapping: {
- ikeversion: {
- options: ['ike', 'ikev1', 'ikev2']
- }
- }
+ popup: true,
+ component: shallowRef(defineAsyncComponent(() => import('@/views/network/UpdateVpnCustomerGateway.vue')))
},
{
api: 'deleteVpnCustomerGateway',
diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js
index 4a32619..bc95772 100644
--- a/ui/src/config/section/offering.js
+++ b/ui/src/config/section/offering.js
@@ -340,9 +340,9 @@
icon: 'cloud-upload-outlined',
docHelp: 'adminguide/virtual_machines.html#backup-offerings',
permission: ['listBackupOfferings'],
- searchFilters: ['zoneid'],
- columns: ['name', 'description', 'zonename'],
- details: ['name', 'id', 'description', 'externalid', 'zone', 'allowuserdrivenbackups', 'created'],
+ searchFilters: ['zoneid', 'domainid'],
+ columns: ['name', 'description', 'domain', 'zonename'],
+ details: ['name', 'id', 'description', 'externalid', 'domain', 'zone', 'allowuserdrivenbackups', 'created'],
related: [{
name: 'vm',
title: 'label.instances',
diff --git a/ui/src/config/section/tools.js b/ui/src/config/section/tools.js
index a07228c..5b7f4b9 100644
--- a/ui/src/config/section/tools.js
+++ b/ui/src/config/section/tools.js
@@ -117,6 +117,10 @@
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
},
{
+ name: 'filters',
+ component: shallowRef(defineAsyncComponent(() => import('@/components/view/WebhookFiltersTab.vue')))
+ },
+ {
name: 'recent.deliveries',
component: shallowRef(defineAsyncComponent(() => import('@/components/view/WebhookDeliveriesTab.vue')))
}
diff --git a/ui/src/utils/acsrepo/index.js b/ui/src/utils/acsrepo/index.js
new file mode 100644
index 0000000..809bd7f
--- /dev/null
+++ b/ui/src/utils/acsrepo/index.js
@@ -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.
+
+const BASE_KUBERNETES_ISO_URL = 'https://download.cloudstack.org/cks/'
+
+function getDefaultLatestKubernetesIsoParams (arch) {
+ return {
+ name: 'v1.33.1-calico-' + arch,
+ semanticversion: '1.33.1',
+ url: BASE_KUBERNETES_ISO_URL + 'setup-v1.33.1-calico-' + arch + '.iso',
+ arch: arch,
+ mincpunumber: 2,
+ minmemory: 2048
+ }
+}
+
+/**
+ * Returns the latest Kubernetes ISO info for the given architecture.
+ * Falls back to a hardcoded default if fetching fails.
+ * @param {string} arch
+ * @returns {Promise<{name: string, semanticversion: string, url: string, arch: string}>}
+ */
+export async function getLatestKubernetesIsoParams (arch) {
+ arch = arch || 'x86_64'
+ try {
+ const html = await fetch(BASE_KUBERNETES_ISO_URL, { cache: 'no-store' }).then(r => r.text())
+
+ const hrefs = [...html.matchAll(/href="([^"]+\.iso)"/gi)].map(m => m[1])
+
+ // Prefer files that explicitly include the arch (e.g. ...-x86_64.iso)
+ let isoHrefs = hrefs.filter(h => new RegExp(`${arch}\\.iso$`, 'i').test(h))
+
+ // Fallback: older files without arch suffix (e.g. setup-1.28.4.iso)
+ if (isoHrefs.length === 0) {
+ isoHrefs = hrefs.filter(h => /setup-\d+\.\d+\.\d+\.iso$/i.test(h))
+ }
+
+ const entries = isoHrefs.map(h => {
+ const m = h.match(/setup-(?:v)?(\d+\.\d+\.\d+)(?:-calico)?(?:-(x86_64|arm64))?/i)
+ return m
+ ? {
+ name: h.replace('.iso', ''),
+ semanticversion: m[1],
+ url: new URL(h, BASE_KUBERNETES_ISO_URL).toString(),
+ arch: m[2] || arch,
+ mincpunumber: 2,
+ minmemory: 2048
+ }
+ : null
+ }).filter(Boolean)
+
+ if (entries.length === 0) throw new Error('No matching ISOs found')
+
+ entries.sort((a, b) => {
+ const pa = a.semanticversion.split('.').map(Number)
+ const pb = b.semanticversion.split('.').map(Number)
+ for (let i = 0; i < 3; i++) {
+ if ((pb[i] ?? 0) !== (pa[i] ?? 0)) return (pb[i] ?? 0) - (pa[i] ?? 0)
+ }
+ return 0
+ })
+
+ return entries[0]
+ } catch {
+ return { ...getDefaultLatestKubernetesIsoParams(arch) }
+ }
+}
diff --git a/ui/src/utils/plugins.js b/ui/src/utils/plugins.js
index 729cef8..b8856c7 100644
--- a/ui/src/utils/plugins.js
+++ b/ui/src/utils/plugins.js
@@ -569,7 +569,8 @@
app.config.globalProperties.$fetchCpuArchitectureTypes = function () {
const architectures = [
{ id: 'x86_64', name: 'Intel/AMD 64 bits (x86_64)' },
- { id: 'aarch64', name: 'ARM 64 bits (aarch64)' }
+ { id: 'aarch64', name: 'ARM 64 bits (aarch64)' },
+ { id: 's390x', name: 'IBM Z 64 bits (s390x)' }
]
return architectures.map(item => ({ ...item, description: item.name }))
}
diff --git a/ui/src/utils/renderIcon.js b/ui/src/utils/renderIcon.js
index 8d982fd..b92fba2 100644
--- a/ui/src/utils/renderIcon.js
+++ b/ui/src/utils/renderIcon.js
@@ -45,8 +45,9 @@
const props = Object.assign({}, this.props)
props.width = '1em'
props.height = '1em'
- props.class = 'custom-icon'
-
+ if (!this.$attrs.style) {
+ props.class = 'custom-icon'
+ }
return h('span', { role: 'img', class: 'anticon' }, [
h(this.svgIcon, { ...props }, this.event)
])
diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue
index a5c0be3..f4aa842 100644
--- a/ui/src/views/AutogenView.vue
+++ b/ui/src/views/AutogenView.vue
@@ -553,6 +553,9 @@
class="row-element"
v-else
>
+ <advisories-view
+ v-if="$route.meta.advisories && !loading"
+ />
<list-view
:loading="loading"
:columns="columns"
@@ -618,6 +621,7 @@
import BulkActionProgress from '@/components/view/BulkActionProgress'
import TooltipLabel from '@/components/widgets/TooltipLabel'
import DetailsInput from '@/components/widgets/DetailsInput'
+import AdvisoriesView from '@/components/view/AdvisoriesView'
export default {
name: 'Resource',
@@ -632,7 +636,8 @@
TooltipLabel,
OsLogo,
ResourceIcon,
- DetailsInput
+ DetailsInput,
+ AdvisoriesView
},
mixins: [mixinDevice],
provide: function () {
diff --git a/ui/src/views/compute/AttachIso.vue b/ui/src/views/compute/AttachIso.vue
index aafed01..60694cb 100644
--- a/ui/src/views/compute/AttachIso.vue
+++ b/ui/src/views/compute/AttachIso.vue
@@ -85,10 +85,10 @@
})
},
fetchData () {
- const isoFiters = ['featured', 'community', 'selfexecutable']
+ const isoFilters = ['featured', 'community', 'selfexecutable']
this.loading = true
const promises = []
- isoFiters.forEach((filter) => {
+ isoFilters.forEach((filter) => {
promises.push(this.fetchIsos(filter))
})
Promise.all(promises).then(() => {
diff --git a/ui/src/views/compute/CreateAutoScaleVmGroup.vue b/ui/src/views/compute/CreateAutoScaleVmGroup.vue
index 362c9b7..9e8ebb8 100644
--- a/ui/src/views/compute/CreateAutoScaleVmGroup.vue
+++ b/ui/src/views/compute/CreateAutoScaleVmGroup.vue
@@ -3172,12 +3172,12 @@
configuration.cpunumber = 0
configuration.cpuspeed = 0
configuration.memory = 0
- for (var harwareItem of configuration.hardwareItems) {
- if (harwareItem.resourceType === 'Processor') {
- configuration.cpunumber = harwareItem.virtualQuantity
- configuration.cpuspeed = harwareItem.reservation
- } else if (harwareItem.resourceType === 'Memory') {
- configuration.memory = harwareItem.virtualQuantity
+ for (var hardwareItem of configuration.hardwareItems) {
+ if (hardwareItem.resourceType === 'Processor') {
+ configuration.cpunumber = hardwareItem.virtualQuantity
+ configuration.cpuspeed = hardwareItem.reservation
+ } else if (hardwareItem.resourceType === 'Memory') {
+ configuration.memory = hardwareItem.virtualQuantity
}
}
configurations.push(configuration)
diff --git a/ui/src/views/compute/CreateKubernetesCluster.vue b/ui/src/views/compute/CreateKubernetesCluster.vue
index 68c7a35..1799933 100644
--- a/ui/src/views/compute/CreateKubernetesCluster.vue
+++ b/ui/src/views/compute/CreateKubernetesCluster.vue
@@ -930,7 +930,7 @@
description: values.name,
loadingMessage: `${this.$t('label.kubernetes.cluster.create')} ${values.name} ${this.$t('label.in.progress')}`,
catchMessage: this.$t('error.fetching.async.job.result'),
- successMessage: this.$t('message.success.create.kubernetes.cluter') + ' ' + values.name
+ successMessage: this.$t('message.success.create.kubernetes.cluster') + ' ' + values.name
})
this.closeAction()
}).catch(error => {
diff --git a/ui/src/views/compute/DeployVM.vue b/ui/src/views/compute/DeployVM.vue
index 1966203..26176e7 100644
--- a/ui/src/views/compute/DeployVM.vue
+++ b/ui/src/views/compute/DeployVM.vue
@@ -1920,7 +1920,7 @@
}
this.fetchBootTypes()
this.fetchBootModes()
- this.fetchInstaceGroups()
+ this.fetchInstanceGroups()
this.fetchIoPolicyTypes()
nextTick().then(() => {
['name', 'keyboard', 'boottype', 'bootmode', 'userdata', 'iothreadsenabled', 'iodriverpolicy', 'nicmultiqueuenumber', 'nicpackedvirtqueues'].forEach(this.fillValue)
@@ -1976,7 +1976,7 @@
{ id: 'storage_specific', description: 'storage_specific' }
]
},
- fetchInstaceGroups () {
+ fetchInstanceGroups () {
this.options.instanceGroups = []
getAPI('listInstanceGroups', {
account: this.$store.getters.project?.id ? null : this.$store.getters.userInfo.account,
@@ -3226,12 +3226,12 @@
configuration.cpunumber = 0
configuration.cpuspeed = 0
configuration.memory = 0
- for (var harwareItem of configuration.hardwareItems) {
- if (harwareItem.resourceType === 'Processor') {
- configuration.cpunumber = harwareItem.virtualQuantity
- configuration.cpuspeed = harwareItem.reservation
- } else if (harwareItem.resourceType === 'Memory') {
- configuration.memory = harwareItem.virtualQuantity
+ for (var hardwareItem of configuration.hardwareItems) {
+ if (hardwareItem.resourceType === 'Processor') {
+ configuration.cpunumber = hardwareItem.virtualQuantity
+ configuration.cpuspeed = hardwareItem.reservation
+ } else if (hardwareItem.resourceType === 'Memory') {
+ configuration.memory = hardwareItem.virtualQuantity
}
}
configurations.push(configuration)
diff --git a/ui/src/views/compute/DeployVnfAppliance.vue b/ui/src/views/compute/DeployVnfAppliance.vue
index 36fdd86..be15422 100644
--- a/ui/src/views/compute/DeployVnfAppliance.vue
+++ b/ui/src/views/compute/DeployVnfAppliance.vue
@@ -1768,7 +1768,7 @@
}
this.fetchBootTypes()
this.fetchBootModes()
- this.fetchInstaceGroups()
+ this.fetchInstanceGroups()
this.fetchIoPolicyTypes()
nextTick().then(() => {
['name', 'keyboard', 'boottype', 'bootmode', 'userdata', 'iothreadsenabled', 'iodriverpolicy', 'nicmultiqueuenumber', 'nicpackedvirtqueues'].forEach(this.fillValue)
@@ -1823,7 +1823,7 @@
{ id: 'storage_specific', description: 'storage_specific' }
]
},
- fetchInstaceGroups () {
+ fetchInstanceGroups () {
this.options.instanceGroups = []
getAPI('listInstanceGroups', {
account: this.$store.getters.userInfo.account,
@@ -2777,12 +2777,12 @@
configuration.cpunumber = 0
configuration.cpuspeed = 0
configuration.memory = 0
- for (var harwareItem of configuration.hardwareItems) {
- if (harwareItem.resourceType === 'Processor') {
- configuration.cpunumber = harwareItem.virtualQuantity
- configuration.cpuspeed = harwareItem.reservation
- } else if (harwareItem.resourceType === 'Memory') {
- configuration.memory = harwareItem.virtualQuantity
+ for (var hardwareItem of configuration.hardwareItems) {
+ if (hardwareItem.resourceType === 'Processor') {
+ configuration.cpunumber = hardwareItem.virtualQuantity
+ configuration.cpuspeed = hardwareItem.reservation
+ } else if (hardwareItem.resourceType === 'Memory') {
+ configuration.memory = hardwareItem.virtualQuantity
}
}
configurations.push(configuration)
diff --git a/ui/src/views/compute/EditVM.vue b/ui/src/views/compute/EditVM.vue
index 0763303..9f08a33 100644
--- a/ui/src/views/compute/EditVM.vue
+++ b/ui/src/views/compute/EditVM.vue
@@ -255,7 +255,7 @@
this.fetchZoneDetails()
this.fetchSecurityGroups()
this.fetchOsTypes()
- this.fetchInstaceGroups()
+ this.fetchInstanceGroups()
this.fetchServiceOfferingData()
this.fetchTemplateData()
this.fetchUserData()
@@ -335,7 +335,7 @@
this.$notifyError(error)
}).finally(() => { this.osTypes.loading = false })
},
- fetchInstaceGroups () {
+ fetchInstanceGroups () {
this.groups.loading = true
this.groups.opts = []
const params = {
@@ -425,6 +425,8 @@
}
if (values.extraconfig && values.extraconfig.length > 0) {
params.extraconfig = encodeURIComponent(values.extraconfig)
+ } else if (this.combinedExtraConfig) {
+ params.cleanupextraconfig = true
}
this.loading = true
diff --git a/ui/src/views/compute/ReinstallVm.vue b/ui/src/views/compute/ReinstallVm.vue
index 5238252..4cb6317 100644
--- a/ui/src/views/compute/ReinstallVm.vue
+++ b/ui/src/views/compute/ReinstallVm.vue
@@ -1,17 +1,17 @@
// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
+// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
+// 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
+// with the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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
+// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
diff --git a/ui/src/views/compute/wizard/OsBasedImageSelection.vue b/ui/src/views/compute/wizard/OsBasedImageSelection.vue
index 6a52eea..6809227 100644
--- a/ui/src/views/compute/wizard/OsBasedImageSelection.vue
+++ b/ui/src/views/compute/wizard/OsBasedImageSelection.vue
@@ -47,7 +47,7 @@
@change="handleGuestOsCategoryChange">
<template #radio-option="{ item }">
<div class="radio-option">
- <div class="radio-opion__icon">
+ <div class="radio-option__icon">
<resource-icon v-if="item.icon && item.icon.base64image" :image="item.icon.base64image" size="os" style="margin-bottom: 2px; margin-left: 1px" />
<font-awesome-icon v-else-if="['-1', '0'].includes(item.id)" :icon="['fas', item.id === '0' ? 'user' : 'images']" size="2x" :style="categoryFontAwesomeIconStyle" />
<os-logo v-else size="2x" :os-name="item.name" />
@@ -367,7 +367,7 @@
text-overflow: ellipsis;
}
- .radio-opion__icon {
+ .radio-option__icon {
width: 30px;
height: 30px;
object-fit: contain;
diff --git a/ui/src/views/extension/CreateExtension.vue b/ui/src/views/extension/CreateExtension.vue
index 9a7e0c8..6311e6d 100644
--- a/ui/src/views/extension/CreateExtension.vue
+++ b/ui/src/views/extension/CreateExtension.vue
@@ -47,8 +47,8 @@
<tooltip-label :title="$t('label.path')" :tooltip="apiParams.path.description"/>
</template>
<div class="path-input-container">
- <span v-if="!!safeName" :title="extenstionBasePath" class="path-input-base">
- {{ extenstionBasePath }}
+ <span v-if="!!safeName" :title="extensionBasePath" class="path-input-base">
+ {{ extensionBasePath }}
</span>
<a-input
v-model:value="form.path"
@@ -137,7 +137,7 @@
}
return value.replace(/[^a-zA-Z0-9._-]/g, '_').toLowerCase()
},
- extenstionBasePath () {
+ extensionBasePath () {
return (this.$store.getters.features.extensionspath || '[EXTENSIONS_PATH]') + '/' + this.safeName + '/'
}
},
diff --git a/ui/src/views/extension/UpdateCustomAction.vue b/ui/src/views/extension/UpdateCustomAction.vue
index 008882a..70ed677 100644
--- a/ui/src/views/extension/UpdateCustomAction.vue
+++ b/ui/src/views/extension/UpdateCustomAction.vue
@@ -138,7 +138,7 @@
this.roleTypes = this.$fetchCustomActionRoleTypes()
},
methods: {
- fixParamatersOptions (params) {
+ fixParametersOptions (params) {
if (!params) {
return
}
@@ -153,7 +153,7 @@
initForm () {
this.formRef = ref()
const formData = {
- parameters: this.fixParamatersOptions(this.resource.parameters)
+ parameters: this.fixParametersOptions(this.resource.parameters)
}
const keys = ['description', 'allowedroletypes', 'successmessage', 'errormessage', 'details', 'timeout']
for (const key of keys) {
diff --git a/ui/src/views/iam/AddAccount.vue b/ui/src/views/iam/AddAccount.vue
index 9118a61..25b45cd 100644
--- a/ui/src/views/iam/AddAccount.vue
+++ b/ui/src/views/iam/AddAccount.vue
@@ -114,6 +114,7 @@
:placeholder="apiParams.domainid.description"
showSearch
optionFilterProp="label"
+ @change="onDomainChange"
:filterOption="(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}" >
@@ -207,8 +208,9 @@
this.fetchTimeZone = debounce(this.fetchTimeZone, 800)
return {
loading: false,
- domain: { loading: false },
+ domain: { id: null, loading: false },
domainsList: [],
+ dom: null,
roleLoading: false,
roles: [],
timeZoneLoading: false,
@@ -227,14 +229,35 @@
computed: {
samlAllowed () {
return 'authorizeSamlSso' in this.$store.getters.apis
+ },
+ selectedDomain () {
+ return this.domainsList.find(domain => domain.id === this.form.domainid)
+ },
+ isNonRootDomain () {
+ if (!this.selectedDomain) return false
+ return this.selectedDomain.level > 0 && this.selectedDomain.path !== 'ROOT'
+ }
+ },
+ watch: {
+ 'form.domainid': {
+ handler (newDomainId, oldDomainId) {
+ if (newDomainId && this.roles.length > 0) {
+ this.$nextTick(() => {
+ this.setDefaultRole()
+ })
+ }
+ },
+ immediate: false
}
},
methods: {
initForm () {
+ var domId = this.$route.query.domainid || this.$store.getters.userInfo.domainid
this.formRef = ref()
this.form = reactive({
- domainid: this.$store.getters.userInfo.domainid
+ domainid: domId
})
+ this.domain.id = domId
this.rules = reactive({
roleid: [{ required: true, message: this.$t('message.error.select') }],
username: [{ required: true, message: this.$t('message.error.required.input') }],
@@ -263,9 +286,36 @@
isDomainAdmin () {
return this.$store.getters.userInfo.roletype === 'DomainAdmin'
},
+ isAdmin () {
+ return this.$store.getters.userInfo.roletype === 'Admin'
+ },
isValidValueForKey (obj, key) {
return key in obj && obj[key] != null
},
+ onDomainChange (newDomainId) {
+ if (newDomainId && this.roles.length > 0) {
+ this.$nextTick(() => {
+ this.setDefaultRole()
+ })
+ }
+ },
+ setDefaultRole () {
+ if (this.roles.length === 0) return
+
+ let targetRoleType = null
+
+ if (this.isAdmin()) {
+ targetRoleType = this.isNonRootDomain ? 'DomainAdmin' : 'Admin'
+ } else if (this.isDomainAdmin()) {
+ targetRoleType = 'User'
+ }
+
+ const targetRole = targetRoleType
+ ? this.roles.find(role => role.type === targetRoleType)
+ : this.roles[0]
+
+ this.form.roleid = (targetRole || this.roles[0]).id
+ },
async validateConfirmPassword (rule, value) {
if (!value || value.length === 0) {
return Promise.resolve()
@@ -286,17 +336,22 @@
this.loadMore('listDomains', 1, this.domain)
},
loadMore (apiToCall, page, sema) {
- console.log('sema.loading ' + sema.loading)
- const params = {}
- params.listAll = true
- params.details = 'min'
- params.pagesize = 100
- params.page = page
+ const params = {
+ listAll: true,
+ details: 'min',
+ pagesize: 100,
+ page: page
+ }
var count
getAPI(apiToCall, params).then(json => {
const listDomains = json.listdomainsresponse.domain
count = json.listdomainsresponse.count
this.domainsList = this.domainsList.concat(listDomains)
+ this.dom = this.domainsList.find(domain => domain.id === this.domain.id)
+
+ if (this.roles.length > 0) {
+ this.setDefaultRole()
+ }
}).finally(() => {
if (count <= this.domainsList.length) {
sema.loading = false
@@ -307,17 +362,13 @@
},
fetchRoles () {
this.roleLoading = true
- const params = {}
- params.state = 'enabled'
+ const params = {
+ state: 'enabled'
+ }
+
getAPI('listRoles', params).then(response => {
this.roles = response.listrolesresponse.role || []
- this.form.roleid = this.roles[0].id
- if (this.isDomainAdmin()) {
- const userRole = this.roles.filter(role => role.type === 'User')
- if (userRole.length > 0) {
- this.form.roleid = userRole[0].id
- }
- }
+ this.setDefaultRole()
}).finally(() => {
this.roleLoading = false
})
diff --git a/ui/src/views/iam/CreateRole.vue b/ui/src/views/iam/CreateRole.vue
index 11cecf6..eac138f 100644
--- a/ui/src/views/iam/CreateRole.vue
+++ b/ui/src/views/iam/CreateRole.vue
@@ -202,7 +202,7 @@
this.$emit('refresh-data')
this.$notification.success({
message: 'Create Role',
- description: 'Sucessfully created role ' + params.name
+ description: 'Successfully created role ' + params.name
})
}
this.closeAction()
diff --git a/ui/src/views/iam/ImportRole.vue b/ui/src/views/iam/ImportRole.vue
index c4dcf8f..7a8e17c 100644
--- a/ui/src/views/iam/ImportRole.vue
+++ b/ui/src/views/iam/ImportRole.vue
@@ -213,7 +213,7 @@
this.$emit('refresh-data')
this.$notification.success({
message: 'Import Role',
- description: 'Sucessfully imported role ' + params.name
+ description: 'Successfully imported role ' + params.name
})
}
this.closeAction()
diff --git a/ui/src/views/infra/ClusterUpdate.vue b/ui/src/views/infra/ClusterUpdate.vue
index 1af7f42..590abe6 100644
--- a/ui/src/views/infra/ClusterUpdate.vue
+++ b/ui/src/views/infra/ClusterUpdate.vue
@@ -168,6 +168,10 @@
id: 'aarch64',
description: 'ARM 64 bits (aarch64)'
})
+ typesList.push({
+ id: 's390x',
+ description: 'IBM Z 64 bits (s390x)'
+ })
this.architectureTypes.opts = typesList
},
fetchExtensionResourceMapDetails () {
diff --git a/ui/src/views/infra/Resources.vue b/ui/src/views/infra/Resources.vue
index cad1a02..0055343 100644
--- a/ui/src/views/infra/Resources.vue
+++ b/ui/src/views/infra/Resources.vue
@@ -35,7 +35,7 @@
v-if="item.tagged"
class="list-item__collapse"
@change="handleCollapseChange(item.type)">
- <a-collapse-panel key="1" :header="$t('label.tagged') + ' ' + returnCapacityTitle(item.type) + (collpaseActive[item.type] ? '' : ' - ' + item.tagsasstring)">
+ <a-collapse-panel key="1" :header="$t('label.tagged') + ' ' + returnCapacityTitle(item.type) + (collapseActive[item.type] ? '' : ' - ' + item.tagsasstring)">
<a-list
size="small"
:dataSource="item.tagged" >
@@ -90,7 +90,7 @@
return {
fetchLoading: false,
resourcesList: [],
- collpaseActive: {}
+ collapseActive: {}
}
},
created () {
@@ -181,11 +181,11 @@
}
},
handleCollapseChange (type) {
- if (this.collpaseActive[type]) {
- this.collpaseActive[type] = null
+ if (this.collapseActive[type]) {
+ this.collapseActive[type] = null
return
}
- this.collpaseActive[type] = true
+ this.collapseActive[type] = true
var typeItems = this.resourcesList.filter(x => x.type === type)
typeItems.forEach(resource => {
this.animatePercentVals(resource.tagged)
diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue
index 81f5656..dc6ef67 100644
--- a/ui/src/views/infra/network/IpRangesTabPublic.vue
+++ b/ui/src/views/infra/network/IpRangesTabPublic.vue
@@ -47,6 +47,9 @@
<template v-if="column.key === 'endip'">
{{ record.endip || record.endipv6 }}
</template>
+ <template v-if="column.key === 'systemvms'">
+ {{ record.systemvms || record.forsystemvms }}
+ </template>
<template v-if="column.key === 'account' && !basicGuestNetwork">
<a-button @click="() => handleOpenAccountModal(record)">{{ record.domain === undefined ? `${$t('label.system.ip.pool')}` : `[ ${record.domain}] ${record.account === undefined ? '' : record.account}` }}</a-button>
</template>
@@ -128,10 +131,6 @@
<div class="list__label">{{ $t('label.domain') }}</div>
<div>{{ selectedItem.domain }}</div>
</div>
- <div style="margin-bottom: 10px;">
- <div class="list__label">{{ $t('label.system.vms') }}</div>
- <div>{{ selectedItem.forsystemvms }}</div>
- </div>
</div>
<div :span="24" class="action-button">
@@ -450,6 +449,10 @@
title: this.$t('label.endip')
},
{
+ key: 'systemvms',
+ title: this.$t('label.reserved.system.ip')
+ },
+ {
key: 'actions',
title: this.$t('label.actions')
}
diff --git a/ui/src/views/infra/routers/RouterHealthCheck.vue b/ui/src/views/infra/routers/RouterHealthCheck.vue
index 89a05d1..0fe49c3 100644
--- a/ui/src/views/infra/routers/RouterHealthCheck.vue
+++ b/ui/src/views/infra/routers/RouterHealthCheck.vue
@@ -22,7 +22,7 @@
banner
:message="$t('message.action.router.health.checks.disabled.warning')" />
<div v-else>
- <a-button :disabled="!('getRouterHealthCheckResults' in $store.getters.apis)" type="primary" style="width: 100%; margin-bottom: 15px" @click="showGetHelathCheck">
+ <a-button :disabled="!('getRouterHealthCheckResults' in $store.getters.apis)" type="primary" style="width: 100%; margin-bottom: 15px" @click="showGetHealthCheck">
<template #icon><play-circle-outlined /></template>
{{ $t('label.action.router.health.checks') }}
</a-button>
@@ -158,7 +158,7 @@
}
this.checkConfigurationAndGetHealthChecks()
},
- showGetHelathCheck () {
+ showGetHealthCheck () {
this.showGetHealthChecksForm = true
},
onCloseGetHealthChecksForm () {
diff --git a/ui/src/views/infra/zone/ZoneWizardAddResources.vue b/ui/src/views/infra/zone/ZoneWizardAddResources.vue
index 32b7b10..3189869 100644
--- a/ui/src/views/infra/zone/ZoneWizardAddResources.vue
+++ b/ui/src/views/infra/zone/ZoneWizardAddResources.vue
@@ -872,6 +872,9 @@
}, {
id: 'aarch64',
description: 'ARM 64 bits (aarch64)'
+ }, {
+ id: 's390x',
+ description: 'IBM Z 64 bits (s390x)'
}],
storageProviders: [],
currentStep: null,
diff --git a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue
index 7406be4..e16afbc 100644
--- a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue
+++ b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue
@@ -1609,7 +1609,7 @@
try {
if (!this.stepData.stepMove.includes('createStoragePool')) {
- this.stepData.primaryStorageRetunred = await this.createStoragePool(params)
+ this.stepData.primaryStorageReturned = await this.createStoragePool(params)
this.stepData.stepMove.push('createStoragePool')
}
await this.stepAddSecondaryStorage()
diff --git a/ui/src/views/infra/zone/ZoneWizardRegisterTemplate.vue b/ui/src/views/infra/zone/ZoneWizardRegisterTemplate.vue
index 0d94fc5..40123a5 100644
--- a/ui/src/views/infra/zone/ZoneWizardRegisterTemplate.vue
+++ b/ui/src/views/infra/zone/ZoneWizardRegisterTemplate.vue
@@ -201,7 +201,7 @@
if (successful.length > 0) {
this.$notification.success({
message: this.$t('label.register.template'),
- description: 'Succesfully registered templates: ' + successful.map(r => r.name).join(', ')
+ description: 'Successfully registered templates: ' + successful.map(r => r.name).join(', ')
})
successful.forEach(r => {
diff --git a/ui/src/views/network/CreateVpnCustomerGateway.vue b/ui/src/views/network/CreateVpnCustomerGateway.vue
index f71fc47..155765a 100644
--- a/ui/src/views/network/CreateVpnCustomerGateway.vue
+++ b/ui/src/views/network/CreateVpnCustomerGateway.vue
@@ -15,352 +15,58 @@
// specific language governing permissions and limitations
// under the License.
<template>
- <div>
- <a-form
- class="form-layout"
- :ref="formRef"
- :model="form"
- :rules="rules"
- layout="vertical"
- @finish="handleSubmit"
- v-ctrl-enter="handleSubmit"
- >
- <a-form-item ref="name" name="name">
- <template #label>
- <tooltip-label :title="$t('label.name')" :tooltip="apiParams.name.description"/>
- </template>
- <a-input
- v-model:value="form.name"
- :placeholder="apiParams.name.description"
- v-focus="true" />
- </a-form-item>
- <a-form-item ref="gateway" name="gateway">
- <template #label>
- <tooltip-label :title="$t('label.gateway')" :tooltip="apiParams.gateway.description"/>
- </template>
- <a-input
- v-model:value="form.gateway"
- :placeholder="apiParams.gateway.description" />
- </a-form-item>
- <a-form-item ref="cidrlist" name="cidrlist">
- <template #label>
- <tooltip-label :title="$t('label.cidrlist')" :tooltip="apiParams.cidrlist.description"/>
- </template>
- <a-input
- v-model:value="form.cidrlist"
- :placeholder="apiParams.cidrlist.description" />
- </a-form-item>
- <a-form-item ref="ipsecpsk" name="ipsecpsk">
- <template #label>
- <tooltip-label :title="$t('label.ipsecpsk')" :tooltip="apiParams.ipsecpsk.description"/>
- </template>
- <a-input
- v-model:value="form.ipsecpsk"
- :placeholder="apiParams.ipsecpsk.description" />
- </a-form-item>
- <a-form-item ref="ikeEncryption" name="ikeEncryption" :label="$t('label.ikeencryption')">
- <a-select
- v-model:value="form.ikeEncryption"
- showSearch
- optionFilterProp="value"
- :filterOption="(input, option) => {
- return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
- }" >
- <a-select-option :value="algo" v-for="(algo, idx) in encryptionAlgo" :key="idx">
- {{ algo }}
- </a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item ref="ikeHash" name="ikeHash" :label="$t('label.ikehash')">
- <a-select
- v-model:value="form.ikeHash"
- showSearch
- optionFilterProp="value"
- :filterOption="(input, option) => {
- return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
- }" >
- <a-select-option :value="h" v-for="(h, idx) in hash" :key="idx">
- {{ h }}
- </a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item ref="ikeversion" name="ikeversion">
- <template #label>
- <tooltip-label :title="$t('label.ikeversion')" :tooltip="apiParams.ikeversion.description"/>
- </template>
- <a-select
- v-model:value="form.ikeversion"
- showSearch
- optionFilterProp="value"
- :filterOption="(input, option) => {
- return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
- }" >
- <a-select-option :value="vers" v-for="(vers, idx) in ikeVersions" :key="idx">
- {{ vers }}
- </a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item ref="ikeDh" name="ikeDh" :label="$t('label.ikedh')">
- <a-select
- v-model:value="form.ikeDh"
- showSearch
- optionFilterProp="label"
- :filterOption="(input, option) => {
- return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
- }" >
- <a-select-option
- :value="DHGroups[group]"
- v-for="(group, idx) in Object.keys(DHGroups)"
- :key="idx"
- :label="group + '(' + DHGroups[group] + ')'">
- <div v-if="group !== ''">
- {{ group+"("+DHGroups[group]+")" }}
- </div>
- </a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item ref="espEncryption" name="espEncryption" :label="$t('label.espencryption')">
- <a-select
- v-model:value="form.espEncryption"
- showSearch
- optionFilterProp="value"
- :filterOption="(input, option) => {
- return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
- }" >
- <a-select-option :value="algo" v-for="(algo, idx) in encryptionAlgo" :key="idx">
- {{ algo }}
- </a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item ref="espHash" name="espHash" :label="$t('label.esphash')">
- <a-select
- v-model:value="form.espHash"
- showSearch
- optionFilterProp="value"
- :filterOption="(input, option) => {
- return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
- }" >
- <a-select-option :value="h" v-for="(h, idx) in hash" :key="idx">
- {{ h }}
- </a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item ref="perfectForwardSecrecy" name="perfectForwardSecrecy" :label="$t('label.perfectforwardsecrecy')">
- <a-select
- v-model:value="form.perfectForwardSecrecy"
- showSearch
- optionFilterProp="label"
- :filterOption="(input, option) => {
- return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
- }" >
- <a-select-option
- :value="DHGroups[group]"
- v-for="(group, idx) in Object.keys(DHGroups)"
- :key="idx"
- :label="group === '' ? DHGroups[group] : group + '(' + DHGroups[group] + ')'">
- <div v-if="group === ''">
- {{ DHGroups[group] }}
- </div>
- <div v-else>
- {{ group+"("+DHGroups[group]+")" }}
- </div>
- </a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item ref="ikelifetime" name="ikelifetime">
- <template #label>
- <tooltip-label :title="$t('label.ikelifetime')" :tooltip="apiParams.ikelifetime.description"/>
- </template>
- <a-input
- v-model:value="form.ikelifetime"
- :placeholder="apiParams.ikelifetime.description"/>
- </a-form-item>
- <a-form-item ref="esplifetime" name="esplifetime">
- <template #label>
- <tooltip-label :title="$t('label.esplifetime')" :tooltip="apiParams.esplifetime.description"/>
- </template>
- <a-input
- v-model:value="form.esplifetime"
- :placeholder="apiParams.esplifetime.description"/>
- </a-form-item>
- <a-form-item ref="dpd" name="dpd">
- <template #label>
- <tooltip-label :title="$t('label.dpd')" :tooltip="apiParams.dpd.description"/>
- </template>
- <a-switch v-model:checked="form.dpd"/>
- </a-form-item>
- <a-form-item ref="splitconnections" name="splitconnections" v-if="form.ikeversion !== 'ikev1'">
- <template #label>
- <tooltip-label :title="$t('label.splitconnections')" :tooltip="apiParams.splitconnections.description"/>
- </template>
- <a-switch v-model:checked="form.splitconnections"/>
- </a-form-item>
- <a-form-item ref="forceencap" name="forceencap">
- <template #label>
- <tooltip-label :title="$t('label.forceencap')" :tooltip="apiParams.forceencap.description"/>
- </template>
- <a-switch v-model:checked="form.forceencap"/>
- </a-form-item>
- <div class="action-button">
- <a-button @click="closeModal">
- {{ $t('label.cancel') }}
- </a-button>
- <a-button type="primary" @click="handleSubmit" html-type="submit">
- {{ $t('label.ok') }}
- </a-button>
- </div>
- </a-form>
- </div>
+ <vpn-customer-gateway
+ ref="vpnCustomerGatewayForm"
+ :apiParams="apiParams"
+ @submit="handleSubmit"
+ @cancel="closeModal"
+ />
</template>
+
<script>
-import { ref, reactive, toRaw } from 'vue'
import { postAPI } from '@/api'
-import { mixinForm } from '@/utils/mixin'
-import TooltipLabel from '@/components/widgets/TooltipLabel'
+import VpnCustomerGateway from './VpnCustomerGateway.vue'
export default {
name: 'CreateVpnCustomerGateway',
- mixins: [mixinForm],
components: {
- TooltipLabel
- },
- props: {
- resource: {
- type: Object,
- required: true
- }
- },
- data () {
- return {
- encryptionAlgo: [
- 'aes128',
- 'aes192',
- 'aes256',
- '3des'
- ],
- hash: [
- 'sha1',
- 'sha256',
- 'sha384',
- 'sha512',
- 'md5'
- ],
- ikeVersions: [
- 'ike',
- 'ikev1',
- 'ikev2'
- ],
- DHGroups: {
- '': 'None',
- 'Group 2': 'modp1024',
- 'Group 5': 'modp1536',
- 'Group 14': 'modp2048',
- 'Group 15': 'modp3072',
- 'Group 16': 'modp4096',
- 'Group 17': 'modp6144',
- 'Group 18': 'modp8192'
- },
- ikeDhGroupInitialValue: 'Group 5(modp1536)',
- isSubmitted: false,
- ikeversion: 'ike'
- }
+ VpnCustomerGateway
},
beforeCreate () {
this.apiParams = this.$getApiParams('createVpnCustomerGateway')
},
- created () {
- this.initForm()
- },
methods: {
- initForm () {
- this.formRef = ref()
- this.form = reactive({
- ikeEncryption: 'aes128',
- ikeHash: 'sha1',
- ikeversion: 'ike',
- ikeDh: 'Group 5(modp1536)',
- espEncryption: 'aes128',
- espHash: 'sha1',
- perfectForwardSecrecy: 'None',
- ikelifetime: '86400',
- esplifetime: '3600',
- dpd: false,
- splitconnections: false,
- forceencap: false
- })
- this.rules = reactive({
- name: [{ required: true, message: this.$t('label.required') }],
- gateway: [{ required: true, message: this.$t('label.required') }],
- cidrlist: [{ required: true, message: this.$t('label.required') }],
- ipsecpsk: [{ required: true, message: this.$t('label.required') }]
- })
- },
closeModal () {
this.$emit('close-action')
},
- handleSubmit (e) {
- e.preventDefault()
- if (this.isSubmitted) return
- this.formRef.value.validate().then(() => {
- const formRaw = toRaw(this.form)
- const values = this.handleRemoveFields(formRaw)
- let ikepolicy = values.ikeEncryption + '-' + values.ikeHash + ';'
- ikepolicy += (values.ikeDh !== this.ikeDhGroupInitialValue) ? values.ikeDh : (values.ikeDh.split('(')[1]).split(')')[0]
- let esppolicy = values.espEncryption + '-' + values.espHash
- if (values.perfectForwardSecrecy !== 'None') {
- esppolicy += ';' + (values.perfectForwardSecrecy)
- }
- postAPI('createVpnCustomerGateway', {
- name: values.name,
- gateway: values.gateway,
- cidrlist: values.cidrlist,
- ipsecpsk: values.ipsecpsk,
- ikelifetime: values.ikelifetime,
- esplifetime: values.esplifetime,
- dpd: values.dpd,
- forceencap: values.forceencap,
- ikepolicy: ikepolicy,
- esppolicy: esppolicy,
- splitconnections: values.splitconnections,
- ikeversion: values.ikeversion
- }).then(response => {
- this.$pollJob({
- jobId: response.createvpncustomergatewayresponse.jobid,
- title: this.$t('message.add.vpn.customer.gateway'),
- description: values.name,
- successMessage: this.$t('message.success.add.vpn.customer.gateway'),
- successMethod: () => {
- this.closeModal()
- this.isSubmitted = false
- },
- errorMessage: `${this.$t('message.create.vpn.customer.gateway.failed')} ` + response,
- errorMethod: () => {
- this.closeModal()
- this.isSubmitted = false
- },
- loadingMessage: this.$t('message.add.vpn.customer.gateway.processing'),
- catchMessage: this.$t('error.fetching.async.job.result'),
- catchMethod: () => {
- this.closeModal()
- this.isSubmitted = false
- }
- })
- this.closeModal()
- this.formRef.value.resetFields()
- }).catch(error => {
- console.error(error)
- this.$message.error(this.$t('message.add.vpn.customer.gateway.failed'))
- this.isSubmitted = false
+ handleSubmit ({ payload }) {
+ postAPI('createVpnCustomerGateway', payload).then(response => {
+ this.$pollJob({
+ jobId: response.createvpncustomergatewayresponse.jobid,
+ title: this.$t('message.add.vpn.customer.gateway'),
+ description: payload.name,
+ successMessage: this.$t('message.success.add.vpn.customer.gateway'),
+ successMethod: () => {
+ this.closeModal()
+ },
+ errorMessage: this.$t('message.create.vpn.customer.gateway.failed'),
+ errorMethod: () => {
+ this.closeModal()
+ },
+ loadingMessage: this.$t('message.add.vpn.customer.gateway.processing'),
+ catchMessage: this.$t('error.fetching.async.job.result'),
+ catchMethod: () => {
+ this.closeModal()
+ }
})
+ this.closeModal()
}).catch(error => {
- this.formRef.value.scrollToField(error.errorFields[0].name)
+ this.$refs.vpnCustomerGatewayForm.resetSubmission()
+ const errResponse = error.response?.data?.createvpncustomergatewayresponse
+ const errText = errResponse?.errortext || this.$t('message.create.vpn.customer.gateway.failed')
+ this.$message.error(errText)
})
}
}
}
</script>
-<style lang="scss" scoped>
-.form-layout {
- width: 500px;
-}
-</style>
diff --git a/ui/src/views/network/UpdateVpnCustomerGateway.vue b/ui/src/views/network/UpdateVpnCustomerGateway.vue
new file mode 100644
index 0000000..2d54e8e
--- /dev/null
+++ b/ui/src/views/network/UpdateVpnCustomerGateway.vue
@@ -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.
+<template>
+ <vpn-customer-gateway
+ ref="vpnCustomerGatewayForm"
+ :initial-values="initialValues"
+ :apiParams="apiParams"
+ @submit="handleSubmit"
+ @cancel="closeModal"
+ />
+</template>
+
+<script>
+import { postAPI } from '@/api'
+import VpnCustomerGateway from './VpnCustomerGateway.vue'
+
+export default {
+ name: 'UpdateVpnCustomerGateway',
+ components: {
+ VpnCustomerGateway
+ },
+ props: {
+ resource: {
+ type: Object,
+ required: true
+ }
+ },
+ beforeCreate () {
+ this.apiParams = this.$getApiParams('updateVpnCustomerGateway')
+ },
+ computed: {
+ initialValues () {
+ const ikepolicy = this.parseIkePolicy(this.resource.ikepolicy)
+ const esppolicy = this.parseEspPolicy(this.resource.esppolicy)
+ return {
+ id: this.resource.id,
+ name: this.resource.name,
+ domainid: this.resource.domainid,
+ gateway: this.resource.gateway,
+ cidrlist: this.resource.cidrlist,
+ ipsecpsk: this.resource.ipsecpsk,
+ ikeEncryption: ikepolicy.encryption,
+ ikeHash: ikepolicy.hash,
+ ikeDh: ikepolicy.dh,
+ espEncryption: esppolicy.encryption,
+ espHash: esppolicy.hash,
+ espDh: esppolicy.dh,
+ ikelifetime: this.resource.ikelifetime,
+ esplifetime: this.resource.esplifetime,
+ dpd: this.resource.dpd,
+ splitconnections: this.resource.splitconnections,
+ forceencap: this.resource.forceencap,
+ ikeversion: this.resource.ikeversion
+ }
+ }
+ },
+ methods: {
+ closeModal () {
+ this.$emit('close-action')
+ },
+ parseIkePolicy (ikePolicy) {
+ console.log('ikePolicy', ikePolicy)
+ if (!ikePolicy) return { encryption: null, hash: null, dh: null }
+ const parts = ikePolicy.split(';')
+ const cipherHash = parts[0] || ''
+ const dhGroup = parts[1] || null
+ const cipherHashParts = cipherHash.split('-')
+ const encryption = cipherHashParts[0] || null
+ const hash = cipherHashParts[1] || null
+ return { encryption, hash, dh: dhGroup }
+ },
+ parseEspPolicy (espPolicy) {
+ if (!espPolicy) return { encryption: null, hash: null, dh: null }
+ const parts = espPolicy.split(';')
+ const cipherHash = parts[0] || ''
+ const dhGroup = parts[1] || null
+ const cipherHashParts = cipherHash.split('-')
+ const encryption = cipherHashParts[0] || null
+ const hash = cipherHashParts[1] || null
+ return { encryption, hash, dh: dhGroup }
+ },
+ handleSubmit ({ payload }) {
+ postAPI('updateVpnCustomerGateway', {
+ id: this.resource.id,
+ ...payload
+ }).then(response => {
+ this.$pollJob({
+ jobId: response.updatevpncustomergatewayresponse.jobid,
+ title: this.$t('message.update.vpn.customer.gateway'),
+ description: payload.name,
+ successMessage: this.$t('message.success.update.vpn.customer.gateway'),
+ successMethod: () => {
+ this.closeModal()
+ },
+ errorMessage: this.$t('message.update.vpn.customer.gateway.failed'),
+ errorMethod: () => {
+ this.closeModal()
+ },
+ loadingMessage: this.$t('message.update.vpn.customer.gateway.processing'),
+ catchMessage: this.$t('error.fetching.async.job.result'),
+ catchMethod: () => {
+ this.closeModal()
+ }
+ })
+ this.closeModal()
+ }).catch(error => {
+ this.$refs.vpnCustomerGatewayForm.resetSubmission()
+ const errResponse = error.response?.data?.createvpncustomergatewayresponse
+ const errText = errResponse?.errortext || this.$t('message.update.vpn.customer.gateway.failed')
+ this.$message.error(errText)
+ })
+ }
+ }
+}
+</script>
diff --git a/ui/src/views/network/VpnCustomerGateway.vue b/ui/src/views/network/VpnCustomerGateway.vue
new file mode 100644
index 0000000..c1b1ed7
--- /dev/null
+++ b/ui/src/views/network/VpnCustomerGateway.vue
@@ -0,0 +1,581 @@
+// 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.
+<template>
+ <div>
+ <a-form
+ class="form-layout"
+ :ref="formRef"
+ :model="form"
+ :rules="rules"
+ layout="vertical"
+ @finish="handleSubmit"
+ v-ctrl-enter="handleSubmit"
+ >
+ <a-form-item ref="name" name="name">
+ <template #label>
+ <tooltip-label :title="$t('label.name')" :tooltip="apiParams.name.description"/>
+ </template>
+ <a-input
+ v-model:value="form.name"
+ :placeholder="apiParams.name.description"
+ v-focus="true" />
+ </a-form-item>
+ <a-form-item ref="gateway" name="gateway">
+ <template #label>
+ <tooltip-label :title="$t('label.gateway')" :tooltip="apiParams.gateway.description"/>
+ </template>
+ <a-input
+ v-model:value="form.gateway"
+ :placeholder="apiParams.gateway.description" />
+ </a-form-item>
+ <a-form-item ref="cidrlist" name="cidrlist">
+ <template #label>
+ <tooltip-label :title="$t('label.cidrlist')" :tooltip="apiParams.cidrlist.description"/>
+ </template>
+ <a-input
+ v-model:value="form.cidrlist"
+ :placeholder="apiParams.cidrlist.description" />
+ </a-form-item>
+ <a-form-item ref="ipsecpsk" name="ipsecpsk">
+ <template #label>
+ <tooltip-label :title="$t('label.ipsecpsk')" :tooltip="apiParams.ipsecpsk.description"/>
+ </template>
+ <a-input
+ v-model:value="form.ipsecpsk"
+ :placeholder="apiParams.ipsecpsk.description" />
+ </a-form-item>
+ <a-form-item ref="ikeEncryption" name="ikeEncryption" :label="$t('label.ikeencryption')">
+ <a-select
+ v-model:value="form.ikeEncryption"
+ showSearch
+ optionFilterProp="value"
+ :loading="loadingParameters"
+ :filterOption="(input, option) => {
+ return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option :value="algo" v-for="(algo, idx) in allowedEncryptionAlgos" :key="idx">
+ {{ algo }}
+ <a-tooltip v-if="isObsolete('encryption', algo)" :title="$t('message.vpn.customer.gateway.obsolete.parameter.tooltip')">
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ </a-tooltip>
+ </a-select-option>
+ </a-select>
+ <template #extra v-if="isExcluded('encryption', form.ikeEncryption)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@error-color'] }" />
+ {{ form.ikeEncryption }} {{ $t('message.vpn.customer.gateway.excluded.parameter') }}
+ </span>
+ </template>
+ <template #extra v-else-if="isObsolete('encryption', form.ikeEncryption)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ {{ form.ikeEncryption }} {{ $t('message.vpn.customer.gateway.obsolete.parameter') }}
+ </span>
+ </template>
+ </a-form-item>
+ <a-form-item ref="ikeHash" name="ikeHash" :label="$t('label.ikehash')">
+ <a-select
+ v-model:value="form.ikeHash"
+ showSearch
+ optionFilterProp="value"
+ :loading="loadingParameters"
+ :filterOption="(input, option) => {
+ return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option :value="h" v-for="(h, idx) in allowedHashingAlgos" :key="idx">
+ {{ h }}
+ <a-tooltip v-if="isObsolete('hash', h)" :title="$t('message.vpn.customer.gateway.obsolete.parameter.tooltip')">
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ </a-tooltip>
+ </a-select-option>
+ </a-select>
+ <template #extra v-if="isExcluded('hash', form.ikeHash)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@error-color'] }" />
+ {{ form.ikeHash }} {{ $t('message.vpn.customer.gateway.excluded.parameter') }}
+ </span>
+ </template>
+ <template #extra v-else-if="isObsolete('hash', form.ikeHash)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ {{ form.ikeHash }} {{ $t('message.vpn.customer.gateway.obsolete.parameter') }}
+ </span>
+ </template>
+ </a-form-item>
+ <a-form-item ref="ikeversion" name="ikeversion">
+ <template #label>
+ <tooltip-label :title="$t('label.ikeversion')" :tooltip="apiParams.ikeversion.description"/>
+ </template>
+ <a-select
+ v-model:value="form.ikeversion"
+ showSearch
+ optionFilterProp="value"
+ :loading="loadingParameters"
+ :filterOption="(input, option) => {
+ return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option :value="vers" v-for="(vers, idx) in allowedIkeVersions" :key="idx">
+ {{ vers }}
+ <a-tooltip v-if="isObsolete('ikeversion', vers)" :title="$t('message.vpn.customer.gateway.obsolete.parameter.tooltip')">
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ </a-tooltip>
+ </a-select-option>
+ </a-select>
+ <template #extra v-if="isExcluded('ikeversion', form.ikeversion)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@error-color'] }" />
+ {{ form.ikeversion }} {{ $t('message.vpn.customer.gateway.excluded.parameter') }}
+ </span>
+ </template>
+ <template #extra v-else-if="isObsolete('ikeversion', form.ikeversion)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ {{ form.ikeversion }} {{ $t('message.vpn.customer.gateway.obsolete.parameter') }}
+ </span>
+ </template>
+ </a-form-item>
+ <a-form-item ref="ikeDh" name="ikeDh" :label="$t('label.ikedh')">
+ <a-select
+ v-model:value="form.ikeDh"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option
+ :value="group + '(' + DHGroups[group] + ')'"
+ v-for="(group, idx) in allowedDhGroupKeys"
+ :key="idx"
+ :label="group + '(' + DHGroups[group] + ')'">
+ <div v-if="group !== ''">
+ {{ group+"("+DHGroups[group]+")" }}
+ <a-tooltip v-if="isObsolete('dh', group)" :title="$t('message.vpn.customer.gateway.obsolete.parameter.tooltip')">
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ </a-tooltip>
+ </div>
+ </a-select-option>
+ </a-select>
+ <template #extra v-if="isExcluded('dh', form.ikeDh)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@error-color'] }" />
+ {{ form.ikeDh }} {{ $t('message.vpn.customer.gateway.excluded.parameter') }}
+ </span>
+ </template>
+ <template #extra v-else-if="isObsolete('dh', form.ikeDh)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ {{ form.ikeDh }} {{ $t('message.vpn.customer.gateway.obsolete.parameter') }}
+ </span>
+ </template>
+ </a-form-item>
+ <a-form-item ref="espEncryption" name="espEncryption" :label="$t('label.espencryption')">
+ <a-select
+ v-model:value="form.espEncryption"
+ showSearch
+ optionFilterProp="value"
+ :loading="loadingParameters"
+ :filterOption="(input, option) => {
+ return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option :value="algo" v-for="(algo, idx) in allowedEncryptionAlgos" :key="idx">
+ {{ algo }}
+ <a-tooltip v-if="isObsolete('encryption', algo)" :title="$t('message.vpn.customer.gateway.obsolete.parameter.tooltip')">
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ </a-tooltip>
+ </a-select-option>
+ </a-select>
+ <template #extra v-if="isExcluded('encryption', form.espEncryption)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@error-color'] }" />
+ {{ form.espEncryption }} {{ $t('message.vpn.customer.gateway.excluded.parameter') }}
+ </span>
+ </template>
+ <template #extra v-else-if="isObsolete('encryption', form.espEncryption)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ {{ form.espEncryption }} {{ $t('message.vpn.customer.gateway.obsolete.parameter') }}
+ </span>
+ </template>
+ </a-form-item>
+ <a-form-item ref="espHash" name="espHash" :label="$t('label.esphash')">
+ <a-select
+ v-model:value="form.espHash"
+ showSearch
+ optionFilterProp="value"
+ :loading="loadingParameters"
+ :filterOption="(input, option) => {
+ return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option :value="h" v-for="(h, idx) in allowedHashingAlgos" :key="idx">
+ {{ h }}
+ <a-tooltip v-if="isObsolete('hash', h)" :title="$t('message.vpn.customer.gateway.obsolete.parameter.tooltip')">
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ </a-tooltip>
+ </a-select-option>
+ </a-select>
+ <template #extra v-if="isExcluded('hash', form.espHash)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@error-color'] }" />
+ {{ form.espHash }} {{ $t('message.vpn.customer.gateway.excluded.parameter') }}
+ </span>
+ </template>
+ <template #extra v-else-if="isObsolete('hash', form.espHash)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ {{ form.espHash }} {{ $t('message.vpn.customer.gateway.obsolete.parameter') }}
+ </span>
+ </template>
+ </a-form-item>
+ <a-form-item ref="perfectForwardSecrecy" name="perfectForwardSecrecy" :label="$t('label.perfectforwardsecrecy')">
+ <a-select
+ v-model:value="form.perfectForwardSecrecy"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option
+ :value="group + '(' + DHGroups[group] + ')'"
+ v-for="(group, idx) in allowedDhGroupKeys"
+ :key="idx"
+ :label="group === '' ? DHGroups[group] : group + '(' + DHGroups[group] + ')'">
+ <div v-if="group === ''">
+ {{ DHGroups[group] }}
+ </div>
+ <div v-else>
+ {{ group+"("+DHGroups[group]+")" }}
+ <a-tooltip v-if="isObsolete('dh', group)" :title="$t('message.vpn.customer.gateway.obsolete.parameter.tooltip')">
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ </a-tooltip>
+ </div>
+ </a-select-option>
+ </a-select>
+ <template #extra v-if="isExcluded('dh', form.perfectForwardSecrecy)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@error-color'] }" />
+ {{ form.perfectForwardSecrecy }} {{ $t('message.vpn.customer.gateway.excluded.parameter') }}
+ </span>
+ </template>
+ <template #extra v-else-if="isObsolete('dh', form.perfectForwardSecrecy)">
+ <span>
+ <warning-outlined :style="{ color: $config.theme['@warning-color'] }" />
+ {{ form.perfectForwardSecrecy }} {{ $t('message.vpn.customer.gateway.obsolete.parameter') }}
+ </span>
+ </template>
+ </a-form-item>
+ <a-form-item ref="ikelifetime" name="ikelifetime">
+ <template #label>
+ <tooltip-label :title="$t('label.ikelifetime')" :tooltip="apiParams.ikelifetime.description"/>
+ </template>
+ <a-input
+ v-model:value="form.ikelifetime"
+ :placeholder="apiParams.ikelifetime.description"/>
+ </a-form-item>
+ <a-form-item ref="esplifetime" name="esplifetime">
+ <template #label>
+ <tooltip-label :title="$t('label.esplifetime')" :tooltip="apiParams.esplifetime.description"/>
+ </template>
+ <a-input
+ v-model:value="form.esplifetime"
+ :placeholder="apiParams.esplifetime.description"/>
+ </a-form-item>
+ <a-form-item ref="dpd" name="dpd">
+ <template #label>
+ <tooltip-label :title="$t('label.dpd')" :tooltip="apiParams.dpd.description"/>
+ </template>
+ <a-switch v-model:checked="form.dpd"/>
+ </a-form-item>
+ <a-form-item ref="splitconnections" name="splitconnections" v-if="form.ikeversion !== 'ikev1'">
+ <template #label>
+ <tooltip-label :title="$t('label.splitconnections')" :tooltip="apiParams.splitconnections.description"/>
+ </template>
+ <a-switch v-model:checked="form.splitconnections"/>
+ </a-form-item>
+ <a-form-item ref="forceencap" name="forceencap">
+ <template #label>
+ <tooltip-label :title="$t('label.forceencap')" :tooltip="apiParams.forceencap.description"/>
+ </template>
+ <a-switch v-model:checked="form.forceencap"/>
+ </a-form-item>
+ <div class="action-button">
+ <a-button @click="$emit('cancel')">
+ {{ $t('label.cancel') }}
+ </a-button>
+ <a-button type="primary" @click="handleSubmit" html-type="submit">
+ {{ $t('label.ok') }}
+ </a-button>
+ </div>
+ </a-form>
+ </div>
+</template>
+<script>
+
+import { getAPI } from '@/api'
+import { ref, reactive, toRaw } from 'vue'
+import { mixinForm } from '@/utils/mixin'
+import TooltipLabel from '@/components/widgets/TooltipLabel'
+
+export default {
+ name: 'VpnCustomerGateway',
+ mixins: [mixinForm],
+ components: {
+ TooltipLabel
+ },
+ props: {
+ initialValues: {
+ type: Object,
+ default: () => ({})
+ },
+ apiParams: {
+ type: Object,
+ default: () => {}
+ }
+ },
+ data () {
+ return {
+ encryptionAlgo: [
+ 'aes128',
+ 'aes192',
+ 'aes256',
+ '3des'
+ ],
+ hash: [
+ 'sha1',
+ 'sha256',
+ 'sha384',
+ 'sha512',
+ 'md5'
+ ],
+ ikeVersions: [
+ 'ike',
+ 'ikev1',
+ 'ikev2'
+ ],
+ DHGroups: {
+ 'Group 2': 'modp1024',
+ 'Group 5': 'modp1536',
+ 'Group 14': 'modp2048',
+ 'Group 15': 'modp3072',
+ 'Group 16': 'modp4096',
+ 'Group 17': 'modp6144',
+ 'Group 18': 'modp8192'
+ },
+ ikeDhGroupInitialKey: 'Group 5',
+ isSubmitted: false,
+ ikeversion: 'ike',
+ allowedEncryptionAlgos: [],
+ allowedHashingAlgos: [],
+ allowedIkeVersions: [],
+ allowedDhGroupKeys: [],
+ allowedDhGroupValues: [],
+ obsoleteEncryptionAlgos: [],
+ obsoleteHashingAlgos: [],
+ obsoleteIkeVersions: [],
+ obsoleteDhGroups: [],
+ loadingParameters: false
+ }
+ },
+ created () {
+ this.initForm()
+ this.fetchVpnCustomerGatewayParameters()
+ },
+ methods: {
+ initForm () {
+ this.formRef = ref()
+ const defaults = {
+ name: '',
+ gateway: '',
+ cidrlist: '',
+ ipsecpsk: '',
+ ikeEncryption: '',
+ ikeHash: '',
+ ikeversion: '',
+ ikeDh: '',
+ espEncryption: '',
+ espHash: '',
+ perfectForwardSecrecy: 'None',
+ ikelifetime: '86400',
+ esplifetime: '3600',
+ dpd: false,
+ splitconnections: false,
+ forceencap: false
+ }
+ this.form = reactive({
+ ...defaults,
+ ...this.initialValues
+ })
+ if (this.initialValues.ikeDh) {
+ const ikeDhKey = Object.keys(this.DHGroups).find(key => this.DHGroups[key] === this.initialValues.ikeDh)
+ this.form.ikeDh = ikeDhKey + '(' + this.initialValues.ikeDh + ')'
+ }
+ if (this.initialValues.espDh) {
+ const espDhKey = Object.keys(this.DHGroups).find(key => this.DHGroups[key] === this.initialValues.espDh)
+ this.form.perfectForwardSecrecy = espDhKey + '(' + this.initialValues.espDh + ')'
+ }
+ this.rules = reactive({
+ name: [{ required: true, message: this.$t('label.required') }],
+ gateway: [{ required: true, message: this.$t('label.required') }],
+ cidrlist: [{ required: true, message: this.$t('label.required') }],
+ ipsecpsk: [{ required: true, message: this.$t('label.required') }]
+ })
+ },
+ closeModal () {
+ this.$emit('close-action')
+ },
+ resetSubmission () {
+ this.isSubmitted = false
+ },
+ buildPolicies (values) {
+ let ikepolicy = values.ikeEncryption + '-' + values.ikeHash + ';'
+ ikepolicy += (values.ikeDh.split('(')[1]).split(')')[0]
+
+ let esppolicy = values.espEncryption + '-' + values.espHash
+ if (values.perfectForwardSecrecy !== 'None') {
+ esppolicy += ';' + (values.perfectForwardSecrecy.split('(')[1]).split(')')[0]
+ }
+
+ return { ikepolicy, esppolicy }
+ },
+ isObsolete (type, value) {
+ switch (type) {
+ case 'encryption':
+ return this.obsoleteEncryptionAlgos.some(v => v.toLowerCase() === value)
+ case 'hash':
+ return this.obsoleteHashingAlgos.some(v => v.toLowerCase() === value)
+ case 'ikeversion':
+ return this.obsoleteIkeVersions.some(v => v.toLowerCase() === value)
+ case 'dh': {
+ const key = value.split('(')[0]
+ return this.obsoleteDhGroups.some(v => v.toLowerCase() === this.DHGroups[key])
+ }
+ default:
+ return false
+ }
+ },
+ isExcluded (type, value) {
+ switch (type) {
+ case 'encryption':
+ return !this.allowedEncryptionAlgos.some(v => v.toLowerCase() === value)
+ case 'hash':
+ return !this.allowedHashingAlgos.some(v => v.toLowerCase() === value)
+ case 'ikeversion':
+ return !this.allowedIkeVersions.some(v => v.toLowerCase() === value)
+ case 'dh': {
+ if (value === '' || value === 'None') return false
+ const key = value.split('(')[0]
+ return !this.allowedDhGroupValues.some(v => v.toLowerCase() === this.DHGroups[key])
+ }
+ default:
+ return false
+ }
+ },
+ async fetchVpnCustomerGatewayParameters () {
+ const getParam = (obj, key) => {
+ const val = obj?.[key.toLowerCase()]
+ return typeof val === 'string'
+ ? val.split(',').map(s => s.trim()).filter(Boolean)
+ : []
+ }
+ const getAllowed = (baseList, excludedList) => {
+ const excluded = new Set(excludedList.map(v => v.toLowerCase()))
+ return baseList.filter(item => !excluded.has(item.toLowerCase()))
+ }
+
+ this.loadingParameters = true
+
+ const response = await getAPI('listCapabilities', { domainid: this.initialValues.domainid })
+ const capability = response.listcapabilitiesresponse?.capability || {}
+ const parameters = capability.vpncustomergatewayparameters || {}
+
+ const excludedEnc = getParam(parameters, 'excludedEncryptionAlgorithms')
+ const excludedHash = getParam(parameters, 'excludedHashingAlgorithms')
+ const excludedIke = getParam(parameters, 'excludedIkeVersions')
+ const excludedDh = getParam(parameters, 'excludedDhGroups')
+
+ this.allowedEncryptionAlgos = getAllowed(this.encryptionAlgo, excludedEnc)
+ this.allowedHashingAlgos = getAllowed(this.hash, excludedHash)
+ this.allowedIkeVersions = getAllowed(this.ikeVersions, excludedIke)
+
+ const dhValues = Object.values(this.DHGroups)
+ this.allowedDhGroupValues = getAllowed(dhValues, excludedDh)
+ this.allowedDhGroupKeys = Object.entries(this.DHGroups)
+ .filter(([key, value]) => this.allowedDhGroupValues.includes(value))
+ .map(([key]) => key)
+
+ this.form.ikeEncryption = this.form.ikeEncryption || this.allowedEncryptionAlgos[0]
+ this.form.ikeHash = this.form.ikeHash || this.allowedHashingAlgos[0]
+ this.form.ikeversion = this.form.ikeversion || this.allowedIkeVersions[0]
+ this.form.espEncryption = this.form.espEncryption || this.allowedEncryptionAlgos[0]
+ this.form.espHash = this.form.espHash || this.allowedHashingAlgos[0]
+ if (!this.initialValues.ikeDh) {
+ if (this.allowedDhGroupKeys.includes(this.ikeDhGroupInitialKey)) {
+ this.form.ikeDh = this.ikeDhGroupInitialKey + '(' + this.DHGroups[this.ikeDhGroupInitialKey] + ')'
+ } else {
+ this.form.ikeDh = this.allowedDhGroupKeys[0] + '(' + this.DHGroups[this.allowedDhGroupKeys[0]] + ')'
+ }
+ }
+
+ this.obsoleteEncryptionAlgos = getParam(parameters, 'obsoleteEncryptionAlgorithms')
+ this.obsoleteHashingAlgos = getParam(parameters, 'obsoleteHashingAlgorithms')
+ this.obsoleteIkeVersions = getParam(parameters, 'obsoleteIkeVersions')
+ this.obsoleteDhGroups = getParam(parameters, 'obsoleteDhGroups')
+
+ this.loadingParameters = false
+ },
+ handleSubmit (e) {
+ if (e && e.preventDefault) {
+ e.preventDefault()
+ }
+ if (this.isSubmitted) return
+
+ this.formRef.value.validate().then(() => {
+ this.isSubmitted = true
+ const formRaw = toRaw(this.form)
+ const values = this.handleRemoveFields(formRaw)
+ const { ikepolicy, esppolicy } = this.buildPolicies(values)
+
+ const payload = {
+ name: values.name,
+ gateway: values.gateway,
+ cidrlist: values.cidrlist,
+ ipsecpsk: values.ipsecpsk,
+ ikelifetime: values.ikelifetime,
+ esplifetime: values.esplifetime,
+ dpd: values.dpd,
+ forceencap: values.forceencap,
+ ikepolicy: ikepolicy,
+ esppolicy: esppolicy,
+ splitconnections: values.splitconnections,
+ ikeversion: values.ikeversion
+ }
+ this.$emit('submit', {
+ payload,
+ rawValues: values
+ })
+ }).catch(error => {
+ this.formRef.value.scrollToField(error.errorFields[0].name)
+ })
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.form-layout {
+ width: 500px;
+}
+</style>
diff --git a/ui/src/views/offering/AddComputeOffering.vue b/ui/src/views/offering/AddComputeOffering.vue
index dc4d5b1..465d07b 100644
--- a/ui/src/views/offering/AddComputeOffering.vue
+++ b/ui/src/views/offering/AddComputeOffering.vue
@@ -714,7 +714,7 @@
domainLoading: false,
zones: [],
zoneLoading: false,
- selectedDeployementPlanner: null,
+ selectedDeploymentPlanner: null,
storagePolicies: null,
storageTags: [],
storageTagLoading: false,
@@ -1021,9 +1021,9 @@
this.qosType = val
},
handleDeploymentPlannerChange (planner) {
- this.selectedDeployementPlanner = planner
+ this.selectedDeploymentPlanner = planner
this.plannerModeVisible = false
- if (this.selectedDeployementPlanner === 'ImplicitDedicationPlanner') {
+ if (this.selectedDeploymentPlanner === 'ImplicitDedicationPlanner') {
this.plannerModeVisible = isAdmin()
}
},
diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue
index 2b3275a..abb70ab 100644
--- a/ui/src/views/offering/AddNetworkOffering.vue
+++ b/ui/src/views/offering/AddNetworkOffering.vue
@@ -135,6 +135,7 @@
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:placeholder="apiParams.provider.description" >
+ <a-select-option key="" >{{ }}</a-select-option>
<a-select-option :value="'NSX'" :label="$t('label.nsx')"> {{ $t('label.nsx') }} </a-select-option>
<a-select-option :value="'Netris'" :label="$t('label.netris')"> {{ $t('label.netris') }} </a-select-option>
</a-select>
diff --git a/ui/src/views/offering/AddVpcOffering.vue b/ui/src/views/offering/AddVpcOffering.vue
index d909cbd..32aa3e8 100644
--- a/ui/src/views/offering/AddVpcOffering.vue
+++ b/ui/src/views/offering/AddVpcOffering.vue
@@ -83,6 +83,7 @@
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:placeholder="apiParams.provider.description" >
+ <a-select-option key="" >{{ }}</a-select-option>
<a-select-option :value="'NSX'" :label="$t('label.nsx')"> {{ $t('label.nsx') }} </a-select-option>
<a-select-option :value="'Netris'" :label="$t('label.netris')"> {{ $t('label.netris') }} </a-select-option>
</a-select>
diff --git a/ui/src/views/offering/ImportBackupOffering.vue b/ui/src/views/offering/ImportBackupOffering.vue
index b8ac7d8..f680eac 100644
--- a/ui/src/views/offering/ImportBackupOffering.vue
+++ b/ui/src/views/offering/ImportBackupOffering.vue
@@ -85,6 +85,33 @@
</template>
<a-switch v-model:checked="form.allowuserdrivenbackups"/>
</a-form-item>
+ <a-form-item name="ispublic" ref="ispublic" :label="$t('label.ispublic')" v-if="isAdmin()">
+ <a-switch v-model:checked="form.ispublic" />
+ </a-form-item>
+ <a-form-item name="domainid" ref="domainid" v-if="!form.ispublic">
+ <template #label>
+ <tooltip-label :title="$t('label.domainid')" :tooltip="apiParams.domainid.description"/>
+ </template>
+ <a-select
+ mode="multiple"
+ :getPopupContainer="(trigger) => trigger.parentNode"
+ v-model:value="form.domainid"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }"
+ :loading="domains.loading"
+ :placeholder="apiParams.domainid.description">
+ <a-select-option v-for="(opt, optIndex) in domains.opts" :key="optIndex" :label="opt.path || opt.name || opt.description">
+ <span>
+ <resource-icon v-if="opt && opt.icon" :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
+ <block-outlined v-else style="margin-right: 5px" />
+ {{ opt.path || opt.name || opt.description }}
+ </span>
+ </a-select-option>
+ </a-select>
+ </a-form-item>
<div :span="24" class="action-button">
<a-button :loading="loading" @click="closeAction">{{ this.$t('label.cancel') }}</a-button>
<a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ this.$t('label.ok') }}</a-button>
@@ -96,6 +123,7 @@
<script>
import { ref, reactive, toRaw } from 'vue'
import { getAPI, postAPI } from '@/api'
+import { isAdmin } from '@/role'
import ResourceIcon from '@/components/view/ResourceIcon'
import TooltipLabel from '@/components/widgets/TooltipLabel'
@@ -108,6 +136,10 @@
data () {
return {
loading: false,
+ domains: {
+ loading: false,
+ opts: []
+ },
zones: {
loading: false,
opts: []
@@ -129,17 +161,23 @@
initForm () {
this.formRef = ref()
this.form = reactive({
- allowuserdrivenbackups: true
+ allowuserdrivenbackups: true,
+ ispublic: true
})
this.rules = reactive({
name: [{ required: true, message: this.$t('message.error.required.input') }],
description: [{ required: true, message: this.$t('message.error.required.input') }],
zoneid: [{ required: true, message: this.$t('message.error.select') }],
- externalid: [{ required: true, message: this.$t('message.error.select') }]
+ externalid: [{ required: true, message: this.$t('message.error.select') }],
+ domainid: [{ type: 'array', message: this.$t('message.error.select') }]
})
},
+ isAdmin () {
+ return isAdmin()
+ },
fetchData () {
this.fetchZone()
+ this.fetchDomainData()
},
fetchZone () {
this.zones.loading = true
@@ -151,6 +189,19 @@
this.zones.loading = false
})
},
+ fetchDomainData () {
+ const params = {}
+ params.listAll = true
+ params.details = 'min'
+ this.domains.loading = true
+ getAPI('listDomains', params).then(json => {
+ this.domains.opts = json.listdomainsresponse.domain || []
+ }).catch(error => {
+ this.$notifyError(error)
+ }).finally(() => {
+ this.domains.loading = false
+ })
+ },
fetchExternal (zoneId) {
if (!zoneId) {
this.externals.opts = []
@@ -179,6 +230,20 @@
params[key] = input
}
}
+ if (values.ispublic !== true) {
+ var domainIndexes = values.domainid
+ var domainId = null
+ if (domainIndexes && domainIndexes.length > 0) {
+ var domainIds = []
+ for (var i = 0; i < domainIndexes.length; i++) {
+ domainIds = domainIds.concat(this.domains.opts[domainIndexes[i]].id)
+ }
+ domainId = domainIds.join(',')
+ }
+ if (domainId) {
+ params.domainid = domainId
+ }
+ }
params.allowuserdrivenbackups = values.allowuserdrivenbackups
this.loading = true
const title = this.$t('label.import.offering')
diff --git a/ui/src/views/project/iam/ProjectRoleTab.vue b/ui/src/views/project/iam/ProjectRoleTab.vue
index c3a3159..406952a 100644
--- a/ui/src/views/project/iam/ProjectRoleTab.vue
+++ b/ui/src/views/project/iam/ProjectRoleTab.vue
@@ -144,7 +144,7 @@
createModalVisible: false,
editModalVisible: false,
selectedRole: null,
- projectPermisssions: [],
+ projectPermissions: [],
customStyle: 'margin-bottom: 0; border: none'
}
},
diff --git a/ui/src/views/setting/ConfigurationHierarchy.vue b/ui/src/views/setting/ConfigurationHierarchy.vue
index 80b464e..815a048 100644
--- a/ui/src/views/setting/ConfigurationHierarchy.vue
+++ b/ui/src/views/setting/ConfigurationHierarchy.vue
@@ -34,7 +34,7 @@
<span :style="record.parent ? 'padding-left: 50px; display:block' : 'padding-left: 25px; display:block'">{{ record.description }}</span>
</template>
<template v-if="column.key === 'value'">
- <ConfigurationValue :configrecord="record" />
+ <ConfigurationValue :configrecord="record" @refresh="handleConfigRefresh" />
</template>
</template>
</a-table>
@@ -83,6 +83,9 @@
return 'light-row'
}
return 'dark-row'
+ },
+ handleConfigRefresh (name, updatedRecord) {
+ this.$emit('refresh-config', name, updatedRecord)
}
}
}
diff --git a/ui/src/views/setting/ConfigurationTab.vue b/ui/src/views/setting/ConfigurationTab.vue
index 75905cb..65b256c 100644
--- a/ui/src/views/setting/ConfigurationTab.vue
+++ b/ui/src/views/setting/ConfigurationTab.vue
@@ -58,7 +58,8 @@
:count="count"
:page="page"
:pagesize="pagesize"
- @change-page="changePage" />
+ @change-page="changePage"
+ @refresh-config="handleConfigRefresh" />
</a-tab-pane>
<a-tab-pane
v-for="(group) in groups"
@@ -74,7 +75,8 @@
:tab="subgroup.name" >
<ConfigurationHierarchy
:columns="columns"
- :config="config" />
+ :config="config"
+ @refresh-config="handleConfigRefresh" />
</a-tab-pane>
</a-tabs>
</a-tab-pane>
@@ -322,6 +324,13 @@
'#' + this.$route.path
)
}
+ },
+ handleConfigRefresh (name, updatedRecord) {
+ if (!name || !updatedRecord) return
+ const index = this.config.findIndex(item => item.name === name)
+ if (index !== -1) {
+ this.config.splice(index, 1, updatedRecord)
+ }
}
}
}
diff --git a/ui/src/views/setting/ConfigurationTable.vue b/ui/src/views/setting/ConfigurationTable.vue
index da05b93..7edc1b1 100644
--- a/ui/src/views/setting/ConfigurationTable.vue
+++ b/ui/src/views/setting/ConfigurationTable.vue
@@ -32,7 +32,10 @@
<b> {{record.displaytext }} </b> {{ ' (' + record.name + ')' }} <br/> {{ record.description }}
</template>
<template v-if="column.key === 'value'">
- <ConfigurationValue :configrecord="record" :resource="resource" />
+ <ConfigurationValue
+ :configrecord="record"
+ :resource="resource"
+ @refresh="handleConfigRefresh" />
</template>
</template>
</a-table>
@@ -113,6 +116,9 @@
return 'config-light-row'
}
return 'config-dark-row'
+ },
+ handleConfigRefresh (name, updatedRecord) {
+ this.$emit('refresh-config', name, updatedRecord)
}
}
}
diff --git a/ui/src/views/setting/ConfigurationValue.vue b/ui/src/views/setting/ConfigurationValue.vue
index 31c0798..d9e36d9 100644
--- a/ui/src/views/setting/ConfigurationValue.vue
+++ b/ui/src/views/setting/ConfigurationValue.vue
@@ -187,7 +187,7 @@
@onClick="$resetConfigurationValueConfirm(configrecord, resetConfigurationValue)"
v-if="editableValueKey === null"
icon="reload-outlined"
- :disabled="(!('resetConfiguration' in $store.getters.apis) || configDisabled || valueLoading)" />
+ :disabled="(!('resetConfiguration' in $store.getters.apis) || configDisabled || valueLoading || configrecord.value === configrecord.defaultvalue)" />
</span>
</a-list-item>
</a-list>
@@ -273,6 +273,7 @@
this.editableValueKey = null
},
updateConfigurationValue (configrecord) {
+ let configRecordEntry = this.configrecord
this.valueLoading = true
this.editableValueKey = null
var newValue = this.editableValue
@@ -294,7 +295,8 @@
params[this.scopeKey] = this.resource?.id
}
postAPI('updateConfiguration', params).then(json => {
- this.editableValue = this.getEditableValue(json.updateconfigurationresponse.configuration)
+ configRecordEntry = json.updateconfigurationresponse.configuration
+ this.editableValue = this.getEditableValue(configRecordEntry)
this.actualValue = this.editableValue
this.$emit('change-config', { value: newValue })
this.$store.dispatch('RefreshFeatures')
@@ -310,10 +312,11 @@
})
}).finally(() => {
this.valueLoading = false
- this.$emit('refresh')
+ this.$emit('refresh', configrecord.name, configRecordEntry)
})
},
resetConfigurationValue (configrecord) {
+ let configRecordEntry = this.configrecord
this.valueLoading = true
this.editableValueKey = null
const params = {
@@ -324,7 +327,8 @@
params[this.scopeKey] = this.resource?.id
}
postAPI('resetConfiguration', params).then(json => {
- this.editableValue = this.getEditableValue(json.resetconfigurationresponse.configuration)
+ configRecordEntry = json.resetconfigurationresponse.configuration
+ this.editableValue = this.getEditableValue(configRecordEntry)
this.actualValue = this.editableValue
var newValue = this.editableValue
if (configrecord.type === 'Range') {
@@ -344,7 +348,7 @@
})
}).finally(() => {
this.valueLoading = false
- this.$emit('refresh')
+ this.$emit('refresh', configrecord.name, configRecordEntry)
})
},
getEditableValue (configrecord) {
diff --git a/ui/src/views/storage/ChangeSharedFSServiceOffering.vue b/ui/src/views/storage/ChangeSharedFSServiceOffering.vue
index 2291388..f74ad59 100644
--- a/ui/src/views/storage/ChangeSharedFSServiceOffering.vue
+++ b/ui/src/views/storage/ChangeSharedFSServiceOffering.vue
@@ -95,7 +95,7 @@
loading: false,
configLoading: false,
serviceofferings: [],
- serviceofferingLoding: false
+ serviceofferingLoading: false
}
},
beforeCreate () {
diff --git a/ui/src/views/storage/FormSchedule.vue b/ui/src/views/storage/FormSchedule.vue
index 433e399..baecd3b 100644
--- a/ui/src/views/storage/FormSchedule.vue
+++ b/ui/src/views/storage/FormSchedule.vue
@@ -174,7 +174,10 @@
</a-form-item>
</a-col>
<a-col :md="24" :lg="24" v-if="resourceType === 'Volume'">
- <a-form-item :label="$t('label.usestoragereplication')" name="useStorageReplication" ref="useStorageReplication">
+ <a-form-item name="useStorageReplication" ref="useStorageReplication">
+ <template #label>
+ <tooltip-label :title="$t('label.usestoragereplication')" :tooltip="apiParams.usestoragereplication.description" />
+ </template>
<a-switch v-model:checked="form.useStorageReplication" />
</a-form-item>
<a-form-item v-if="isAdmin && form.useStorageReplication" ref="storageids" name="storageids">
@@ -310,6 +313,9 @@
storagePools: []
}
},
+ beforeCreate () {
+ this.apiParams = this.$getApiParams('createSnapshotPolicy')
+ },
created () {
this.initForm()
this.volumeId = this.resource.id
diff --git a/ui/src/views/storage/SnapshotZones.vue b/ui/src/views/storage/SnapshotZones.vue
index 45b1aba..564d03c 100644
--- a/ui/src/views/storage/SnapshotZones.vue
+++ b/ui/src/views/storage/SnapshotZones.vue
@@ -137,7 +137,10 @@
</a-select-option>
</a-select>
</a-form-item>
- <a-form-item :label="$t('label.usestoragereplication')" name="useStorageReplication" ref="useStorageReplication">
+ <a-form-item name="useStorageReplication" ref="useStorageReplication">
+ <template #label>
+ <tooltip-label :title="$t('label.usestoragereplication')" :tooltip="apiParams.usestoragereplication.description" />
+ </template>
<a-switch v-model:checked="form.useStorageReplication" />
</a-form-item>
<a-form-item v-if="isAdmin && form.useStorageReplication" ref="storageid" name="storageid" :label="$t('label.storagepools')">
@@ -236,6 +239,7 @@
import OsLogo from '@/components/widgets/OsLogo'
import ResourceIcon from '@/components/view/ResourceIcon'
import TooltipButton from '@/components/widgets/TooltipButton'
+import TooltipLabel from '@/components/widgets/TooltipLabel'
import BulkActionProgress from '@/components/view/BulkActionProgress'
import Status from '@/components/widgets/Status'
import eventBus from '@/config/eventBus'
@@ -244,6 +248,7 @@
name: 'SnapshotZones',
components: {
TooltipButton,
+ TooltipLabel,
OsLogo,
ResourceIcon,
BulkActionProgress,
diff --git a/ui/src/views/storage/TakeSnapshot.vue b/ui/src/views/storage/TakeSnapshot.vue
index fc80e6d..9e17e06 100644
--- a/ui/src/views/storage/TakeSnapshot.vue
+++ b/ui/src/views/storage/TakeSnapshot.vue
@@ -66,7 +66,10 @@
</a-select-option>
</a-select>
</a-form-item>
- <a-form-item :label="$t('label.usestoragereplication')" name="useStorageReplication" ref="useStorageReplication">
+ <a-form-item name="useStorageReplication" ref="useStorageReplication">
+ <template #label>
+ <tooltip-label :title="$t('label.usestoragereplication')" :tooltip="apiParams.usestoragereplication.description" />
+ </template>
<a-switch v-model:checked="form.useStorageReplication" />
</a-form-item>
<a-form-item v-if="isAdmin && form.useStorageReplication" ref="storageids" name="storageids">
@@ -93,7 +96,10 @@
</a-select-option>
</a-select>
</a-form-item>
- <a-form-item :label="$t('label.asyncbackup')" name="asyncbackup" ref="asyncbackup" v-if="!supportsStorageSnapshot">
+ <a-form-item name="asyncbackup" ref="asyncbackup" v-if="!supportsStorageSnapshot">
+ <template #label>
+ <tooltip-label :title="$t('label.asyncbackup')" :tooltip="apiParams.asyncbackup.description" />
+ </template>
<a-switch v-model:checked="form.asyncbackup" />
</a-form-item>
<a-form-item :label="$t('label.quiescevm')" name="quiescevm" ref="quiescevm" v-if="quiescevm && hypervisorSupportsQuiesceVm">
diff --git a/usage/pom.xml b/usage/pom.xml
index 7f5b0ba..e1e0b0f 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/utils/pom.xml b/utils/pom.xml
index ee6df96..4b6e547 100755
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/utils/src/main/java/com/cloud/utils/EnumUtils.java b/utils/src/main/java/com/cloud/utils/EnumUtils.java
index 380b595..1af2906 100644
--- a/utils/src/main/java/com/cloud/utils/EnumUtils.java
+++ b/utils/src/main/java/com/cloud/utils/EnumUtils.java
@@ -29,30 +29,4 @@
b.append("]");
return b.toString();
}
-
- public static <T extends Enum<T>> T fromString(Class<T> clz, String value, T defaultVal) {
- assert (clz != null);
-
- if (value != null) {
- try {
- return Enum.valueOf(clz, value.trim());
- } catch (IllegalArgumentException ex) {
- assert (false);
- }
- }
- return defaultVal;
- }
-
- public static <T extends Enum<T>> T fromString(Class<T> clz, String value) {
- assert (clz != null);
-
- if (value != null) {
- try {
- return Enum.valueOf(clz, value.trim());
- } catch (IllegalArgumentException ex) {
- assert (false);
- }
- }
- return null;
- }
}
diff --git a/utils/src/main/java/com/cloud/utils/rest/BasicRestClient.java b/utils/src/main/java/com/cloud/utils/rest/BasicRestClient.java
index 9424bae..1d9180f 100644
--- a/utils/src/main/java/com/cloud/utils/rest/BasicRestClient.java
+++ b/utils/src/main/java/com/cloud/utils/rest/BasicRestClient.java
@@ -75,7 +75,7 @@
final URI uri = request.getURI();
String query = uri.getQuery();
query = query != null ? "?" + query : "";
- logger.debug("Executig " + request.getMethod() + " request on " + clientContext.getTargetHost() + uri.getPath() + query);
+ logger.debug("Executing " + request.getMethod() + " request on " + clientContext.getTargetHost() + uri.getPath() + query);
}
@Override
diff --git a/utils/src/main/java/com/cloud/utils/xmlobject/XmlObject.java b/utils/src/main/java/com/cloud/utils/xmlobject/XmlObject.java
index 67634e4..42f687c 100644
--- a/utils/src/main/java/com/cloud/utils/xmlobject/XmlObject.java
+++ b/utils/src/main/java/com/cloud/utils/xmlobject/XmlObject.java
@@ -55,14 +55,11 @@
}
Object old = elements.get(key);
if (old == null) {
- //System.out.println(String.format("no %s, add new", key));
elements.put(key, e);
} else {
if (old instanceof List) {
- //System.out.println(String.format("already list %s, add", key));
((List)old).add(e);
} else {
- //System.out.println(String.format("not list list %s, add list", key));
List lst = new ArrayList();
lst.add(old);
lst.add(e);
diff --git a/utils/src/main/java/com/cloud/utils/xmlobject/XmlObjectParser.java b/utils/src/main/java/com/cloud/utils/xmlobject/XmlObjectParser.java
index ea63170..25146f7 100644
--- a/utils/src/main/java/com/cloud/utils/xmlobject/XmlObjectParser.java
+++ b/utils/src/main/java/com/cloud/utils/xmlobject/XmlObjectParser.java
@@ -49,7 +49,6 @@
@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
- //System.out.println(String.format("startElement: namespaceURI:%s, localName:%s, qName:%s", namespaceURI, localName, qName));
currentValue = null;
XmlObject obj = new XmlObject();
for (int i = 0; i < atts.getLength(); i++) {
@@ -73,8 +72,6 @@
if (stack.isEmpty()) {
root = currObj;
}
-
- //System.out.println(String.format("endElement: namespaceURI:%s, localName:%s, qName:%s", namespaceURI, localName, qName));
}
@Override
@@ -82,7 +79,6 @@
StringBuilder str = new StringBuilder();
str.append(ch, start, length);
currentValue = str.toString();
- //System.out.println(String.format("characters: %s", str.toString()));
}
XmlObject getRoot() {
diff --git a/utils/src/main/java/org/apache/cloudstack/utils/server/ServerPropertiesUtil.java b/utils/src/main/java/org/apache/cloudstack/utils/server/ServerPropertiesUtil.java
new file mode 100644
index 0000000..14d24db
--- /dev/null
+++ b/utils/src/main/java/org/apache/cloudstack/utils/server/ServerPropertiesUtil.java
@@ -0,0 +1,58 @@
+// 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.utils.server;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.cloud.utils.PropertiesUtil;
+
+public class ServerPropertiesUtil {
+ private static final Logger logger = LoggerFactory.getLogger(ServerPropertiesUtil.class);
+ protected static final String PROPERTIES_FILE = "server.properties";
+ protected static final AtomicReference<Properties> propertiesRef = new AtomicReference<>();
+
+ public static String getProperty(String name) {
+ Properties props = propertiesRef.get();
+ if (props != null) {
+ return props.getProperty(name);
+ }
+ File propsFile = PropertiesUtil.findConfigFile(PROPERTIES_FILE);
+ if (propsFile == null) {
+ logger.error("{} file not found", PROPERTIES_FILE);
+ return null;
+ }
+ Properties tempProps = new Properties();
+ try (FileInputStream is = new FileInputStream(propsFile)) {
+ tempProps.load(is);
+ } catch (IOException e) {
+ logger.error("Error loading {}: {}", PROPERTIES_FILE, e.getMessage(), e);
+ return null;
+ }
+ if (!propertiesRef.compareAndSet(null, tempProps)) {
+ tempProps = propertiesRef.get();
+ }
+ return tempProps.getProperty(name);
+ }
+}
diff --git a/utils/src/test/java/org/apache/cloudstack/utils/server/ServerPropertiesUtilTest.java b/utils/src/test/java/org/apache/cloudstack/utils/server/ServerPropertiesUtilTest.java
new file mode 100644
index 0000000..2eece43
--- /dev/null
+++ b/utils/src/test/java/org/apache/cloudstack/utils/server/ServerPropertiesUtilTest.java
@@ -0,0 +1,95 @@
+// 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.utils.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Properties;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockedStatic;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.PropertiesUtil;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ServerPropertiesUtilTest {
+
+ @After
+ public void clearCache() {
+ ServerPropertiesUtil.propertiesRef.set(null);
+ }
+
+ @Test
+ public void returnsPropertyValueWhenPropertiesAreLoaded() {
+ Properties mockProperties = mock(Properties.class);
+ when(mockProperties.getProperty("key")).thenReturn("value");
+ ServerPropertiesUtil.propertiesRef.set(mockProperties);
+ String result = ServerPropertiesUtil.getProperty("key");
+ assertEquals("value", result);
+ }
+
+ @Test
+ public void returnsNullWhenPropertyDoesNotExist() {
+ Properties mockProperties = mock(Properties.class);
+ ServerPropertiesUtil.propertiesRef.set(mockProperties);
+ assertNull(ServerPropertiesUtil.getProperty("nonexistentKey"));
+ }
+
+ @Test
+ public void loadsPropertiesFromFileWhenNotCached() throws Exception {
+ File tempFile = Files.createTempFile("server", ".properties").toFile();
+ tempFile.deleteOnExit();
+ Files.writeString(tempFile.toPath(), "key=value\n");
+ try (MockedStatic<PropertiesUtil> mocked = mockStatic(PropertiesUtil.class)) {
+ mocked.when(() -> PropertiesUtil.findConfigFile(ServerPropertiesUtil.PROPERTIES_FILE))
+ .thenReturn(tempFile);
+ assertEquals("value", ServerPropertiesUtil.getProperty("key"));
+ }
+ }
+
+ @Test
+ public void returnsNullWhenPropertiesFileNotFound() {
+ try (MockedStatic<PropertiesUtil> mocked = mockStatic(PropertiesUtil.class)) {
+ mocked.when(() -> PropertiesUtil.findConfigFile(ServerPropertiesUtil.PROPERTIES_FILE))
+ .thenReturn(null);
+ assertNull(ServerPropertiesUtil.getProperty("key"));
+ }
+ }
+
+ @Test
+ public void returnsNullWhenIOExceptionOccurs() throws IOException {
+ File tempFile = Files.createTempFile("bad", ".properties").toFile();
+ tempFile.deleteOnExit();
+ Files.writeString(tempFile.toPath(), "\u0000\u0000\u0000");
+ try (MockedStatic<PropertiesUtil> mocked = mockStatic(PropertiesUtil.class)) {
+ mocked.when(() -> PropertiesUtil.findConfigFile(ServerPropertiesUtil.PROPERTIES_FILE))
+ .thenReturn(tempFile);
+ assertNull(ServerPropertiesUtil.getProperty("key"));
+ }
+ }
+}
diff --git a/vmware-base/pom.xml b/vmware-base/pom.xml
index 9b7b989..7c40517 100644
--- a/vmware-base/pom.xml
+++ b/vmware-base/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.22.1.0-SNAPSHOT</version>
+ <version>4.23.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
index a984d84..82a7b91 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
@@ -451,7 +451,7 @@
return isAccessible;
}
- public boolean isDatastoreStoragePolicyComplaint(String storagePolicyId) throws Exception {
+ public boolean isDatastoreStoragePolicyCompliant(String storagePolicyId) throws Exception {
PbmProfileManagerMO profMgrMo = new PbmProfileManagerMO(_context);
PbmProfile profile = profMgrMo.getStorageProfile(storagePolicyId);
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
index ebd8d0e..288a108 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
@@ -1728,7 +1728,6 @@
cdRom.setBacking(backingInfo);
VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec();
- //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
deviceConfigSpec.setDevice(cdRom);
@@ -1738,7 +1737,6 @@
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT);
}
- //deviceConfigSpecArray[0] = deviceConfigSpec;
reConfigSpec.getDeviceChange().add(deviceConfigSpec);
ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec);
@@ -1780,13 +1778,11 @@
device.setBacking(backingInfo);
VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec();
- //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
deviceConfigSpec.setDevice(device);
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT);
- //deviceConfigSpecArray[0] = deviceConfigSpec;
reConfigSpec.getDeviceChange().add(deviceConfigSpec);
ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec);