Merge branch 'main' into 423-vmw-kvm-cleanup-migrated-disks-failure

This commit is contained in:
nvazquez 2026-06-24 10:27:27 -03:00
commit 97ba5d3dac
No known key found for this signature in database
GPG Key ID: 656E1BCC8CB54F84
670 changed files with 62965 additions and 6839 deletions

View File

@ -16,7 +16,6 @@
# under the License.
# https://cwiki.apache.org/confluence/display/INFRA/git+-+.asf.yaml+features
---
github:
description: "Apache CloudStack is an opensource Infrastructure as a Service (IaaS) cloud computing platform"
homepage: https://cloudstack.apache.org/
@ -51,12 +50,32 @@ github:
collaborators:
- ingox
- gpordeus
- gp-santos
- erikbocks
- Imvedansh
- Damans227
- jmsperu
- GaOrtiga
- bhouse-nexthop
protected_branches: ~
protected_branches:
rulesets:
- name: "Default Branch Protection"
type: branch
branches:
includes:
- "~DEFAULT_BRANCH"
excludes: []
bypass_teams:
- root
restrict_deletion: true
restrict_force_push: true
copilot_code_review:
enabled: true
review_drafts: true
review_on_push: true
notifications:
commits: commits@cloudstack.apache.org

View File

@ -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.
name: 'Install CloudStack Non-OSS'
description: 'Clones and installs the shapeblue/cloudstack-nonoss repository.'
runs:
using: "composite"
steps:
- name: Install cloudstack-nonoss
shell: bash
run: |
git clone --depth 1 https://github.com/shapeblue/cloudstack-nonoss.git nonoss
cd nonoss
bash -x install-non-oss.sh
cd ..
rm -fr nonoss

58
.github/actions/setup-env/action.yml vendored Normal file
View File

@ -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.
name: 'Setup CloudStack Environment'
description: 'Sets up JDK (with Maven cache), optionally Python, and optionally APT build dependencies for CloudStack.'
inputs:
java-version:
description: 'The JDK version to use'
required: false
default: '17'
install-python:
description: 'Whether to install Python 3.10'
required: false
default: 'false'
install-apt-deps:
description: 'Whether to install CloudStack APT build dependencies'
required: false
default: 'false'
runs:
using: "composite"
steps:
- name: Set up JDK ${{ inputs.java-version }}
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
java-version: ${{ inputs.java-version }}
distribution: 'adopt'
architecture: x64
cache: 'maven'
- name: Set up Python
if: ${{ inputs.install-python == 'true' }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.10'
architecture: x64
- name: Install Build Dependencies
if: ${{ inputs.install-apt-deps == 'true' }}
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y git uuid-runtime genisoimage netcat-openbsd ipmitool build-essential libgcrypt20 libgpg-error-dev libgpg-error0 libopenipmi0 libpython3-dev libssl-dev libffi-dev python3-openssl python3-dev python3-setuptools

56
.github/aw/actions-lock.json vendored Normal file
View File

@ -0,0 +1,56 @@
{
"entries": {
"actions/github-script@v9.0.0": {
"repo": "actions/github-script",
"version": "v9.0.0",
"sha": "3a2844b7e9c422d3c10d287c895573f7108da1b3"
},
"github/gh-aw-actions/setup@v0.76.1": {
"repo": "github/gh-aw-actions/setup",
"version": "v0.76.1",
"sha": "46d564922b082d0db93244972e8005ea6904ee5f"
}
},
"containers": {
"ghcr.io/github/gh-aw-firewall/agent:0.18.0": {
"image": "ghcr.io/github/gh-aw-firewall/agent:0.18.0",
"digest": "sha256:ab84dfc7f5998cb8cd0c596526dd573b7e7d06c6a740266a1e6df879fa16c866",
"pinned_image": "ghcr.io/github/gh-aw-firewall/agent:0.18.0@sha256:ab84dfc7f5998cb8cd0c596526dd573b7e7d06c6a740266a1e6df879fa16c866"
},
"ghcr.io/github/gh-aw-firewall/agent:0.25.55": {
"image": "ghcr.io/github/gh-aw-firewall/agent:0.25.55",
"digest": "sha256:138c363411decc9a61a5af9b95e8d64c76648b00add0ba06fc7ba786f0e72731",
"pinned_image": "ghcr.io/github/gh-aw-firewall/agent:0.25.55@sha256:138c363411decc9a61a5af9b95e8d64c76648b00add0ba06fc7ba786f0e72731"
},
"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.55": {
"image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.25.55",
"digest": "sha256:4142b873b678cd3279b98dcbe464857d56ea2f2348719b00379cdf35dd843ff3",
"pinned_image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.25.55@sha256:4142b873b678cd3279b98dcbe464857d56ea2f2348719b00379cdf35dd843ff3"
},
"ghcr.io/github/gh-aw-firewall/squid:0.18.0": {
"image": "ghcr.io/github/gh-aw-firewall/squid:0.18.0",
"digest": "sha256:82a5d062a5612a57a43a171a5b79ddbb690a86a8ddda02339cc1675131ae9f8b",
"pinned_image": "ghcr.io/github/gh-aw-firewall/squid:0.18.0@sha256:82a5d062a5612a57a43a171a5b79ddbb690a86a8ddda02339cc1675131ae9f8b"
},
"ghcr.io/github/gh-aw-firewall/squid:0.25.55": {
"image": "ghcr.io/github/gh-aw-firewall/squid:0.25.55",
"digest": "sha256:74084b704d8d3664a363655986664d70bd9cdb4830532d0b35cd784d867aabca",
"pinned_image": "ghcr.io/github/gh-aw-firewall/squid:0.25.55@sha256:74084b704d8d3664a363655986664d70bd9cdb4830532d0b35cd784d867aabca"
},
"ghcr.io/github/gh-aw-mcpg:v0.1.4": {
"image": "ghcr.io/github/gh-aw-mcpg:v0.1.4",
"digest": "sha256:0acf25aa1d409f9c73be9e39ac84f4bd4b90d8bfa1db4dc6d7f47d38ccd58914",
"pinned_image": "ghcr.io/github/gh-aw-mcpg:v0.1.4@sha256:0acf25aa1d409f9c73be9e39ac84f4bd4b90d8bfa1db4dc6d7f47d38ccd58914"
},
"ghcr.io/github/gh-aw-mcpg:v0.3.19": {
"image": "ghcr.io/github/gh-aw-mcpg:v0.3.19",
"digest": "sha256:a6c890d7c24d7190c9ef97b9c954cc4cffaae6b01c371ced1f959f1370b1f68f",
"pinned_image": "ghcr.io/github/gh-aw-mcpg:v0.3.19@sha256:a6c890d7c24d7190c9ef97b9c954cc4cffaae6b01c371ced1f959f1370b1f68f"
},
"ghcr.io/github/github-mcp-server:v0.30.3": {
"image": "ghcr.io/github/github-mcp-server:v0.30.3",
"digest": "sha256:a2b5fb79b1cee851bfc3532dfe480c3dc5736974ca9d93a7a9f68e52ce4b62a0",
"pinned_image": "ghcr.io/github/github-mcp-server:v0.30.3@sha256:a2b5fb79b1cee851bfc3532dfe480c3dc5736974ca9d93a7a9f68e52ce4b62a0"
}
}
}

View File

@ -1,73 +0,0 @@
---
# Report formatting guidelines
---
## Report Structure Guidelines
### 1. Header Levels
**Use h3 (###) or lower for all headers in your issue report to maintain proper document hierarchy.**
When creating GitHub issues or discussions:
- Use `###` (h3) for main sections (e.g., "### Test Summary")
- Use `####` (h4) for subsections (e.g., "#### Device-Specific Results")
- Never use `##` (h2) or `#` (h1) in reports - these are reserved for titles
### 2. Progressive Disclosure
**Wrap detailed test results in `<details><summary><b>Section Name</b></summary>` tags to improve readability and reduce scrolling.**
Use collapsible sections for:
- Verbose details (full test logs, raw data)
- Secondary information (minor warnings, extra context)
- Per-item breakdowns when there are many items
Always keep critical information visible (summary, critical issues, key metrics).
### 3. Report Structure Pattern
1. **Overview**: 1-2 paragraphs summarizing key findings
2. **Critical Information**: Show immediately (summary stats, critical issues)
3. **Details**: Use `<details><summary><b>Section Name</b></summary>` for expanded content
4. **Context**: Add helpful metadata (workflow run, date, trigger)
### Design Principles (Airbnb-Inspired)
Reports should:
- **Build trust through clarity**: Most important info immediately visible
- **Exceed expectations**: Add helpful context like trends, comparisons
- **Create delight**: Use progressive disclosure to reduce overwhelm
- **Maintain consistency**: Follow patterns across all reports
### Example Report Structure
```markdown
### Summary
- Key metric 1: value
- Key metric 2: value
- Status: ✅/⚠️/❌
### Critical Issues
[Always visible - these are important]
<details>
<summary><b>View Detailed Results</b></summary>
[Comprehensive details, logs, traces]
</details>
<details>
<summary><b>View All Warnings</b></summary>
[Minor issues and potential problems]
</details>
### Recommendations
[Actionable next steps - keep visible]
```
## Workflow Run References
- Format run IDs as links: `[§12345](https://github.com/owner/repo/actions/runs/12345)`
- Include up to 3 most relevant run URLs at end under `**References:**`
- Do NOT add footer attribution (system adds automatically)

View File

@ -31,6 +31,8 @@ updates:
github-actions-dependencies:
patterns:
- "*"
ignore:
- dependency-name: "github/gh-aw-actions/**" # Managed by gh aw compile. Version-locked to the gh-aw compiler; do not bump.
cooldown:
default-days: 7
- package-ecosystem: "maven"

View File

@ -16,40 +16,27 @@
# under the License.
name: Build
on: [push, pull_request]
on:
- push
- pull_request
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Set up JDK 17
uses: actions/setup-java@v5
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v6
- name: Setup Environment
uses: ./.github/actions/setup-env
with:
python-version: '3.10'
architecture: 'x64'
- name: Install Build Dependencies
run: |
sudo apt-get update
sudo apt-get install -y git uuid-runtime genisoimage netcat ipmitool build-essential libgcrypt20 libgpg-error-dev libgpg-error0 libopenipmi0 ipmitool libpython3-dev libssl-dev libffi-dev python3-openssl python3-dev python3-setuptools
install-python: 'true'
install-apt-deps: 'true'
- name: Env details
run: |
uname -a
@ -60,9 +47,8 @@ jobs:
free -m
nproc
git status
- name: Install Non-OSS
uses: ./.github/actions/install-nonoss
- name: Noredist Build
run: |
git clone https://github.com/shapeblue/cloudstack-nonoss.git nonoss && cd nonoss && bash -x install-non-oss.sh && cd ..
rm -fr nonoss
mvn -B -P developer,systemvm -Dsimulator -Dnoredist clean install -T$(nproc)

View File

@ -16,21 +16,56 @@
# under the License.
name: Simulator CI
on: [push, pull_request]
on:
- push
- pull_request
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
permissions:
contents: read
jobs:
build:
if: github.repository == 'apache/cloudstack'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Environment
uses: ./.github/actions/setup-env
with:
install-python: 'true'
install-apt-deps: 'true'
- name: Env details
run: |
uname -a
whoami
javac -version
mvn -v
python3 --version
free -m
nproc
git status
ipmitool -V
- name: Build with Maven
run: |
mvn -B -P developer,systemvm -Dsimulator clean install -DskipTests=true -T$(nproc)
- name: Archive artifacts
run: |
mkdir -p /tmp/artifacts
tar -czf /tmp/artifacts/targets.tar.gz $(find . -name "target" -type d) tools/marvin/dist engine/schema/dist utils/conf
tar -czf /tmp/artifacts/m2-cloudstack.tar.gz -C ~/.m2/repository org/apache/cloudstack
- name: Upload artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: build-artifacts
path: /tmp/artifacts/
test:
needs: build
if: github.repository == 'apache/cloudstack'
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
@ -215,30 +250,16 @@ jobs:
smoke/test_list_service_offerings
smoke/test_list_storage_pools
smoke/test_list_volumes"]
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v5
persist-credentials: false
- name: Setup Environment
uses: ./.github/actions/setup-env
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'
architecture: 'x64'
- name: Install Build Dependencies
run: |
sudo apt-get update
sudo apt-get install -y git uuid-runtime genisoimage netcat-openbsd ipmitool build-essential libgcrypt20 libgpg-error-dev libgpg-error0 libopenipmi0 ipmitool libpython3-dev libssl-dev libffi-dev python3-openssl python3-dev python3-setuptools
install-python: 'true'
install-apt-deps: 'true'
- name: Setup IPMI Tool for CloudStack
run: |
# Create cloudstack-common directory if it doesn't exist
@ -256,55 +277,43 @@ jobs:
/usr/share/cloudstack-common/ipmitool -C3 $@
EOF
sudo chmod 755 /usr/bin/ipmitool
- name: Install Python dependencies
run: |
python3 -m pip install --user --upgrade urllib3 lxml paramiko nose texttable ipmisim pyopenssl pycryptodome mock flask netaddr pylint pycodestyle six astroid pynose
- name: Install jacoco dependencies
run: |
wget https://github.com/jacoco/jacoco/releases/download/v0.8.10/jacoco-0.8.10.zip
unzip jacoco-0.8.10.zip -d jacoco
- name: Env details
run: |
uname -a
whoami
javac -version
mvn -v
python3 --version
free -m
nproc
git status
ipmitool -V
- name: Setup MySQL Server
run: |
# https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2004-Readme.md#mysql
sudo apt-get install -y mysql-server
sudo systemctl start mysql
sudo mysql -uroot -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY ''; FLUSH PRIVILEGES;"
sudo mysql -uroot -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY ''; FLUSH PRIVILEGES;"
sudo systemctl restart mysql
sudo mysql -uroot -e "SELECT VERSION();"
- name: Build with Maven
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: build-artifacts
path: /tmp/artifacts/
- name: Extract artifacts
run: |
mvn -B -P developer,systemvm -Dsimulator clean install -DskipTests=true -T$(nproc)
tar -xzf /tmp/artifacts/targets.tar.gz
mkdir -p ~/.m2/repository
tar -xzf /tmp/artifacts/m2-cloudstack.tar.gz -C ~/.m2/repository
- name: Setup Simulator Prerequisites
run: |
sudo python3 -m pip install --upgrade netaddr mysql-connector-python
python3 -m pip install --user --upgrade tools/marvin/dist/[mM]arvin-*.tar.gz
mvn -q -Pdeveloper -pl developer -Ddeploydb
mvn -q -Pdeveloper -pl developer -Ddeploydb-simulator
- name: Generate jacoco-coverage.sh
run: |
echo "java -jar jacoco/lib/jacococli.jar report jacoco-it.exec \\" > jacoco-report.sh
find . | grep "target/classes" | sed 's/\/classes\//\/classes /g' | awk '{print "--classfiles", $1, "\\"}' | sort |uniq >> jacoco-report.sh
find . | grep "src/main/java" | sed 's/\/java\//\/java /g' | awk '{print "--sourcefiles", $1, "\\"}' | sort | uniq >> jacoco-report.sh
echo "--xml jacoco-coverage.xml" >> jacoco-report.sh
- name: Start CloudStack Management Server with Simulator
run: |
export MAVEN_OPTS="-Xmx4096m -XX:MaxMetaspaceSize=800m -Djava.security.egd=file:/dev/urandom -javaagent:jacoco/lib/jacocoagent.jar=address=*,port=36320,output=tcpserver --add-opens=java.base/java.lang=ALL-UNNAMED --add-exports=java.base/sun.security.x509=ALL-UNNAMED --add-opens=java.base/jdk.internal.reflect=ALL-UNNAMED"
@ -315,7 +324,6 @@ jobs:
set -e
echo -e "\nStarting Advanced Zone DataCenter deployment"
python3 tools/marvin/marvin/deployDataCenter.py -i setup/dev/advdualzone.cfg 2>&1 || true
- name: Run Integration Tests with Simulator
run: |
mkdir -p integration-test-results/smoke/misc
@ -335,13 +343,12 @@ jobs:
bash jacoco-report.sh
mvn -Dsimulator -pl client jetty:stop 2>&1
find /tmp//MarvinLogs -type f -exec echo -e "Printing marvin logs {} :\n" \; -exec cat {} \;
- name: Integration Tests Result
run: |
echo -e "Simulator CI Test Results: (only failures listed)\n"
python3 ./tools/marvin/xunit-reader.py integration-test-results/
- uses: codecov/codecov-action@v6
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
files: jacoco-coverage.xml
fail_ci_if_error: true

View File

@ -1,59 +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.
name: Coverage Check
on: [pull_request, push]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
if: github.repository == 'apache/cloudstack'
name: codecov
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'
- name: Build CloudStack with Quality Checks
run: |
git clone https://github.com/shapeblue/cloudstack-nonoss.git nonoss
cd nonoss && bash -x install-non-oss.sh && cd ..
mvn -P quality -Dsimulator -Dnoredist clean install -T$(nproc)
- uses: codecov/codecov-action@v6
with:
files: ./client/target/site/jacoco-aggregate/jacoco.xml
fail_ci_if_error: true
flags: unittests
verbose: true
name: codecov
token: ${{ secrets.CODECOV_TOKEN }}

View File

@ -35,14 +35,16 @@ jobs:
language: ["actions"]
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v4
uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
category: "Security"

1400
.github/workflows/daily-issue-triage.lock.yml generated vendored Normal file

File diff suppressed because it is too large Load Diff

171
.github/workflows/daily-issue-triage.md vendored Normal file
View File

@ -0,0 +1,171 @@
---
description: |
Scheduled daily triage that processes untriaged CloudStack issues in batches.
Detects duplicates, filters spam, and assigns CloudStack-specific labels
(type:*, component:*, Severity:*, status:*), then posts a structured triage report.
name: Daily Issue Triage
on:
schedule: daily around 14:00 on weekdays
workflow_dispatch:
permissions: read-all
network: defaults
safe-outputs:
add-labels:
target: "*"
max: 10
add-comment:
target: "*"
max: 10
tools:
web-fetch:
github:
toolsets: [issues, labels]
min-integrity: none
source: githubnext/agentics/workflows/daily-issue-triage.md@d7c1dc4b72b00607a67caaffdcc216cb64379cf9
timeout-minutes: 60
---
# Daily Issue Triage
<!-- Note - this file can be customized to your needs. Replace this section directly, or add further instructions here. After editing run 'gh aw compile' -->
You are a batch triage assistant for GitHub issues in **${{ github.repository }}** (Apache CloudStack). Your task is to find untriaged issues and triage them one by one. Your triage comments are written for maintainers reviewing the triage, not for the issue author.
Do not make assumptions beyond what the issue content supports. Do not invent missing context.
## Step 1: Find untriaged issues
Use the `search_issues` tool to find open issues that need triage. An issue is considered untriaged if it has **no labels applied**.
Query: `repo:${{ github.repository }} is:issue is:open no:label`
Paginate through all results to find untriaged issues. Do not stop at the first page.
From the results, filter out:
- Issues that already have a triage comment (look for "🎯 Triage report" in comments). **Never retriage an issue that has already been triaged.**
- Issues created by bots (unless they look like real user issues).
- Issues that have any labels already applied (even if they weren't applied by this workflow).
Process the **oldest untriaged issues first**. Note: this workflow is capped at 10 label-sets and 10 comments per run, so the backlog will drain over several daily runs — that is intentional.
## Step 2: Fetch labels (once)
Before triaging any issues, fetch the list of labels available in this repository using the `list_labels` tool. Use this live list for all issues in the batch — only apply labels that actually exist in the repository.
CloudStack uses a prefixed label taxonomy. Choose from these families:
- **Type** (pick the single best one): `type:bug`, `type:new-feature`, `type:enhancement`, `type:improvement`, `type:regression`, `type:security`, `type:question`, `type:config`, `type:cleanup`
- **Component** (apply when clearly identifiable; more than one is allowed): e.g. `component:kvm`, `component:vmware`, `component:XenServer`, `component:api`, `component:UI`, `component:networking`, `component:virtual-router`, `component:management-server`, `component:primary-storage`, `component:secondary-storage`, `component:kubernetes`, `component:database`, and others — use the full list returned by `list_labels`.
- **Severity** (bugs only, when assessable): `Severity:BLOCKER`, `Severity:Critical`, `Severity:Major`, `Severity:Minor`, `Severity:Trivial`
- **Duplicate / invalid**: `status:duplicate`, `status:invalid`
- **Help wanted / newcomer-friendly**: `status:Help-wanted`
## Step 3: Triage each issue
For each untriaged issue, perform the following steps:
### 3a: Gather context
1. Retrieve the full issue content using the `get_issue` tool.
2. Fetch any comments on the issue using the `get_issue_comments` tool.
3. Search for similar issues using the `search_issues` tool.
### 3b: Spam and quality check
**Spam and invalid issues:** If the issue is obviously spam, bot-generated, gibberish, or a test issue:
- Apply the `status:invalid` label.
- **Do not close the issue** — closing is a human decision. Note in the report that it looks like spam/invalid so a maintainer can act.
- Move to the next issue.
**Incomplete issues:** If the issue lacks enough detail for meaningful triage, add a comment that politely asks the author to provide the missing information:
- For bugs: steps to reproduce, expected vs actual behavior, logs/errors, environment details (CloudStack version, hypervisor, etc.).
- For other issue types: equivalent details that would make the report actionable.
- Apply a `type:question` label if appropriate.
- Be specific about what is missing and why it is needed.
- Move to the next issue.
### 3c: Select labels
- Be cautious with labels; they can trigger automation.
- Choose a single `type:*` label that best reflects the issue's nature.
- Add `component:*` label(s) when the affected area is clear from the content.
- Add a `Severity:*` label for bugs when severity can be reasonably assessed.
- Do not apply labels that do not exist in the repository.
- It is better to under-label than to speculatively add labels.
### 3d: Detect duplicates and related issues
- Review the similar issues found in Step 3a.
- Classify matches as:
- **Duplicate** (high confidence): the issue describes the same problem as an existing open issue. Include up to 3.
- **Related**: similar domain or adjacent problem, but not a duplicate. Include up to 3.
- If a high-confidence duplicate is found, apply the `status:duplicate` label.
- If no similar issues are found, state that explicitly in your report.
### 3e: Assess coding agent suitability
Assess whether the issue is suitable for automated coding agent assignment:
- **Suitable**: clear requirements, sufficient context, well-defined success criteria, self-contained scope.
- **Needs more info**: potentially suitable but missing details needed to start.
- **Not suitable**: requires investigation, design decisions, extensive coordination, or policy/architectural choices.
### 3f: Additional analysis
- Search the web for relevant documentation, error messages, or known solutions if applicable.
- Write notes, debugging strategies, and/or reproduction steps relevant to the issue.
- Suggest resources or links that might help resolve the issue.
### 3g: Apply results and post comment
Apply all triage results for this issue:
- Use `update_issue` to apply the chosen labels.
- Add an issue comment with the triage report using the format below.
Then move to the next issue.
## Processing order
1. Fetch available labels (Step 2, once at the start).
2. Find untriaged issues (Step 1).
3. For each issue (oldest first), run Step 3 (gather, check, label, detect duplicates, comment).
## Comment format
Use this structure for each triage comment. Use collapsed sections to keep it tidy.
```markdown
## 🎯 Triage report
{2-3 sentence summary to help a maintainer quickly grasp the issue.}
### 📊 Assessment
| Dimension | Value | Reasoning |
|---|---|---|
| **Type** | [type:* label or "none"] | [brief] |
| **Component** | [component:* label(s) or "none"] | [brief] |
| **Severity** | [Severity:* label or "n/a"] | [brief] |
| **Labels** | [all labels applied or "none"] | [brief] |
| **Coding agent** | [Suitable / Needs more info / Not suitable] | [brief] |
### 🔗 Similar issues
- issue-url (duplicate/related) — [brief explanation]
<details><summary>💡 Notes and suggestions</summary>
{Debugging strategies, reproduction steps, resource links, sub-task checklists, nudges for the team.}
</details>
```
If no similar issues were found, omit the "Similar issues" section. If there are no notes to add, omit the collapsed section.
**Important**: Never close issues. Only apply labels and post comments.

File diff suppressed because it is too large Load Diff

View File

@ -16,21 +16,29 @@ permissions:
network: defaults
engine:
id: copilot
model: claude-haiku-4.5
tools:
github:
# If in a public repo, setting `lockdown: false` allows
# reading issues, pull requests and comments from 3rd-parties
# If in a private repo this has no particular effect.
lockdown: false
min-integrity: none # This workflow is allowed to examine and comment on any issues
safe-outputs:
mentions: false
allowed-github-references: []
create-issue:
title-prefix: "[repo-status] "
labels: [report, daily-status]
source: githubnext/agentics/workflows/daily-repo-status.md@d19056381ba48cb1f7c78510c23069701fa7ae87
close-older-issues: true
source: githubnext/agentics/workflows/repo-status.md@main
---
# Daily Repo Status
# Repo Status
Create an upbeat daily status report for the repo as a GitHub issue.

View File

@ -35,10 +35,10 @@ concurrency:
jobs:
build:
if: github.repository == 'apache/cloudstack'
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Login to Docker Registry
uses: docker/login-action@v4
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ${{ secrets.DOCKER_REGISTRY }}
username: ${{ secrets.DOCKERHUB_USER }}
@ -47,7 +47,9 @@ jobs:
- name: Set Docker repository name
run: echo "DOCKER_REPOSITORY=apache" >> $GITHUB_ENV
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Set ACS version
run: echo "ACS_VERSION=$(grep '<version>' pom.xml | head -2 | tail -1 | cut -d'>' -f2 |cut -d'<' -f1)" >> $GITHUB_ENV

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +0,0 @@
---
on:
schedule: 0 14 * * 1-5
workflow_dispatch: null
permissions:
issues: read
imports:
- github/gh-aw/.github/workflows/shared/reporting.md@94662b1dee8ce96c876ba9f33b3ab8be32de82a4
safe-outputs:
add-comment: {}
add-labels:
allowed:
- bug
- feature
- enhancement
- documentation
- question
- help-wanted
- good-first-issue
source: github/gh-aw/.github/workflows/issue-triage-agent.md@94662b1dee8ce96c876ba9f33b3ab8be32de82a4
strict: true
timeout-minutes: 5
tools:
github:
toolsets:
- issues
- labels
---
# Issue Triage Agent
List open issues in ${{ github.repository }} that have no labels. For each unlabeled issue, analyze the title and body, then add one of the allowed labels: `bug`, `feature`, `enhancement`, `documentation`, `question`, `help-wanted`, or `good-first-issue`.
Skip issues that:
- Already have any of these labels
- Have been assigned to any user (especially non-bot users)
After adding the label to an issue, mention the issue author in a comment using this format (follow shared/reporting.md guidelines):
**Comment Template**:
```markdown
### 🏷️ Issue Triaged
Hi @{author}! I've categorized this issue as **{label_name}** based on the following analysis:
**Reasoning**: {brief_explanation_of_why_this_label}
<details>
<summary><b>View Triage Details</b></summary>
#### Analysis
- **Keywords detected**: {list_of_keywords_that_matched}
- **Issue type indicators**: {what_made_this_fit_the_category}
- **Confidence**: {High/Medium/Low}
#### Recommended Next Steps
- {context_specific_suggestion_1}
- {context_specific_suggestion_2}
</details>
**References**: [Triage run §{run_id}](https://github.com/github/gh-aw/actions/runs/{run_id})
```
**Key formatting requirements**:
- Use h3 (###) for the main heading
- Keep reasoning visible for quick understanding
- Wrap detailed analysis in `<details>` tags
- Include workflow run reference
- Keep total comment concise (collapsed details prevent noise)
## Batch Comment Optimization
For efficiency, if multiple issues are triaged in a single run:
1. Add individual labels to each issue
2. Add a brief comment to each issue (using the template above)
3. Optionally: Create a discussion summarizing all triage actions for that run
This provides both per-issue context and batch visibility.

View File

@ -15,54 +15,53 @@
# specific language governing permissions and limitations
# under the License.
name: Main Branch Sonar Quality Check
name: Sonar Quality Check (Main)
permissions:
contents: read
on:
push:
branches:
- main
permissions:
contents: read # to fetch code (actions/checkout)
pull-requests: write # for sonar to comment on pull-request
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
build:
if: github.repository == 'apache/cloudstack'
name: Main Sonar JaCoCo Build
runs-on: ubuntu-22.04
name: Sonar JaCoCo Coverage
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
- name: Set up JDK17
uses: actions/setup-java@v5
persist-credentials: false
- name: Setup Environment
uses: ./.github/actions/setup-env
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'
install-python: 'true'
install-apt-deps: 'true'
- name: Cache SonarCloud packages
uses: actions/cache@v5
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache local Maven repository
uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('pom.xml', '*/pom.xml', '*/*/pom.xml', '*/*/*/pom.xml') }}
restore-keys: |
${{ runner.os }}-m2
- name: Run Tests with Coverage
- name: Install Non-OSS
uses: ./.github/actions/install-nonoss
- name: Run Build and Tests with Coverage
run: mvn -B -T$(nproc) -P developer,systemvm,quality -Dsimulator -Dnoredist clean install
- name: Upload to SonarQube
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
git clone https://github.com/shapeblue/cloudstack-nonoss.git nonoss
cd nonoss && bash -x install-non-oss.sh && cd ..
mvn -T$(nproc) -P quality -Dsimulator -Dnoredist clean install org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=apache_cloudstack
run: mvn -B -P quality org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=apache_cloudstack -Dsonar.branch.name=${{ github.ref_name }}
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
files: ./client/target/site/jacoco-aggregate/jacoco.xml
fail_ci_if_error: true
flags: unittests
verbose: true
name: codecov
token: ${{ secrets.CODECOV_TOKEN }}
- name: Compute Coverage Grade
run: bash scripts/coverage-grade.sh client/target/site/jacoco-aggregate/jacoco.xml

View File

@ -17,28 +17,26 @@
name: "PR Merge Conflict Check"
on:
push:
pull_request:
types: [opened, synchronize, reopened]
schedule:
- cron: '*/10 * * * *'
workflow_dispatch:
permissions: # added using https://github.com/step-security/secure-workflows
contents: read
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
group: "gh-aw-${{ github.workflow }}"
jobs:
triage:
permissions:
pull-requests: write # for eps1lon/actions-label-merge-conflict to label PRs
runs-on: ubuntu-22.04
pull-requests: write # for eps1lon/actions-label-merge-conflict to label PRs
runs-on: ubuntu-24.04
steps:
- name: Conflict Check
uses: eps1lon/actions-label-merge-conflict@v3.0.3
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"
dirtyLabel: "status:has-conflicts"
removeOnDirtyLabel: "status:ready-for-review"
continueOnMissingPermissions: true
commentOnDirty: "This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch."
- name: Conflict Check
uses: eps1lon/actions-label-merge-conflict@0273be72a0bbd58fcd71d0d6c02c209b50d1e5e1 # v3.1.0
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"
dirtyLabel: "status:has-conflicts"
removeOnDirtyLabel: "status:ready-for-review"
continueOnMissingPermissions: true
commentOnDirty: "This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch."

View File

@ -29,17 +29,23 @@ concurrency:
jobs:
pre-commit:
name: Run pre-commit
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Check Out
uses: actions/checkout@v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.11'
cache: 'pip'
- name: Install
run: |
python -m pip install --upgrade pip
pip install pre-commit
run: pip install pre-commit
- name: Set PY
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
- uses: actions/cache@v5
- name: Cache pre-commit environments
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}

View File

@ -16,32 +16,27 @@
# under the License.
name: License Check
on: [push, pull_request]
on:
- push
- pull_request
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Set up JDK 17
uses: actions/setup-java@v5
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
java-version: '17'
distribution: 'adopt'
architecture: x64
cache: maven
persist-credentials: false
- name: Setup Environment
uses: ./.github/actions/setup-env
- name: Install Non-OSS
uses: ./.github/actions/install-nonoss
- name: RAT licence checks
run: |
git clone https://github.com/shapeblue/cloudstack-nonoss.git nonoss && cd nonoss && bash -x install-non-oss.sh && cd ..
rm -fr nonoss
mvn -P developer,systemvm -Dsimulator -Dnoredist -pl . org.apache.rat:apache-rat-plugin:0.12:check
- name: Rat Report
if: always()

View File

@ -16,58 +16,100 @@
# under the License.
name: Sonar Quality Check
on: [pull_request]
permissions:
contents: read # to fetch code (actions/checkout)
pull-requests: write # for sonar to comment on pull-request
contents: read
pull-requests: write
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
build:
if: github.repository == 'apache/cloudstack' && github.event.pull_request.head.repo.full_name == github.repository
name: Sonar JaCoCo Coverage
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: "refs/pull/${{ github.event.number }}/merge"
fetch-depth: 0
- name: Set up JDK17
uses: actions/setup-java@v5
persist-credentials: false
- name: Setup Environment
uses: ./.github/actions/setup-env
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'
install-python: 'true'
install-apt-deps: 'true'
- name: Cache SonarCloud packages
uses: actions/cache@v5
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache local Maven repository
uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('pom.xml', '*/pom.xml', '*/*/pom.xml', '*/*/*/pom.xml') }}
restore-keys: |
${{ runner.os }}-m2
- name: Install Non-OSS
uses: ./.github/actions/install-nonoss
- name: Run Build and Tests with Coverage
id: coverage
run: mvn -B -T$(nproc) -P developer,systemvm,quality -Dsimulator -Dnoredist clean install
- name: Upload to SonarQube
if: github.repository == 'apache/cloudstack' && github.event.pull_request.head.repo.full_name == github.repository
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
PR_ID: ${{ github.event.pull_request.number }}
HEADREF: ${{ github.event.pull_request.head.ref }}
run: |
git clone https://github.com/shapeblue/cloudstack-nonoss.git nonoss
cd nonoss && bash -x install-non-oss.sh && cd ..
mvn -T$(nproc) -P quality -Dsimulator -Dnoredist clean install org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=apache_cloudstack -Dsonar.pullrequest.key="$PR_ID" -Dsonar.pullrequest.branch="$HEADREF" -Dsonar.pullrequest.github.repository=apache/cloudstack -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.summary_comment=true
mvn -B -P quality org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=apache_cloudstack -Dsonar.pullrequest.key="$PR_ID" -Dsonar.pullrequest.branch="$HEADREF" -Dsonar.pullrequest.github.repository=apache/cloudstack -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.summary_comment=true
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
files: ./client/target/site/jacoco-aggregate/jacoco.xml
fail_ci_if_error: true
flags: unittests
verbose: true
name: codecov
token: ${{ secrets.CODECOV_TOKEN }}
- name: Compute Coverage Grade
id: grade
run: bash scripts/coverage-grade.sh client/target/site/jacoco-aggregate/jacoco.xml
- name: Post Coverage Grade Comment on PR
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const grade = '${{ steps.grade.outputs.coverage_grade }}';
const label = '${{ steps.grade.outputs.coverage_grade_label }}';
const linePct = '${{ steps.grade.outputs.line_coverage }}';
const branchPct = '${{ steps.grade.outputs.branch_coverage }}';
const emojiMap = { A: '🟢', B: '🟡', C: '🟠', D: '🔴', F: '⛔' };
const emoji = emojiMap[grade] ?? '❓';
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const branchRow = branchPct !== 'N/A'
? `| Branch coverage | **${branchPct}%** |`
: '';
const body = [
`## ${emoji} Test Coverage Grade: \`${grade}\` — ${label}`,
'',
'| Metric | Value |',
'|--------|-------|',
`| Line coverage | **${linePct}%** |`,
branchRow,
'',
'### Grade Scale',
'| Grade | Line Coverage | Meaning |',
'|-------|--------------|---------|',
'| 🟢 A | ≥ 80% | Excellent - this code sleeps well at night 😴 |',
'| 🟡 B | 60-79% | Good - almost there, don\'t stop now 😉 |',
'| 🟠 C | 40-59% | Acceptable - your code is wearing a seatbelt, but no airbags 😬 |',
'| 🔴 D | 20-39% | Marginal - boldly shipping where no test has gone before 🖖 |',
'| ⛔ F | < 20% | Failing - tests? what tests? 🔥 |',
'',
'> Branch coverage is shown as a secondary signal. Grade is determined by **line coverage**.',
`> [View full Actions run](${runUrl})`,
].filter(l => l !== undefined).join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body,
});
console.log('Posted coverage grade comment');

View File

@ -28,7 +28,7 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v10
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
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.'
@ -41,7 +41,7 @@ jobs:
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
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
with:
stale-issue-label: 'archive'
days-before-stale: 240

View File

@ -28,15 +28,19 @@ permissions:
jobs:
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Set up Node
uses: actions/setup-node@v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 16
cache: 'npm'
cache-dependency-path: 'ui/package-lock.json'
- name: Env details
run: |
@ -55,7 +59,7 @@ jobs:
npm run lint
npm run test:unit
- uses: codecov/codecov-action@v6
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
if: github.repository == 'apache/cloudstack'
with:
working-directory: ui

View File

@ -151,7 +151,7 @@ repos:
^server/src/test/resources/certs/rsa_self_signed\.key$|
^services/console-proxy/rdpconsole/src/test/doc/rdp-key\.pem$|
^systemvm/agent/certs/localhost\.key$|
^systemvm/agent/certs/realhostip\.key$|
^systemvm/agent/certs/systemvm\.key$|
^test/integration/smoke/test_ssl_offloading\.py$
- id: end-of-file-fixer
exclude: \.vhd$|\.svg$

View File

@ -203,7 +203,7 @@ Unrestricted (TSU) exception (see the BIS Export Administration Regulations, Sec
The following provides more details on the included cryptographic software:
* CloudStack makes use of JaSypt cryptographic libraries.
* CloudStack has a system requirement of MySQL, and uses native database encryption functionality.
* CloudStack requires a MySQL-compatible database (MariaDB or MySQL), and uses native database encryption functionality.
* CloudStack makes use of the Bouncy Castle general-purpose encryption library.
* CloudStack can optionally interact with and control OpenSwan-based VPNs.
* CloudStack has a dependency on and makes use of JSch - a java SSH2 implementation.

View File

@ -78,6 +78,14 @@ zone=default
# Generated with "uuidgen".
local.storage.uuid=
# Enable TLS for image server transfers. The keys are read from:
# cert file = /etc/cloudstack/agent/cloud.crt
# key file = /etc/cloudstack/agent/cloud.key
image.server.tls.enabled=true
# The Address for the network interface that the image server listens on. If not specified, it will listen on the Management network.
#image.server.listen.address=
# Location for KVM virtual router scripts.
# The path defined in this property is relative to the directory "/usr/share/cloudstack-common/".
domr.scripts.dir=scripts/network/domr/kvm

View File

@ -123,6 +123,20 @@ public class AgentProperties{
*/
public static final Property<String> LOCAL_STORAGE_PATH = new Property<>("local.storage.path", "/var/lib/libvirt/images/");
/**
* Enables TLS on the KVM image server transfer endpoint.<br>
* Data type: Boolean.<br>
* Default value: <code>true</code>
*/
public static final Property<Boolean> IMAGE_SERVER_TLS_ENABLED = new Property<>("image.server.tls.enabled", true);
/**
* The IP address that the KVM image server listens on.<br>
* Data type: String.<br>
* Default value: <code>null</code>
*/
public static final Property<String> IMAGE_SERVER_LISTEN_ADDRESS = new Property<>("image.server.listen.address", null, String.class);
/**
* Directory where Qemu sockets are placed.<br>
* These sockets are for the Qemu Guest Agent and SSVM provisioning.<br>

View File

@ -51,6 +51,7 @@ public class VirtualMachineTO {
private long minRam;
private long maxRam;
private long requestedRam;
private String hostName;
private String arch;
private String os;
@ -207,15 +208,20 @@ public class VirtualMachineTO {
return minRam;
}
public void setRam(long minRam, long maxRam) {
public void setRam(long minRam, long maxRam, long requestedRam) {
this.minRam = minRam;
this.maxRam = maxRam;
this.requestedRam = requestedRam;
}
public long getMaxRam() {
return maxRam;
}
public long getRequestedRam() {
return requestedRam;
}
public String getHostName() {
return hostName;
}

View File

@ -43,7 +43,7 @@ import org.apache.cloudstack.storage.object.Bucket;
import org.apache.cloudstack.storage.object.ObjectStore;
import org.apache.cloudstack.storage.sharedfs.SharedFS;
import org.apache.cloudstack.usage.Usage;
import org.apache.cloudstack.vm.schedule.VMSchedule;
import org.apache.cloudstack.schedule.ResourceSchedule;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenterGuestIpv6Prefix;
@ -125,17 +125,18 @@ public class EventTypes {
public static final String EVENT_VM_UNMANAGE = "VM.UNMANAGE";
public static final String EVENT_VM_RECOVER = "VM.RECOVER";
// VM Schedule
public static final String EVENT_VM_SCHEDULE_CREATE = "VM.SCHEDULE.CREATE";
public static final String EVENT_VM_SCHEDULE_UPDATE = "VM.SCHEDULE.UPDATE";
public static final String EVENT_VM_SCHEDULE_DELETE = "VM.SCHEDULE.DELETE";
// VM Schedule action-execution events (fired when a scheduled action runs).
public static final String EVENT_VM_SCHEDULE_START = "VM.SCHEDULE.START";
public static final String EVENT_VM_SCHEDULE_STOP = "VM.SCHEDULE.STOP";
public static final String EVENT_VM_SCHEDULE_REBOOT = "VM.SCHEDULE.REBOOT";
public static final String EVENT_VM_SCHEDULE_FORCE_STOP = "VM.SCHEDULE.FORCE.STOP";
public static final String EVENT_VM_SCHEDULE_FORCE_REBOOT = "VM.SCHEDULE.FORCE.REBOOT";
// Generic Resource Schedule CRUD events (apply to all resource types).
public static final String EVENT_SCHEDULE_CREATE = "SCHEDULE.CREATE";
public static final String EVENT_SCHEDULE_UPDATE = "SCHEDULE.UPDATE";
public static final String EVENT_SCHEDULE_DELETE = "SCHEDULE.DELETE";
// Domain Router
public static final String EVENT_ROUTER_CREATE = "ROUTER.CREATE";
public static final String EVENT_ROUTER_DESTROY = "ROUTER.DESTROY";
@ -676,6 +677,7 @@ public class EventTypes {
public static final String EVENT_AUTOSCALEVMGROUP_DISABLE = "AUTOSCALEVMGROUP.DISABLE";
public static final String EVENT_AUTOSCALEVMGROUP_SCALEDOWN = "AUTOSCALEVMGROUP.SCALEDOWN";
public static final String EVENT_AUTOSCALEVMGROUP_SCALEUP = "AUTOSCALEVMGROUP.SCALEUP";
public static final String EVENT_AUTOSCALEVMGROUP_SCHEDULE_UPDATE = "AUTOSCALEVMGROUP.SCHEDULE.UPDATE";
public static final String EVENT_BAREMETAL_DHCP_SERVER_ADD = "PHYSICAL.DHCP.ADD";
public static final String EVENT_BAREMETAL_DHCP_SERVER_DELETE = "PHYSICAL.DHCP.DELETE";
@ -888,15 +890,18 @@ public class EventTypes {
entityEventDetails.put(EVENT_VM_IMPORT, VirtualMachine.class);
entityEventDetails.put(EVENT_VM_UNMANAGE, VirtualMachine.class);
// VMSchedule
entityEventDetails.put(EVENT_VM_SCHEDULE_CREATE, VMSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_DELETE, VMSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_UPDATE, VMSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_START, VMSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_STOP, VMSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_REBOOT, VMSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_FORCE_STOP, VMSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_FORCE_REBOOT, VMSchedule.class);
// VMSchedule action-execution events
entityEventDetails.put(EVENT_VM_SCHEDULE_START, ResourceSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_STOP, ResourceSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_REBOOT, ResourceSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_FORCE_STOP, ResourceSchedule.class);
entityEventDetails.put(EVENT_VM_SCHEDULE_FORCE_REBOOT, ResourceSchedule.class);
entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_SCHEDULE_UPDATE, ResourceSchedule.class);
// Generic Resource Schedule
entityEventDetails.put(EVENT_SCHEDULE_CREATE, ResourceSchedule.class);
entityEventDetails.put(EVENT_SCHEDULE_UPDATE, ResourceSchedule.class);
entityEventDetails.put(EVENT_SCHEDULE_DELETE, ResourceSchedule.class);
entityEventDetails.put(EVENT_ROUTER_CREATE, VirtualRouter.class);
entityEventDetails.put(EVENT_ROUTER_DESTROY, VirtualRouter.class);

View File

@ -63,6 +63,9 @@ public interface Host extends StateObject<Status>, Identity, Partition, HAResour
String HOST_OVFTOOL_VERSION = "host.ovftool.version";
String HOST_VIRTV2V_VERSION = "host.virtv2v.version";
String HOST_SSH_PORT = "host.ssh.port";
String HOST_CDROM_MAX_COUNT = "host.cdrom.max.count";
String GUEST_OS_CATEGORY_ID = "guest.os.category.id";
String GUEST_OS_RULE = "guest.os.rule";
int DEFAULT_SSH_PORT = 22;

View File

@ -232,7 +232,7 @@ public interface NetworkService {
/**
* Requests an IP address for the guest NIC
*/
NicSecondaryIp allocateSecondaryGuestIP(long nicId, IpAddresses requestedIpPair) throws InsufficientAddressCapacityException;
NicSecondaryIp allocateSecondaryGuestIP(long nicId, IpAddresses requestedIpPair, String description) throws InsufficientAddressCapacityException;
boolean releaseSecondaryIpFromNic(long ipAddressId);

View File

@ -170,6 +170,7 @@ public class Storage {
ISO(false, false, EncryptionSupport.Unsupported), // for iso image
LVM(false, false, EncryptionSupport.Unsupported), // XenServer local LVM SR
CLVM(true, false, EncryptionSupport.Unsupported),
CLVM_NG(true, false, EncryptionSupport.Hypervisor),
RBD(true, true, EncryptionSupport.Unsupported), // http://libvirt.org/storage.html#StorageBackendRBD
SharedMountPoint(true, true, EncryptionSupport.Hypervisor),
VMFS(true, true, EncryptionSupport.Unsupported), // VMware VMFS storage

View File

@ -22,6 +22,7 @@ import java.net.MalformedURLException;
import java.util.List;
import java.util.Map;
import com.cloud.dc.DataCenter;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.offering.DiskOffering;
import com.cloud.user.Account;
@ -70,6 +71,10 @@ public interface VolumeApiService {
*/
Volume allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationException;
Volume allocVolume(long ownerId, Long zoneId, Long diskOfferingId, Long vmId, Long snapshotId, String name,
Long cmdSize, Boolean displayVolume, Long cmdMinIops, Long cmdMaxIops, String customId)
throws ResourceAllocationException;
/**
* Creates the volume based on the given criteria
*
@ -80,6 +85,8 @@ public interface VolumeApiService {
*/
Volume createVolume(CreateVolumeCmd cmd);
Volume createVolume(long volumeId, Long vmId, Long snapshotId, Long storageId, Boolean display);
/**
* Resizes the volume based on the given criteria
*
@ -203,4 +210,6 @@ public interface VolumeApiService {
Pair<String, String> checkAndRepairVolume(CheckAndRepairVolumeCmd cmd) throws ResourceAllocationException;
Long getVolumePhysicalSize(Storage.ImageFormat format, String path, String chainInfo);
Long getCustomDiskOfferingIdForVolumeUpload(Account owner, DataCenter zone, boolean encryptEnabledOnly);
}

View File

@ -88,10 +88,16 @@ public interface AccountService {
Account getActiveAccountById(long accountId);
Account getActiveAccountByUuid(String accountUuid);
Account getAccount(long accountId);
Account getAccountByUuid(String accountUuid);
User getActiveUser(long userId);
User getOneActiveUserForAccount(Account account);
User getUserIncludingRemoved(long userId);
boolean isRootAdmin(Long accountId);

View File

@ -38,6 +38,8 @@ public interface NicSecondaryIp extends ControlledEntity, Identity, InternalIden
String getIp6Address();
String getDescription();
long getNetworkId();
long getVmId();

View File

@ -130,4 +130,10 @@ public interface VmDetailConstants {
String EXTERNAL_DETAIL_PREFIX = "External:";
String CLOUDSTACK_VM_DETAILS = "cloudstack.vm.details";
String CLOUDSTACK_VLAN = "cloudstack.vlan";
// KVM Checkpoints related
String ACTIVE_CHECKPOINT_ID = "active.checkpoint.id";
String ACTIVE_CHECKPOINT_CREATE_TIME = "active.checkpoint.create.time";
String LAST_CHECKPOINT_ID = "last.checkpoint.id";
String LAST_CHECKPOINT_CREATE_TIME = "last.checkpoint.create.time";
}

View File

@ -69,6 +69,8 @@ public class ApiConstants {
public static final String BACKUP_VM_OFFERING_REMOVED = "vmbackupofferingremoved";
public static final String IS_BACKUP_VM_EXPUNGED = "isbackupvmexpunged";
public static final String BACKUP_TOTAL = "backuptotal";
public static final String BALANCE = "balance";
public static final String BALANCES = "balances";
public static final String BASE64_IMAGE = "base64image";
public static final String BGP_PEERS = "bgppeers";
public static final String BGP_PEER_IDS = "bgppeerids";
@ -77,6 +79,7 @@ public class ApiConstants {
public static final String BOOTABLE = "bootable";
public static final String BIND_DN = "binddn";
public static final String BIND_PASSWORD = "bindpass";
public static final String BLANK_INSTANCE = "blankinstance";
public static final String BUS_ADDRESS = "busaddress";
public static final String BYTES_READ_RATE = "bytesreadrate";
public static final String BYTES_READ_RATE_MAX = "bytesreadratemax";
@ -171,6 +174,7 @@ public class ApiConstants {
public static final String DATACENTER_NAME = "datacentername";
public static final String DATADISKS_DETAILS = "datadisksdetails";
public static final String DATADISK_OFFERING_LIST = "datadiskofferinglist";
public static final String DATE = "date";
public static final String DEFAULT_VALUE = "defaultvalue";
public static final String DELETE_PROTECTION = "deleteprotection";
public static final String DESCRIPTION = "description";
@ -217,6 +221,7 @@ public class ApiConstants {
public static final String DOMAIN_PATH = "domainpath";
public static final String DOMAIN_ID = "domainid";
public static final String DOMAIN__ID = "domainId";
public static final String DUMMY = "dummy";
public static final String DURATION = "duration";
public static final String ELIGIBLE = "eligible";
public static final String EMAIL = "email";
@ -260,6 +265,7 @@ public class ApiConstants {
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
public static final String FOR_SYSTEM_VMS = "forsystemvms";
public static final String FOR_PROVIDER = "forprovider";
public static final String FROM_CHECKPOINT_ID = "fromcheckpointid";
public static final String FULL_PATH = "fullpath";
public static final String GATEWAY = "gateway";
public static final String IP6_GATEWAY = "ip6gateway";
@ -332,6 +338,7 @@ public class ApiConstants {
public static final String IS_2FA_VERIFIED = "is2faverified";
public static final String IS_2FA_MANDATED = "is2famandated";
public static final String IS_ACTIVE = "isactive";
public static final String IS_ASYNC = "isasync";
public static final String IP_AVAILABLE = "ipavailable";
public static final String IP_LIMIT = "iplimit";
@ -442,6 +449,7 @@ public class ApiConstants {
public static final String MAX_VGPU_PER_PHYSICAL_GPU = "maxvgpuperphysicalgpu";
public static final String GUEST_OS_LIST = "guestoslist";
public static final String GUEST_OS_COUNT = "guestoscount";
public static final String GUEST_OS_RULE = "guestosrule";
public static final String OS_MAPPING_CHECK_ENABLED = "osmappingcheckenabled";
public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate";
public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled";
@ -595,6 +603,8 @@ public class ApiConstants {
public static final String SUITABLE_FOR_VM = "suitableforvirtualmachine";
public static final String SUPPORTS_STORAGE_SNAPSHOT = "supportsstoragesnapshot";
public static final String TARGET_IQN = "targetiqn";
public static final String TARIFF_ID = "tariffid";
public static final String TARIFF_NAME = "tariffname";
public static final String TASKS_FILTER = "tasksfilter";
public static final String TEMPLATE_FILTER = "templatefilter";
public static final String TEMPLATE_ID = "templateid";
@ -608,6 +618,7 @@ public class ApiConstants {
public static final String TENANT_NAME = "tenantname";
public static final String TOTAL = "total";
public static final String TOTAL_SUBNETS = "totalsubnets";
public static final String TO_CHECKPOINT_ID = "tocheckpointid";
public static final String TOTAL_QUOTA = "totalquota";
public static final String TYPE = "type";
public static final String TRUST_STORE = "truststore";
@ -655,6 +666,7 @@ public class ApiConstants {
public static final String VIRTUAL_MACHINE_STATE = "vmstate";
public static final String VIRTUAL_MACHINES = "virtualmachines";
public static final String USAGE_ID = "usageid";
public static final String USAGE_NAME = "usagename";
public static final String USAGE_TYPE = "usagetype";
public static final String INCLUDE_TAGS = "includetags";
@ -871,6 +883,7 @@ public class ApiConstants {
public static final String IS_SOURCE_NAT = "issourcenat";
public static final String IS_STATIC_NAT = "isstaticnat";
public static final String ITERATIONS = "iterations";
public static final String ITEMS = "items";
public static final String SORT_BY = "sortby";
public static final String CHANGE_CIDR = "changecidr";
public static final String PURPOSE = "purpose";
@ -1330,8 +1343,10 @@ public class ApiConstants {
public static final String VNF_CONFIGURE_MANAGEMENT = "vnfconfiguremanagement";
public static final String VNF_CIDR_LIST = "vnfcidrlist";
public static final String AUTHORIZE_URL = "authorizeurl";
public static final String CLIENT_ID = "clientid";
public static final String REDIRECT_URI = "redirecturi";
public static final String TOKEN_URL = "tokenurl";
public static final String IS_TAG_A_RULE = "istagarule";

View File

@ -21,8 +21,11 @@ import java.util.Map;
import javax.servlet.http.HttpSession;
import org.apache.cloudstack.context.CallContext;
import com.cloud.domain.Domain;
import com.cloud.exception.CloudAuthenticationException;
import com.cloud.user.Account;
import com.cloud.user.UserAccount;
public interface ApiServerService {
@ -52,4 +55,20 @@ public interface ApiServerService {
String getDomainId(Map<String, Object[]> params);
boolean isPostRequestsAndTimestampsEnforced();
AsyncCmdResult processAsyncCmd(BaseAsyncCmd cmdObj, Map<String, String> params, CallContext ctx, Long callerUserId, Account caller) throws Exception;
class AsyncCmdResult {
public final Long objectId;
public final String objectUuid;
public final BaseAsyncCmd asyncCmd;
public final long jobId;
public AsyncCmdResult(Long objectId, String objectUuid, BaseAsyncCmd asyncCmd, long jobId) {
this.objectId = objectId;
this.objectUuid = objectUuid;
this.asyncCmd = asyncCmd;
this.jobId = jobId;
}
}
}

View File

@ -20,7 +20,7 @@ public abstract class BaseAsyncCreateCustomIdCmd extends BaseAsyncCreateCmd {
@Parameter(name = ApiConstants.CUSTOM_ID,
type = CommandType.STRING,
description = "An optional field, in case you want to set a custom id to the resource. Allowed to Root Admins only")
private String customId;
protected String customId;
public String getCustomId() {
return customId;

View File

@ -0,0 +1,100 @@
//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
//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.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.command.admin.AdminCmd;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.ImageTransferResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.backup.ImageTransfer;
import org.apache.cloudstack.backup.KVMBackupExportService;
import org.apache.cloudstack.context.CallContext;
import com.cloud.utils.EnumUtils;
@APICommand(name = "createImageTransfer",
description = "Create image transfer for a disk in backup. This API is intended for testing only and is disabled by default.",
responseObject = ImageTransferResponse.class,
since = "4.23.0",
authorized = {RoleType.Admin})
public class CreateImageTransferCmd extends BaseCmd implements AdminCmd {
@Inject
private KVMBackupExportService kvmBackupExportService;
@Parameter(name = ApiConstants.BACKUP_ID,
type = CommandType.UUID,
entityType = BackupResponse.class,
description = "ID of the backup")
private Long backupId;
@Parameter(name = ApiConstants.VOLUME_ID,
type = CommandType.UUID,
entityType = VolumeResponse.class,
required = true,
description = "ID of the disk/volume")
private Long volumeId;
@Parameter(name = ApiConstants.DIRECTION,
type = CommandType.STRING,
required = true,
description = "Direction of the transfer: upload, download")
private String direction;
@Parameter(name = ApiConstants.FORMAT,
type = CommandType.STRING,
description = "Format for the image transfer: raw/cow. 'raw' will create an NBD backend. 'cow' will use the File backend." +
"For download, only the 'raw' format is supported. Default: raw")
private String format;
public Long getBackupId() {
return backupId;
}
public Long getVolumeId() {
return volumeId;
}
public ImageTransfer.Direction getDirection() {
return ImageTransfer.Direction.valueOf(direction);
}
public ImageTransfer.Format getFormat() {
return EnumUtils.getEnum(ImageTransfer.Format.class, format);
}
@Override
public void execute() {
ImageTransferResponse response = kvmBackupExportService.createImageTransfer(this);
response.setObjectName(ImageTransfer.class.getSimpleName().toLowerCase());
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -0,0 +1,85 @@
//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
//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.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.command.admin.AdminCmd;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.KVMBackupExportService;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = "deleteVirtualMachineCheckpoint",
description = "Delete a VM checkpoint. This API is intended for testing only and is disabled by default.",
responseObject = SuccessResponse.class,
since = "4.23.0",
authorized = {RoleType.Admin})
public class DeleteVmCheckpointCmd extends BaseCmd implements AdminCmd {
@Inject
private KVMBackupExportService kvmBackupExportService;
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the VM")
private Long vmId;
@Parameter(name = "checkpointid",
type = CommandType.STRING,
required = true,
description = "Checkpoint ID")
private String checkpointId;
public Long getVmId() {
return vmId;
}
public String getCheckpointId() {
return checkpointId;
}
public void setVmId(Long vmId) {
this.vmId = vmId;
}
public void setCheckpointId(String checkpointId) {
this.checkpointId = checkpointId;
}
@Override
public void execute() {
boolean result = kvmBackupExportService.deleteVmCheckpoint(this);
SuccessResponse response = new SuccessResponse(getCommandName());
response.setSuccess(result);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -0,0 +1,103 @@
//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
//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.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.AdminCmd;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.KVMBackupExportService;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
@APICommand(name = "finalizeBackup",
description = "Finalize a VM backup session. This API is intended for testing only and is disabled by default.",
responseObject = BackupResponse.class,
since = "4.23.0",
authorized = {RoleType.Admin})
public class FinalizeBackupCmd extends BaseAsyncCmd implements AdminCmd {
@Inject
private KVMBackupExportService kvmBackupExportService;
@Inject
private BackupManager backupManager;
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the VM")
private Long vmId;
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = BackupResponse.class,
required = true,
description = "ID of the backup")
private Long backupId;
public Long getVmId() {
return vmId;
}
public Long getBackupId() {
return backupId;
}
@Override
public void execute() {
Backup backup = kvmBackupExportService.finalizeBackup(this);
if (backup == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Backup");
}
BackupResponse response = backupManager.createBackupResponse(backup, null);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_CREATE;
}
@Override
public String getEventDescription() {
return "Finalizing backup " + backupId;
}
}

View File

@ -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
//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.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.command.admin.AdminCmd;
import org.apache.cloudstack.api.response.ImageTransferResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.backup.ImageTransfer;
import org.apache.cloudstack.backup.KVMBackupExportService;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = "finalizeImageTransfer",
description = "Finalize an image transfer. This API is intended for testing only and is disabled by default.",
responseObject = SuccessResponse.class,
since = "4.23.0",
authorized = {RoleType.Admin})
public class FinalizeImageTransferCmd extends BaseCmd implements AdminCmd {
@Inject
private KVMBackupExportService kvmBackupExportService;
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = ImageTransferResponse.class,
required = true,
description = "ID of the image transfer")
private Long imageTransferId;
public Long getImageTransferId() {
return imageTransferId;
}
@Override
public void execute() {
boolean result = kvmBackupExportService.finalizeImageTransfer(this);
SuccessResponse response = new SuccessResponse(getCommandName());
response.setSuccess(result);
response.setObjectName(ImageTransfer.class.getSimpleName().toLowerCase());
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -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
//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.backup;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.command.admin.AdminCmd;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.ImageTransferResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.backup.ImageTransfer;
import org.apache.cloudstack.backup.KVMBackupExportService;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = "listImageTransfers",
description = "List image transfers for a backup. This API is intended for testing only and is disabled by default.",
responseObject = ImageTransferResponse.class,
since = "4.23.0",
authorized = {RoleType.Admin})
public class ListImageTransfersCmd extends BaseListCmd implements AdminCmd {
@Inject
private KVMBackupExportService kvmBackupExportService;
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = ImageTransferResponse.class,
description = "ID of the Image Transfer")
private Long id;
@Parameter(name = ApiConstants.BACKUP_ID,
type = CommandType.UUID,
entityType = BackupResponse.class,
description = "ID of the backup")
private Long backupId;
public Long getId() {
return id;
}
public Long getBackupId() {
return backupId;
}
@Override
public void execute() {
List<ImageTransferResponse> responses = kvmBackupExportService.listImageTransfers(this);
ListResponse<ImageTransferResponse> response = new ListResponse<>();
response.setResponses(responses);
response.setObjectName(ImageTransfer.class.getSimpleName().toLowerCase());
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -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
//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.backup;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.command.admin.AdminCmd;
import org.apache.cloudstack.api.response.CheckpointResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.KVMBackupExportService;
@APICommand(name = "listVirtualMachineCheckpoints",
description = "List checkpoints for a VM. This API is intended for testing only and is disabled by default.",
responseObject = CheckpointResponse.class,
since = "4.23.0",
authorized = {RoleType.Admin})
public class ListVmCheckpointsCmd extends BaseListCmd implements AdminCmd {
@Inject
private KVMBackupExportService kvmBackupExportService;
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the VM")
private Long vmId;
public Long getVmId() {
return vmId;
}
@Override
public void execute() {
List<CheckpointResponse> responses = kvmBackupExportService.listVmCheckpoints(this);
ListResponse<CheckpointResponse> response = new ListResponse<>();
response.setResponses(responses);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return 0;
}
}

View File

@ -0,0 +1,120 @@
//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
//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.backup;
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.BaseAsyncCreateCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.AdminCmd;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.KVMBackupExportService;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
@APICommand(name = "startBackup",
description = "Start a VM backup session using pull mode backup-begin on the KVM host. This API is intended for testing only and is disabled by default.",
responseObject = BackupResponse.class,
since = "4.23.0",
authorized = {RoleType.Admin})
public class StartBackupCmd extends BaseAsyncCreateCmd implements AdminCmd {
@Inject
private KVMBackupExportService kvmBackupExportService;
@Inject
private BackupManager backupManager;
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the VM")
private Long vmId;
@Parameter(name = ApiConstants.NAME,
type = CommandType.STRING,
description = "the name of the backup")
private String name;
@Parameter(name = ApiConstants.DESCRIPTION,
type = CommandType.STRING,
description = "the description for the backup")
private String description;
public Long getVmId() {
return vmId;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public void execute() {
try {
Backup backup = kvmBackupExportService.startBackup(this);
BackupResponse response = backupManager.createBackupResponse(backup, null);
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public void create() {
Backup backup = kvmBackupExportService.createBackup(this);
if (backup != null) {
setEntityId(backup.getId());
setEntityUuid(backup.getUuid());
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Backup");
}
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_CREATE;
}
@Override
public String getEventDescription() {
return "Starting backup for Instance " + vmId;
}
}

View File

@ -63,6 +63,12 @@ public class ProvisionCertificateCmd extends BaseAsyncCmd {
description = "Name of the CA service provider, otherwise the default configured provider plugin will be used")
private String provider;
@Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN,
description = "When true, uses SSH to re-provision the agent's certificate, bypassing the NIO agent connection. " +
"Use this when agents are disconnected due to a CA change. Supported for KVM hosts and SystemVMs. Default is false",
since = "4.23.0")
private Boolean forced;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -79,6 +85,10 @@ public class ProvisionCertificateCmd extends BaseAsyncCmd {
return provider;
}
public boolean isForced() {
return forced != null && forced;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@ -90,7 +100,7 @@ public class ProvisionCertificateCmd extends BaseAsyncCmd {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId());
}
boolean result = caManager.provisionCertificate(host, getReconnect(), getProvider());
boolean result = caManager.provisionCertificate(host, getReconnect(), getProvider(), isForced());
SuccessResponse response = new SuccessResponse(getCommandName());
response.setSuccess(result);
setResponseObject(response);

View File

@ -19,23 +19,23 @@ package org.apache.cloudstack.api.command.admin.config;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConfigurationResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration;
import org.apache.commons.lang3.StringUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.utils.Pair;
@ -94,6 +94,13 @@ public class ListCfgsByCmd extends BaseListCmd {
description = "The ID of the Image Store to update the parameter value for corresponding image store")
private Long imageStoreId;
@Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID,
type = CommandType.UUID,
entityType = ManagementServerResponse.class,
description = "the ID of the Management Server to update the parameter value for corresponding management server",
since = "4.23.0")
private Long managementServerId;
@Parameter(name = ApiConstants.GROUP, type = CommandType.STRING, description = "Lists configuration by group name (primarily used for UI)", since = "4.18.0")
private String groupName;
@ -139,6 +146,10 @@ public class ListCfgsByCmd extends BaseListCmd {
return imageStoreId;
}
public Long getManagementServerId() {
return managementServerId;
}
public String getGroupName() {
return groupName;
}
@ -200,6 +211,9 @@ public class ListCfgsByCmd extends BaseListCmd {
if (getImageStoreId() != null){
cfgResponse.setScope("imagestore");
}
if (getManagementServerId() != null){
cfgResponse.setScope("managementserver");
}
}
@Override

View File

@ -23,16 +23,16 @@ 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.ImageStoreResponse;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConfigurationResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration;
import org.apache.cloudstack.framework.config.ConfigKey;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
@ -84,6 +84,13 @@ public class ResetCfgCmd extends BaseCmd {
description = "The ID of the Image Store to reset the parameter value for corresponding image store")
private Long imageStoreId;
@Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID,
type = CommandType.UUID,
entityType = ManagementServerResponse.class,
description = "the ID of the Management Server to update the parameter value for corresponding management server",
since = "4.23.0")
private Long managementServerId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -116,6 +123,10 @@ public class ResetCfgCmd extends BaseCmd {
return imageStoreId;
}
public Long getManagementServerId() {
return managementServerId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@ -149,6 +160,9 @@ public class ResetCfgCmd extends BaseCmd {
if (getImageStoreId() != null) {
response.setScope(ConfigKey.Scope.ImageStore.name());
}
if (getManagementServerId() != null) {
response.setScope(ConfigKey.Scope.ManagementServer.name());
}
response.setValue(cfg.second());
this.setResponseObject(response);
} else {

View File

@ -16,9 +16,7 @@
// under the License.
package org.apache.cloudstack.api.command.admin.config;
import com.cloud.utils.crypt.DBEncryptionUtil;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
@ -29,13 +27,17 @@ import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConfigurationResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.commons.lang3.StringUtils;
import com.cloud.user.Account;
import com.cloud.utils.crypt.DBEncryptionUtil;
@APICommand(name = "updateConfiguration", description = "Updates a configuration.", responseObject = ConfigurationResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@ -88,6 +90,13 @@ public class UpdateCfgCmd extends BaseCmd {
validations = ApiArgValidator.PositiveNumber)
private Long imageStoreId;
@Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID,
type = CommandType.UUID,
entityType = ManagementServerResponse.class,
description = "the ID of the Management Server to update the parameter value for corresponding management server",
since = "4.23.0")
private Long managementServerId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -112,7 +121,7 @@ public class UpdateCfgCmd extends BaseCmd {
return clusterId;
}
public Long getStoragepoolId() {
public Long getStoragePoolId() {
return storagePoolId;
}
@ -128,6 +137,10 @@ public class UpdateCfgCmd extends BaseCmd {
return imageStoreId;
}
public Long getManagementServerId() {
return managementServerId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@ -182,7 +195,7 @@ public class UpdateCfgCmd extends BaseCmd {
if (getClusterId() != null) {
response.setScope("cluster");
}
if (getStoragepoolId() != null) {
if (getStoragePoolId() != null) {
response.setScope("storagepool");
}
if (getAccountId() != null) {
@ -191,6 +204,9 @@ public class UpdateCfgCmd extends BaseCmd {
if (getDomainId() != null) {
response.setScope("domain");
}
if (getManagementServerId() != null) {
response.setScope(ConfigKey.Scope.ManagementServer.name().toLowerCase());
}
return response;
}
}

View File

@ -49,9 +49,14 @@ public class UpdateHostCmd extends BaseCmd {
@Parameter(name = ApiConstants.OS_CATEGORY_ID,
type = CommandType.UUID,
entityType = GuestOSCategoryResponse.class,
description = "The ID of OS category to update the host with")
description = "the ID of OS category used to prioritize VMs with matching OS category during the allocation process. " +
"It cannot be used alongside the 'guestosrule' parameter.")
private Long osCategoryId;
@Parameter(name = ApiConstants.GUEST_OS_RULE, type = CommandType.STRING, description = "the guest OS rule written in JavaScript to match with the OS of the VM." +
"It cannot be used alongside the 'oscategoryid' parameter.")
private String guestOsRule;
@Parameter(name = ApiConstants.ALLOCATION_STATE,
type = CommandType.STRING,
description = "Change resource state of host, valid values are [Enable, Disable]. Operation may failed if host in states not allowing Enable/Disable")
@ -96,6 +101,10 @@ public class UpdateHostCmd extends BaseCmd {
return osCategoryId;
}
public String getGuestOsRule() {
return guestOsRule;
}
public String getAllocationState() {
return allocationState;
}

View File

@ -22,7 +22,7 @@ import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.ApiArgValidator;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.UserAccount;
@ -35,7 +35,7 @@ public class GetUserCmd extends BaseCmd {
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.USER_API_KEY, type = CommandType.STRING, required = true, description = "API key of the user")
@Parameter(name = ApiConstants.USER_API_KEY, type = CommandType.STRING, required = true, description = "API key of the user", validations = {ApiArgValidator.NotNullOrEmpty})
private String apiKey;
/////////////////////////////////////////////////////

View File

@ -50,7 +50,7 @@ public class RegisterUserKeysCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "API key pair name.")
private String name;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "API key pair description.")
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "API key pair description.", length = 1024)
private String description;
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, description = "Start date of the API key pair. " +
@ -138,6 +138,9 @@ public class RegisterUserKeysCmd extends BaseAsyncCmd {
String description = detail.get(ApiConstants.DESCRIPTION);
if (StringUtils.isNotEmpty(description)) {
if (description.length() > 255) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Rule description cannot be longer than 255 characters.");
}
ruleDetails.put(ApiConstants.DESCRIPTION, description);
}

View File

@ -85,6 +85,9 @@ public class AssignVMCmd extends BaseCmd {
"In case no security groups are provided the Instance is part of the default security group.")
private List<Long> securityGroupIdList;
// Internal flag to allow assignment without adding a network
private boolean skipNetwork = false;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -113,6 +116,34 @@ public class AssignVMCmd extends BaseCmd {
return securityGroupIdList;
}
public boolean isSkipNetwork() {
return skipNetwork;
}
/////////////////////////////////////////////////////
/////////////////// Setters /////////////////////////
/////////////////////////////////////////////////////
public void setVirtualMachineId(Long virtualMachineId) {
this.virtualMachineId = virtualMachineId;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public void setProjectId(Long projectId) {
this.projectId = projectId;
}
public void setSkipNetwork(boolean skipNetwork) {
this.skipNetwork = skipNetwork;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -41,6 +41,19 @@ public class DeployVMCmdByAdmin extends DeployVMCmd implements AdminCmd {
@Parameter(name = ApiConstants.CLUSTER_ID, type = CommandType.UUID, entityType = ClusterResponse.class, description = "Destination Cluster ID to deploy the Instance to - parameter available for root admin only", since = "4.13")
private Long clusterId;
@Parameter(name = ApiConstants.BLANK_INSTANCE,
type = CommandType.BOOLEAN,
description = "Whether to create a blank instance without storage and network",
since = "4.23.0")
private Boolean blankInstance;
// Internal flag to allow deploying instance with a given type
private String instanceType;
/////////////////////////////////////////////////////
////////////////// Getters //////////////////////////
/////////////////////////////////////////////////////
public Long getPodId() {
return podId;
}
@ -48,4 +61,37 @@ public class DeployVMCmdByAdmin extends DeployVMCmd implements AdminCmd {
public Long getClusterId() {
return clusterId;
}
@Override
public boolean isBlankInstance() {
return Boolean.TRUE.equals(blankInstance);
}
@Override
public String getInstanceType() {
if (!isBlankInstance()) {
return null;
}
return instanceType;
}
/////////////////////////////////////////////////////
////////////////// Setters //////////////////////////
/////////////////////////////////////////////////////
public void setClusterId(Long clusterId) {
this.clusterId = clusterId;
}
public void setBlankInstance(boolean blankInstance) {
this.blankInstance = blankInstance;
}
public void setInstanceType(String instanceType) {
this.instanceType = instanceType;
}
public void setCustomId(String customId) {
this.customId = customId;
}
}

View File

@ -17,6 +17,8 @@
package org.apache.cloudstack.api.command.admin.vm;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject.ResponseView;
import org.apache.cloudstack.api.command.admin.AdminCmd;
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
@ -27,4 +29,20 @@ import com.cloud.vm.VirtualMachine;
@APICommand(name = "destroyVirtualMachine", description = "Destroys an Instance. Once destroyed, only the administrator can recover it.", responseObject = UserVmResponse.class, responseView = ResponseView.Full, entityType = {VirtualMachine.class},
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = true)
public class DestroyVMCmdByAdmin extends DestroyVMCmd implements AdminCmd {}
public class DestroyVMCmdByAdmin extends DestroyVMCmd implements AdminCmd {
@Parameter( name = ApiConstants.FORCED,
type = CommandType.BOOLEAN,
description = "Force destroy the Instance",
since = "4.23.0")
Boolean forced;
@Override
public boolean isForced() {
return Boolean.TRUE.equals(forced);
}
public void setForced(Boolean forced) {
this.forced = forced;
}
}

View File

@ -21,6 +21,7 @@ import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
@ -102,6 +103,16 @@ public class AssignVirtualMachineToBackupOfferingCmd extends BaseAsyncCmd {
return CallContext.current().getCallingAccount().getId();
}
@Override
public Long getApiResourceId() {
return vmId;
}
@Override
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.VirtualMachine;
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_OFFERING_ASSIGN;

View File

@ -123,7 +123,12 @@ public class CreateBackupCmd extends BaseAsyncCreateCmd {
@Override
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.Backup;
return ApiCommandResourceType.VirtualMachine;
}
@Override
public Long getApiResourceId() {
return vmId;
}
@Override

View File

@ -21,6 +21,7 @@ import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
@ -81,7 +82,7 @@ public class CreateBackupScheduleCmd extends BaseCmd {
@Parameter(name = ApiConstants.QUIESCE_VM,
type = CommandType.BOOLEAN,
required = false,
description = "Quiesce the instance before checkpointing the disks for backup. Applicable only to NAS backup provider. " +
description = "Quiesce the Instance before checkpointing the disks for backup. Applicable only to NAS backup provider. " +
"The filesystem is frozen before the backup starts and thawed immediately after. " +
"Requires the instance to have the QEMU Guest Agent installed and running.",
since = "4.21.0")
@ -139,4 +140,14 @@ public class CreateBackupScheduleCmd extends BaseCmd {
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public Long getApiResourceId() {
return vmId;
}
@Override
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.VirtualMachine;
}
}

View File

@ -21,6 +21,7 @@ import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
@ -99,6 +100,16 @@ public class RemoveVirtualMachineFromBackupOfferingCmd extends BaseAsyncCmd {
return CallContext.current().getCallingAccount().getId();
}
@Override
public Long getApiResourceId() {
return vmId;
}
@Override
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.VirtualMachine;
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_OFFERING_REMOVE;

View File

@ -22,6 +22,7 @@ import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
@ -127,4 +128,14 @@ public class RestoreVolumeFromBackupAndAttachToVMCmd extends BaseAsyncCmd {
public String getEventDescription() {
return "Restoring volume "+ volumeUuid + " from backup " + getResourceUuid(ApiConstants.BACKUP_ID) + " and attaching it to Instance " + getResourceUuid(ApiConstants.VIRTUAL_MACHINE_ID);
}
@Override
public Long getApiResourceId() {
return vmId;
}
@Override
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.VirtualMachine;
}
}

View File

@ -27,6 +27,7 @@ import org.apache.cloudstack.api.ResponseObject.ResponseView;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.user.UserCmd;
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
import org.apache.cloudstack.api.response.TemplateResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import com.cloud.event.EventTypes;
@ -51,6 +52,10 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd {
description = "If true, ejects the ISO before detaching on VMware. Default: false", since = "4.15.1")
protected Boolean forced;
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = TemplateResponse.class,
description = "The ID of the ISO to detach. Required when the Instance has more than one ISO attached.", since = "4.23.0")
protected Long id;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -104,7 +109,7 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd {
@Override
public void execute() {
boolean result = _templateService.detachIso(virtualMachineId, null, isForced());
boolean result = _templateService.detachIso(virtualMachineId, id, isForced());
if (result) {
UserVm userVm = _entityMgr.findById(UserVm.class, virtualMachineId);
UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", userVm).get(0);

View File

@ -193,6 +193,22 @@ public class ListServiceOfferingsCmd extends BaseListProjectAndAccountResourcesC
return gpuEnabled;
}
public void setZoneId(Long zoneId) {
this.zoneId = zoneId;
}
public void setCpuNumber(Integer cpuNumber) {
this.cpuNumber = cpuNumber;
}
public void setMemory(Integer memory) {
this.memory = memory;
}
public void setEncryptRoot(Boolean encryptRoot) {
this.encryptRoot = encryptRoot;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -0,0 +1,132 @@
// 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.user.schedule;
import com.cloud.exception.InvalidParameterValueException;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ResourceScheduleResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.schedule.ResourceScheduleManager;
import org.apache.commons.lang3.EnumUtils;
import javax.inject.Inject;
import java.util.Date;
import java.util.Map;
@APICommand(name = "createResourceSchedule", description = "Create Resource Schedule", responseObject = ResourceScheduleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.23.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class CreateResourceScheduleCmd extends BaseCmd {
@Inject
ResourceScheduleManager resourceScheduleManager;
@Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.STRING, required = true, description = "Type of the resource")
private String resourceType;
@Parameter(name = ApiConstants.RESOURCE_ID, type = CommandType.STRING, required = true, description = "ID of the resource for which schedule is to be defined")
private String resourceId;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, required = false, description = "Description of the schedule")
private String description;
@Parameter(name = ApiConstants.SCHEDULE, type = CommandType.STRING, required = true, description = "Schedule for action on resource in cron format. e.g. '0 15 10 * *' for 'at 15:00 on 10th day of every month'")
private String schedule;
@Parameter(name = ApiConstants.TIMEZONE, type = CommandType.STRING, required = true, description = "Specifies a timezone for this command. For more information on the timezone parameter, see TimeZone Format.")
private String timeZone;
@Parameter(name = ApiConstants.ACTION, type = CommandType.STRING, required = true, description = "Action to take on the resource.")
private String action;
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, required = false, description = "Start date from which the schedule becomes active. Defaults to current date plus 1 minute. (Format \"yyyy-MM-dd hh:mm:ss\")")
private Date startDate;
@Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, required = false, description = "End date after which the schedule becomes inactive. (Format \"yyyy-MM-dd hh:mm:ss\")")
private Date endDate;
@Parameter(name = ApiConstants.ENABLED, type = CommandType.BOOLEAN, required = false, description = "Enable schedule. Defaults to true")
private Boolean enabled;
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required = false, description = "Map of (key/value pairs) details for the schedule.")
private Map details;
public ApiCommandResourceType getResourceType() {
ApiCommandResourceType type = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, resourceType);
if (type == null) {
throw new InvalidParameterValueException("Unknown resource type: " + resourceType);
}
return type;
}
public String getResourceId() {
return resourceId;
}
public String getDescription() {
return description;
}
public String getSchedule() {
return schedule;
}
public String getTimeZone() {
return timeZone;
}
public String getAction() {
return action;
}
public Date getStartDate() {
return startDate;
}
public Date getEndDate() {
return endDate;
}
public Boolean getEnabled() {
if (enabled == null) {
enabled = true;
}
return enabled;
}
public Map<String, String> getDetails() {
return convertDetailsToMap(details);
}
@Override
public void execute() {
ResourceScheduleResponse response = resourceScheduleManager.createSchedule(getResourceType(), getResourceId(),
getDescription(), getSchedule(), getTimeZone(), getAction(), getStartDate(), getEndDate(), getEnabled(), getDetails());
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getAccountId();
}
}

View File

@ -0,0 +1,86 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.user.schedule;
import com.cloud.exception.InvalidParameterValueException;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ResourceScheduleResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.schedule.ResourceScheduleManager;
import org.apache.commons.lang3.EnumUtils;
import javax.inject.Inject;
import java.util.List;
@APICommand(name = "deleteResourceSchedule", description = "Delete Resource Schedule", responseObject = SuccessResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.23.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class DeleteResourceScheduleCmd extends BaseCmd {
@Inject
ResourceScheduleManager resourceScheduleManager;
@Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.STRING, required = true, description = "Type of the resource")
private String resourceType;
@Parameter(name = ApiConstants.RESOURCE_ID, type = CommandType.STRING, required = true, description = "ID of the resource for which schedules are to be deleted")
private String resourceId;
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ResourceScheduleResponse.class, required = false, description = "ID of the schedule to be deleted")
private Long id;
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = ResourceScheduleResponse.class, required = false, description = "comma separated list of schedule ids to be deleted")
private List<Long> ids;
public ApiCommandResourceType getResourceType() {
ApiCommandResourceType type = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, resourceType);
if (type == null) {
throw new InvalidParameterValueException("Unknown resource type: " + resourceType);
}
return type;
}
public String getResourceId() {
return resourceId;
}
public Long getId() {
return id;
}
public List<Long> getIds() {
return ids;
}
@Override
public void execute() {
resourceScheduleManager.removeSchedule(getResourceType(), getResourceId(), getId(), getIds());
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getAccountId();
}
}

View File

@ -0,0 +1,97 @@
// 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.user.schedule;
import com.cloud.exception.InvalidParameterValueException;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ResourceScheduleResponse;
import org.apache.cloudstack.schedule.ResourceScheduleManager;
import org.apache.commons.lang3.EnumUtils;
import javax.inject.Inject;
import java.util.List;
@APICommand(name = "listResourceSchedule", description = "List Resource Schedules", responseObject = ResourceScheduleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.23.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class ListResourceScheduleCmd extends BaseListCmd {
@Inject
ResourceScheduleManager resourceScheduleManager;
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ResourceScheduleResponse.class, required = false, description = "ID of the schedule")
private Long id;
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = ResourceScheduleResponse.class, required = false, description = "comma separated list of schedule ids")
private List<Long> ids;
@Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.STRING, required = true, description = "Type of the resource.")
private String resourceType;
@Parameter(name = ApiConstants.RESOURCE_ID, type = CommandType.STRING, required = true, description = "ID of the resource for which schedules are to be listed.")
private String resourceId;
@Parameter(name = ApiConstants.ACTION, type = CommandType.STRING, required = false, description = "Action to take on the resource.")
private String action;
@Parameter(name = ApiConstants.ENABLED, type = CommandType.BOOLEAN, required = false, description = "Filter by enabled status.")
private Boolean enabled;
public Long getId() {
return id;
}
public List<Long> getIds() {
return ids;
}
public ApiCommandResourceType getResourceType() {
ApiCommandResourceType type = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, resourceType);
if (type == null) {
throw new InvalidParameterValueException("Unknown resource type: " + resourceType);
}
return type;
}
public String getResourceId() {
return resourceId;
}
public String getAction() {
return action;
}
public Boolean getEnabled() {
return enabled;
}
@Override
public void execute() {
ListResponse<ResourceScheduleResponse> response = resourceScheduleManager.listSchedule(
getId(), getIds(), getResourceType(), getResourceId(), getAction(), getEnabled(),
getStartIndex(), getPageSizeVal()
);
response.setResponseName(getCommandName());
setResponseObject(response);
}
}

View File

@ -0,0 +1,108 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.user.schedule;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ResourceScheduleResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.schedule.ResourceScheduleManager;
import javax.inject.Inject;
import java.util.Date;
import java.util.Map;
@APICommand(name = "updateResourceSchedule", description = "Update Resource Schedule", responseObject = ResourceScheduleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.23.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class UpdateResourceScheduleCmd extends BaseCmd {
@Inject
ResourceScheduleManager resourceScheduleManager;
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ResourceScheduleResponse.class, required = true, description = "ID of the schedule to be updated")
private Long id;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, required = false, description = "Description of the schedule")
private String description;
@Parameter(name = ApiConstants.SCHEDULE, type = CommandType.STRING, required = false, description = "Schedule for action on resource in cron format.")
private String schedule;
@Parameter(name = ApiConstants.TIMEZONE, type = CommandType.STRING, required = false, description = "Specifies a timezone for this command.")
private String timeZone;
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, required = false, description = "Start date from which the schedule becomes active.")
private Date startDate;
@Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, required = false, description = "End date after which the schedule becomes inactive.")
private Date endDate;
@Parameter(name = ApiConstants.ENABLED, type = CommandType.BOOLEAN, required = false, description = "Enable or disable the schedule.")
private Boolean enabled;
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required = false, description = "Map of (key/value pairs) details for the schedule.")
private Map details;
public Long getId() {
return id;
}
public String getDescription() {
return description;
}
public String getSchedule() {
return schedule;
}
public String getTimeZone() {
return timeZone;
}
public Date getStartDate() {
return startDate;
}
public Date getEndDate() {
return endDate;
}
public Boolean getEnabled() {
return enabled;
}
public Map<String, String> getDetails() {
return convertDetailsToMap(details);
}
@Override
public void execute() {
ResourceScheduleResponse response = resourceScheduleManager.updateSchedule(getId(), getDescription(), getSchedule(),
getTimeZone(), getStartDate(), getEndDate(), getEnabled(), getDetails());
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getAccountId();
}
}

View File

@ -56,6 +56,9 @@ public class AddIpToVmNicCmd extends BaseAsyncCreateCmd {
@Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, required = false, description = "Secondary IP Address")
private String ipAddr;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, required = false, description = "Description of the secondary IP address", length = 2048)
private String description;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -160,7 +163,7 @@ public class AddIpToVmNicCmd extends BaseAsyncCreateCmd {
}
try {
result = _networkService.allocateSecondaryGuestIP(getNicId(), requestedIpPair);
result = _networkService.allocateSecondaryGuestIP(getNicId(), requestedIpPair, description);
if (result != null) {
setEntityId(result.getId());
setEntityUuid(result.getUuid());

View File

@ -100,6 +100,26 @@ public class AddNicToVMCmd extends BaseAsyncCmd implements UserCmd {
return NetUtils.standardizeMacAddress(macaddr);
}
public void setVmId(Long vmId) {
this.vmId = vmId;
}
public void setNetworkId(Long netId) {
this.netId = netId;
}
public void setIpaddr(String ipaddr) {
this.ipaddr = ipaddr;
}
public void setMacAddress(String macaddr) {
this.macaddr = macaddr;
}
public void setDhcpOptions(Map dhcpOptions) {
this.dhcpOptions = dhcpOptions;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -61,10 +61,10 @@ import com.cloud.network.Network;
import com.cloud.network.Network.IpAddresses;
import com.cloud.offering.DiskOffering;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.utils.net.Dhcp;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VmDetailConstants;
import com.cloud.vm.VmDiskInfo;
import com.cloud.utils.net.Dhcp;
public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityGroupAction, UserCmd {
@ -75,13 +75,13 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "availability zone for the virtual machine")
private Long zoneId;
protected Long zoneId;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "host name for the virtual machine", validations = {ApiArgValidator.RFCComplianceDomainName})
private String name;
protected String name;
@Parameter(name = ApiConstants.DISPLAY_NAME, type = CommandType.STRING, description = "an optional user generated name for the virtual machine")
private String displayName;
protected String displayName;
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="The password of the virtual machine. If null, a random password will be generated for the VM.",
since="4.19.0.0")
@ -89,21 +89,21 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
//Owner information
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the virtual machine. Must be used with domainId.")
private String accountName;
protected String accountName;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used. If account is NOT provided then virtual machine will be assigned to the caller account and domain.")
private Long domainId;
protected Long domainId;
//Network information
//@ACL(accessType = AccessType.UseEntry)
@Parameter(name = ApiConstants.NETWORK_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = NetworkResponse.class, description = "list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter")
private List<Long> networkIds;
protected List<Long> networkIds;
@Parameter(name = ApiConstants.BOOT_TYPE, type = CommandType.STRING, required = false, description = "Guest VM Boot option either custom[UEFI] or default boot [BIOS]. Not applicable with VMware if the template is marked as deploy-as-is, as we honour what is defined in the template.", since = "4.14.0.0")
private String bootType;
protected String bootType;
@Parameter(name = ApiConstants.BOOT_MODE, type = CommandType.STRING, required = false, description = "Boot Mode [Legacy] or [Secure] Applicable when Boot Type Selected is UEFI, otherwise Legacy only for BIOS. Not applicable with VMware if the template is marked as deploy-as-is, as we honour what is defined in the template.", since = "4.14.0.0")
private String bootMode;
protected String bootMode;
@Parameter(name = ApiConstants.BOOT_INTO_SETUP, type = CommandType.BOOLEAN, required = false, description = "Boot into hardware setup or not (ignored if startVm = false, only valid for vmware)", since = "4.15.0.0")
private Boolean bootIntoSetup;
@ -138,7 +138,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
@Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, description = "the hypervisor on which to deploy the virtual machine. "
+ "The parameter is required and respected only when hypervisor info is not set on the ISO/Template passed to the call")
private String hypervisor;
protected String hypervisor;
@Parameter(name = ApiConstants.USER_DATA, type = CommandType.STRING,
description = "an optional binary data that can be sent to the virtual machine upon a successful deployment. " +
@ -147,10 +147,10 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
"Using HTTP POST (via POST body), you can send up to 1MB of data after base64 encoding. " +
"You also need to change vm.userdata.max.length value",
length = 1048576)
private String userData;
protected String userData;
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the Userdata", since = "4.18")
private Long userdataId;
protected Long userdataId;
@Parameter(name = ApiConstants.USER_DATA_DETAILS, type = CommandType.MAP, description = "used to specify the parameters values for the variables in userdata.", since = "4.18")
private Map userdataDetails;
@ -160,7 +160,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
private String sshKeyPairName;
@Parameter(name = ApiConstants.SSH_KEYPAIRS, type = CommandType.LIST, collectionType = CommandType.STRING, since="4.17", description = "names of the ssh key pairs used to login to the virtual machine")
private List<String> sshKeyPairNames;
protected List<String> sshKeyPairNames;
@Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "destination Host ID to deploy the VM to - parameter available for root admin only")
private Long hostId;
@ -168,7 +168,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
@ACL
@Parameter(name = ApiConstants.SECURITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = SecurityGroupResponse.class, description = "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")
private List<Long> securityGroupIdList;
protected List<Long> securityGroupIdList;
@ACL
@Parameter(name = ApiConstants.SECURITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = SecurityGroupResponse.class, description = "comma separated list of security groups names that going to be applied to the virtual machine."
@ -189,10 +189,10 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
private String macAddress;
@Parameter(name = ApiConstants.KEYBOARD, type = CommandType.STRING, description = "an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,es-latam,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us")
private String keyboard;
protected String keyboard;
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Deploy vm for the project")
private Long projectId;
protected Long projectId;
@Parameter(name = ApiConstants.START_VM, type = CommandType.BOOLEAN, description = "true if start vm after creating; defaulted to true if not specified")
private Boolean startVm;
@ -200,7 +200,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
@ACL
@Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are going to be applied to the virtual machine."
+ " Mutually exclusive with affinitygroupnames parameter")
private List<Long> affinityGroupIdList;
protected List<Long> affinityGroupIdList;
@ACL
@Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are going to be applied to the virtual machine."
@ -208,10 +208,10 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
private List<String> affinityGroupNameList;
@Parameter(name = ApiConstants.DISPLAY_VM, type = CommandType.BOOLEAN, since = "4.2", description = "an optional field, whether to the display the vm to the end user or not.", authorized = {RoleType.Admin})
private Boolean displayVm;
protected Boolean displayVm;
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, since = "4.3", description = "used to specify the custom parameters. 'extraconfig' is not allowed to be passed in details")
private Map details;
protected Map details;
@Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "Deployment planner to use for vm allocation. Available to ROOT admin only", since = "4.4", authorized = { RoleType.Admin })
private String deploymentPlanner;
@ -225,7 +225,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
private Map dataDiskTemplateToDiskOfferingList;
@Parameter(name = ApiConstants.EXTRA_CONFIG, type = CommandType.STRING, since = "4.12", description = "an optional URL encoded string that can be passed to the virtual machine upon successful deployment", length = 5120)
private String extraConfig;
protected String extraConfig;
@Parameter(name = ApiConstants.COPY_IMAGE_TAGS, type = CommandType.BOOLEAN, since = "4.13", description = "if true the image tags (if any) will be copied to the VM, default value is false")
private Boolean copyImageTags;
@ -798,6 +798,11 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
}
return null;
}
public String getInstanceType() {
return null;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -22,23 +22,26 @@ import com.cloud.exception.InvalidParameterValueException;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ResourceScheduleResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VMScheduleResponse;
import org.apache.cloudstack.vm.schedule.VMScheduleManager;
import org.apache.cloudstack.schedule.ResourceScheduleManager;
import javax.inject.Inject;
import java.util.Date;
@Deprecated
@APICommand(name = "createVMSchedule", description = "Create Instance Schedule", responseObject = VMScheduleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class CreateVMScheduleCmd extends BaseCmd {
@Inject
VMScheduleManager vmScheduleManager;
ResourceScheduleManager resourceScheduleManager;
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
@ -75,14 +78,14 @@ public class CreateVMScheduleCmd extends BaseCmd {
type = CommandType.DATE,
required = false,
description = "Start date from which the schedule becomes active. Defaults to current date plus 1 minute."
+ "Use format \"yyyy-MM-dd hh:mm:ss\")")
+ "(Format \"yyyy-MM-dd hh:mm:ss\")")
private Date startDate;
@Parameter(name = ApiConstants.END_DATE,
type = CommandType.DATE,
required = false,
description = "End date after which the schedule becomes inactive"
+ "Use format \"yyyy-MM-dd hh:mm:ss\")")
+ "(Format \"yyyy-MM-dd hh:mm:ss\")")
private Date endDate;
@Parameter(name = ApiConstants.ENABLED,
@ -91,9 +94,9 @@ public class CreateVMScheduleCmd extends BaseCmd {
description = "Enable Instance schedule. Defaults to true")
private Boolean enabled;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getVmId() {
return vmId;
@ -130,13 +133,19 @@ public class CreateVMScheduleCmd extends BaseCmd {
return enabled;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public void execute() {
VMScheduleResponse response = vmScheduleManager.createSchedule(this);
String resourceIdStr = getVmId() != null ? String.valueOf(getVmId()) : null;
ResourceScheduleResponse scheduleResponse = resourceScheduleManager.createSchedule(
ApiCommandResourceType.VirtualMachine,
resourceIdStr, getDescription(), getSchedule(), getTimeZone(), getAction(),
getStartDate(), getEndDate(), getEnabled(), null);
VMScheduleResponse response = new VMScheduleResponse(scheduleResponse);
response.setResponseName(getCommandName());
setResponseObject(response);
}

View File

@ -22,6 +22,7 @@ import com.cloud.exception.InvalidParameterValueException;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
@ -30,19 +31,19 @@ import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VMScheduleResponse;
import org.apache.cloudstack.vm.schedule.VMSchedule;
import org.apache.cloudstack.vm.schedule.VMScheduleManager;
import org.apache.cloudstack.schedule.ResourceScheduleManager;
import javax.inject.Inject;
import java.util.Collections;
import java.util.List;
@Deprecated
@APICommand(name = "deleteVMSchedule", description = "Delete Instance Schedule.", responseObject = SuccessResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class DeleteVMScheduleCmd extends BaseCmd {
@Inject
VMScheduleManager vmScheduleManager;
ResourceScheduleManager resourceScheduleManager;
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
@ -50,12 +51,14 @@ public class DeleteVMScheduleCmd extends BaseCmd {
required = true,
description = "ID of Instance")
private Long vmId;
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = VMScheduleResponse.class,
required = false,
description = "ID of Instance schedule")
private Long id;
@Parameter(name = ApiConstants.IDS,
type = CommandType.LIST,
collectionType = CommandType.UUID,
@ -64,9 +67,9 @@ public class DeleteVMScheduleCmd extends BaseCmd {
description = "IDs of Instance schedule")
private List<Long> ids;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
@ -83,18 +86,21 @@ public class DeleteVMScheduleCmd extends BaseCmd {
return vmId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public void execute() {
long rowsRemoved = vmScheduleManager.removeSchedule(this);
String resourceIdStr = getVmId() != null ? String.valueOf(getVmId()) : null;
long rowsRemoved = resourceScheduleManager.removeSchedule(
ApiCommandResourceType.VirtualMachine,
resourceIdStr, getId(), getIds());
if (rowsRemoved > 0) {
final SuccessResponse response = new SuccessResponse();
response.setResponseName(getCommandName());
response.setObjectName(VMSchedule.class.getSimpleName().toLowerCase());
response.setObjectName("vmschedule");
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete Instance Schedules");

View File

@ -16,10 +16,11 @@
// under the License.
package org.apache.cloudstack.api.command.user.vm;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
@ -40,6 +41,7 @@ import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.uservm.UserVm;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VirtualMachine;
@APICommand(name = "deployVirtualMachine", description = "Creates and automatically starts an Instance based on a service offering, disk offering, and Template.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
@ -88,6 +90,111 @@ public class DeployVMCmd extends BaseDeployVMCmd {
return volumeId != null || snapshotId != null;
}
public boolean isBlankInstance() {
return false;
}
/////////////////////////////////////////////////////
////////////////// Setters //////////////////////////
/////////////////////////////////////////////////////
public void setZoneId(Long zoneId) {
this.zoneId = zoneId;
}
public void setName(String name) {
this.name = name;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public void setNetworkIds(List<Long> networkIds) {
this.networkIds = networkIds;
}
public void setBootType(String bootType) {
this.bootType = bootType;
}
public void setBootMode(String bootMode) {
this.bootMode = bootMode;
}
public void setHypervisor(String hypervisor) {
this.hypervisor = hypervisor;
}
public void setUserData(String userData) {
this.userData = userData;
}
public void setKeyboard(String keyboard) {
this.keyboard = keyboard;
}
public void setProjectId(Long projectId) {
this.projectId = projectId;
}
public void setDisplayVm(Boolean displayVm) {
this.displayVm = displayVm;
}
public void setUserDataId(Long userDataId) {
this.userdataId = userDataId;
}
public void setAffinityGroupIds(List<Long> ids) {
this.affinityGroupIdList = ids;
}
public void setDetails(Map details) {
this.details = details;
}
public void setExtraConfig(String extraConfig) {
this.extraConfig = extraConfig;
}
public void setDynamicScalingEnabled(Boolean dynamicScalingEnabled) {
this.dynamicScalingEnabled = dynamicScalingEnabled;
}
public void setServiceOfferingId(Long serviceOfferingId) {
this.serviceOfferingId = serviceOfferingId;
}
public void setTemplateId(Long templateId) {
this.templateId = templateId;
}
public void setVolumeId(Long volumeId) {
this.volumeId = volumeId;
}
public void setSnapshotId(Long snapshotId) {
this.snapshotId = snapshotId;
}
public void setSshKeyPairNames(List<String> sshKeyPairNames) {
this.sshKeyPairNames = sshKeyPairNames;
}
public void setSecurityGroupList(List<Long> securityGroupIdList) {
this.securityGroupIdList = securityGroupIdList;
}
@Override
public void execute() {
UserVm result;
@ -132,7 +239,7 @@ public class DeployVMCmd extends BaseDeployVMCmd {
@Override
public void create() throws ResourceAllocationException {
if (Stream.of(templateId, snapshotId, volumeId).filter(Objects::nonNull).count() != 1) {
if (!isBlankInstance() && Stream.of(templateId, snapshotId, volumeId).filter(Objects::nonNull).count() != 1) {
throw new CloudRuntimeException("Please provide only one of the following parameters - template ID, volume ID or snapshot ID");
}

View File

@ -90,6 +90,10 @@ public class DestroyVMCmd extends BaseAsyncCmd implements UserCmd {
return volumeIds;
}
public boolean isForced() {
return false;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -20,23 +20,27 @@ package org.apache.cloudstack.api.command.user.vm;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ResourceScheduleResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VMScheduleResponse;
import org.apache.cloudstack.vm.schedule.VMSchedule;
import org.apache.cloudstack.vm.schedule.VMScheduleManager;
import org.apache.cloudstack.schedule.ResourceScheduleManager;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
@Deprecated
@APICommand(name = "listVMSchedule", description = "List Instance Schedules.", responseObject = VMScheduleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class ListVMScheduleCmd extends BaseListCmd {
@Inject
VMScheduleManager vmScheduleManager;
ResourceScheduleManager resourceScheduleManager;
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
@ -61,12 +65,12 @@ public class ListVMScheduleCmd extends BaseListCmd {
@Parameter(name = ApiConstants.ENABLED,
type = CommandType.BOOLEAN,
required = false,
description = "ID of Instance schedule")
description = "Filter by enabled status")
private Boolean enabled;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getVmId() {
return vmId;
@ -84,14 +88,26 @@ public class ListVMScheduleCmd extends BaseListCmd {
return enabled;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public void execute() {
ListResponse<VMScheduleResponse> response = vmScheduleManager.listSchedule(this);
String resourceIdStr = getVmId() != null ? String.valueOf(getVmId()) : null;
ListResponse<ResourceScheduleResponse> scheduleResponse = resourceScheduleManager.listSchedule(
getId(), null, ApiCommandResourceType.VirtualMachine, resourceIdStr, getAction(), getEnabled(),
getStartIndex(), getPageSizeVal()
);
List<VMScheduleResponse> vmScheduleResponses = new ArrayList<>();
for (ResourceScheduleResponse resourceScheduleResponse : scheduleResponse.getResponses()) {
vmScheduleResponses.add(new VMScheduleResponse(resourceScheduleResponse));
}
ListResponse<VMScheduleResponse> response = new ListResponse<>();
response.setResponses(vmScheduleResponses, scheduleResponse.getCount());
response.setResponseName(getCommandName());
response.setObjectName(VMSchedule.class.getSimpleName().toLowerCase());
response.setObjectName("vmschedule");
setResponseObject(response);
}
}

View File

@ -288,6 +288,14 @@ public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction,
return Boolean.TRUE.equals(cleanupExtraConfig);
}
public void setId(Long id) {
this.id = id;
}
public void setSecurityGroupIdList(List<Long> securityGroupIdList) {
this.securityGroupIdList = securityGroupIdList;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -22,22 +22,25 @@ import com.cloud.exception.InvalidParameterValueException;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ResourceScheduleResponse;
import org.apache.cloudstack.api.response.VMScheduleResponse;
import org.apache.cloudstack.vm.schedule.VMSchedule;
import org.apache.cloudstack.vm.schedule.VMScheduleManager;
import org.apache.cloudstack.schedule.ResourceSchedule;
import org.apache.cloudstack.schedule.ResourceScheduleManager;
import javax.inject.Inject;
import java.util.Date;
@Deprecated
@APICommand(name = "updateVMSchedule", description = "Update Instance Schedule.", responseObject = VMScheduleResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class UpdateVMScheduleCmd extends BaseCmd {
@Inject
VMScheduleManager vmScheduleManager;
ResourceScheduleManager resourceScheduleManager;
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
@ -68,14 +71,14 @@ public class UpdateVMScheduleCmd extends BaseCmd {
type = CommandType.DATE,
required = false,
description = "Start date from which the schedule becomes active"
+ "Use format \"yyyy-MM-dd hh:mm:ss\")")
+ "(Format \"yyyy-MM-dd hh:mm:ss\")")
private Date startDate;
@Parameter(name = ApiConstants.END_DATE,
type = CommandType.DATE,
required = false,
description = "End date after which the schedule becomes inactive"
+ "Use format \"yyyy-MM-dd hh:mm:ss\")")
+ "(Format \"yyyy-MM-dd hh:mm:ss\")")
private Date endDate;
@Parameter(name = ApiConstants.ENABLED,
@ -84,9 +87,9 @@ public class UpdateVMScheduleCmd extends BaseCmd {
description = "Enable Instance schedule")
private Boolean enabled;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
@ -116,24 +119,29 @@ public class UpdateVMScheduleCmd extends BaseCmd {
return enabled;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public void execute() {
VMScheduleResponse response = vmScheduleManager.updateSchedule(this);
ResourceScheduleResponse scheduleResponse = resourceScheduleManager.updateSchedule(
getId(), getDescription(), getSchedule(), getTimeZone(), getStartDate(), getEndDate(), getEnabled(), null);
VMScheduleResponse response = new VMScheduleResponse(scheduleResponse);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
VMSchedule vmSchedule = _entityMgr.findById(VMSchedule.class, getId());
if (vmSchedule == null) {
throw new InvalidParameterValueException(String.format("Unable to find vmSchedule by id=%d", getId()));
ResourceSchedule schedule = _entityMgr.findById(ResourceSchedule.class, getId());
if (schedule == null || !ApiCommandResourceType.VirtualMachine.equals(schedule.getResourceType())) {
throw new InvalidParameterValueException(String.format("Unable to find VM schedule by id=%d", getId()));
}
VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, schedule.getResourceId());
if (vm == null) {
throw new InvalidParameterValueException(String.format("Unable to find VM schedule by id=%d", getId()));
}
VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, vmSchedule.getVmId());
return vm.getAccountId();
}
}

View File

@ -70,6 +70,21 @@ public class AssignVolumeCmd extends BaseCmd implements UserCmd {
return projectid;
}
/////////////////////////////////////////////////////
/////////////////// Setter///////////////////////////
/////////////////////////////////////////////////////
public void setVolumeId(Long volumeId) {
this.volumeId = volumeId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public void setProjectId(Long projectid) {
this.projectid = projectid;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -114,7 +114,8 @@ public class CreateVolumeCmd extends BaseAsyncCreateCustomIdCmd implements UserC
type = CommandType.UUID,
entityType = StoragePoolResponse.class,
description = "Storage pool ID to create the volume in. Cannot be used with the snapshotid parameter.",
authorized = {RoleType.Admin})
authorized = {RoleType.Admin},
since = "4.22.1")
private Long storageId;
/////////////////////////////////////////////////////
@ -150,6 +151,10 @@ public class CreateVolumeCmd extends BaseAsyncCreateCustomIdCmd implements UserC
}
public Long getSnapshotId() {
if (storageId != null && snapshotId != null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
"Snapshot ID cannot be specified with the Storage ID.");
}
return snapshotId;
}
@ -163,7 +168,8 @@ public class CreateVolumeCmd extends BaseAsyncCreateCustomIdCmd implements UserC
public Long getStorageId() {
if (snapshotId != null && storageId != null) {
throw new IllegalArgumentException("StorageId parameter cannot be specified with the SnapshotId parameter.");
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
"Storage ID cannot be specified with the Snapshot ID.");
}
return storageId;
}

View File

@ -77,6 +77,10 @@ public class DetachVolumeCmd extends BaseAsyncCmd implements UserCmd {
return virtualMachineId;
}
public void setId(Long id) {
this.id = id;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -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.api.response;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
public class AttachedIsoResponse extends BaseResponse {
@SerializedName("id")
@Param(description = "The ID of the attached ISO")
private String id;
@SerializedName("name")
@Param(description = "The name of the attached ISO")
private String name;
@SerializedName("displaytext")
@Param(description = "The display text of the attached ISO")
private String displayText;
@SerializedName("deviceseq")
@Param(description = "The cdrom slot that holds this ISO (3=hdc, 4=hdd, ...)")
private Integer deviceSeq;
@SerializedName("bootable")
@Param(description = "Whether this is the bootable ISO for the VM")
private Boolean bootable;
public AttachedIsoResponse() {
}
public AttachedIsoResponse(String id, String name, String displayText, Integer deviceSeq, boolean bootable) {
this.id = id;
this.name = name;
this.displayText = displayText;
this.deviceSeq = deviceSeq;
this.bootable = bootable;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getDisplayText() {
return displayText;
}
public Integer getDeviceSeq() {
return deviceSeq;
}
public Boolean getBootable() {
return bootable;
}
}

View File

@ -127,6 +127,18 @@ public class BackupResponse extends BaseResponse {
@Param(description = "Indicates whether the VM from which the backup was taken is expunged or not", since = "4.22.0")
private Boolean isVmExpunged;
@SerializedName(ApiConstants.FROM_CHECKPOINT_ID)
@Param(description = "Previous active checkpoint ID for incremental backups", since = "4.23.0")
private String fromCheckpointId;
@SerializedName(ApiConstants.TO_CHECKPOINT_ID)
@Param(description = "Next checkpoint ID for incremental backups", since = "4.23.0")
private String toCheckpointId;
@SerializedName(ApiConstants.HOST_ID)
@Param(description = "Host ID where the backup is running", since = "4.23.0")
private String hostId;
public String getId() {
return id;
}
@ -314,4 +326,28 @@ public class BackupResponse extends BaseResponse {
public void setVmExpunged(Boolean isVmExpunged) {
this.isVmExpunged = isVmExpunged;
}
public void setFromCheckpointId(String fromCheckpointId) {
this.fromCheckpointId = fromCheckpointId;
}
public String getFromCheckpointId() {
return this.fromCheckpointId;
}
public void setToCheckpointId(String toCheckpointId) {
this.toCheckpointId = toCheckpointId;
}
public String getToCheckpointId() {
return this.toCheckpointId;
}
public void setHostId(String hostId) {
this.hostId = hostId;
}
public String getHostId() {
return this.hostId;
}
}

View File

@ -0,0 +1,53 @@
//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
//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.response;
import java.util.Date;
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 CheckpointResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the checkpoint ID")
private String id;
@SerializedName(ApiConstants.CREATED)
@Param(description = "the checkpoint creation time")
private Date created;
@SerializedName(ApiConstants.IS_ACTIVE)
@Param(description = "whether this is the active checkpoint")
private Boolean isActive;
public void setId(String id) {
this.id = id;
}
public void setCreated(Date created) {
this.created = created;
}
public void setIsActive(Boolean isActive) {
this.isActive = isActive;
}
}

View File

@ -63,6 +63,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
@Param(description = "The OS category name of the host")
private String osCategoryName;
@SerializedName(ApiConstants.GUEST_OS_RULE)
@Param(description = "the guest OS rule")
private String guestOsRule;
@SerializedName(ApiConstants.IP_ADDRESS)
@Param(description = "The IP address of the host")
private String ipAddress;
@ -999,4 +1003,12 @@ public class HostResponse extends BaseResponseWithAnnotations {
public String getExtensionName() {
return extensionName;
}
public String getGuestOsRule() {
return guestOsRule;
}
public void setGuestOsRule(String guestOsRule) {
this.guestOsRule = guestOsRule;
}
}

View File

@ -0,0 +1,104 @@
//Licensed to the Apache Software Foundation (ASF) under one
//or more contributor license agreements. See the NOTICE file
//distributed with this work for additional information
//regarding copyright ownership. The ASF licenses this file
//to you under the Apache License, Version 2.0 (the
//"License"); you may not use this file except in compliance
//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.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.backup.ImageTransfer;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = ImageTransfer.class)
public class ImageTransferResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the ID of the image transfer")
private String id;
@SerializedName("backupid")
@Param(description = "the backup ID")
private String backupId;
@SerializedName("vmid")
@Param(description = "the VM ID")
private String vmId;
@SerializedName(ApiConstants.VOLUME_ID)
@Param(description = "the disk/volume ID")
private String diskId;
@SerializedName("devicename")
@Param(description = "the device name (vda, vdb, etc)")
private String deviceName;
@SerializedName("transferurl")
@Param(description = "the transfer URL")
private String transferUrl;
@SerializedName("phase")
@Param(description = "the transfer phase")
private String phase;
@SerializedName("direction")
@Param(description = "the image transfer direction: upload / download")
private String direction;
@SerializedName(ApiConstants.CREATED)
@Param(description = "the date created")
private Date created;
public void setId(String id) {
this.id = id;
}
public void setBackupId(String backupId) {
this.backupId = backupId;
}
public void setVmId(String vmId) {
this.vmId = vmId;
}
public void setDiskId(String diskId) {
this.diskId = diskId;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public void setTransferUrl(String transferUrl) {
this.transferUrl = transferUrl;
}
public void setPhase(String phase) {
this.phase = phase;
}
public void setDirection(String direction) {
this.direction = direction;
}
public void setCreated(Date created) {
this.created = created;
}
}

View File

@ -53,6 +53,10 @@ public class NicSecondaryIpResponse extends BaseResponse {
@Param(description = "The ID of the Instance")
private String vmId;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "Description of the secondary IP address")
private String description;
@Override
public String getObjectId() {
return this.getId();
@ -98,6 +102,14 @@ public class NicSecondaryIpResponse extends BaseResponse {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<NicSecondaryIpResponse> getSecondaryIpsList() {
return secondaryIpsList;
}

View File

@ -0,0 +1,178 @@
/*
* 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.response;
import java.util.Date;
import java.util.Map;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.schedule.ResourceSchedule;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = ResourceSchedule.class)
public class ResourceScheduleResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "The ID of resource schedule")
private String id;
@SerializedName(ApiConstants.RESOURCE_TYPE)
@Param(description = "Type of the resource")
private ApiCommandResourceType resourceType;
@SerializedName(ApiConstants.RESOURCE_ID)
@Param(description = "ID of the resource")
private String resourceId;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "Description of resource schedule")
private String description;
@SerializedName(ApiConstants.SCHEDULE)
@Param(description = "Cron formatted resource schedule")
private String schedule;
@SerializedName(ApiConstants.TIMEZONE)
@Param(description = "Timezone of the schedule")
private String timeZone;
@SerializedName(ApiConstants.ACTION)
@Param(description = "Action")
private ResourceSchedule.Action action;
@SerializedName(ApiConstants.ENABLED)
@Param(description = "Resource schedule is enabled")
private boolean enabled;
@SerializedName(ApiConstants.START_DATE)
@Param(description = "Date from which the schedule is active")
private Date startDate;
@SerializedName(ApiConstants.END_DATE)
@Param(description = "Date after which the schedule becomes inactive")
private Date endDate;
@SerializedName(ApiConstants.DETAILS)
@Param(description = "Schedule details")
private Map<String, String> details;
@SerializedName(ApiConstants.CREATED)
@Param(description = "Date when the schedule was created")
private Date created;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setResourceType(ApiCommandResourceType resourceType) {
this.resourceType = resourceType;
}
public ApiCommandResourceType getResourceType() {
return resourceType;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
public String getResourceId() {
return resourceId;
}
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public void setSchedule(String schedule) {
this.schedule = schedule;
}
public String getSchedule() {
return schedule;
}
public void setTimeZone(String timeZone) {
this.timeZone = timeZone;
}
public String getTimeZone() {
return timeZone;
}
public void setAction(ResourceSchedule.Action action) {
this.action = action;
}
public ResourceSchedule.Action getAction() {
return action;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean getEnabled() {
return enabled;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getStartDate() {
return startDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public Date getEndDate() {
return endDate;
}
public void setDetails(Map<String, String> details) {
this.details = details;
}
public Map<String, String> getDetails() {
return details;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getCreated() {
return created;
}
}

View File

@ -166,6 +166,14 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
@Param(description = "An alternate display text of the ISO attached to the Instance")
private String isoDisplayText;
@SerializedName("isos")
@Param(description = "All ISOs attached to the Instance, keyed by cdrom slot. The first entry mirrors isoid/isoname for back-compat.", responseObject = AttachedIsoResponse.class, since = "4.23.0")
private List<AttachedIsoResponse> isos;
@SerializedName("isomaxcount")
@Param(description = "Maximum number of ISOs that may be attached to this Instance, after applying the cluster-scoped vm.iso.max.count and the hypervisor's own cap.", since = "4.23.0")
private Integer isoMaxCount;
@SerializedName(ApiConstants.SERVICE_OFFERING_ID)
@Param(description = "The ID of the service offering of the Instance")
private String serviceOfferingId;
@ -871,6 +879,22 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
this.isoId = isoId;
}
public void setIsos(List<AttachedIsoResponse> isos) {
this.isos = isos;
}
public List<AttachedIsoResponse> getIsos() {
return isos;
}
public void setIsoMaxCount(Integer isoMaxCount) {
this.isoMaxCount = isoMaxCount;
}
public Integer getIsoMaxCount() {
return isoMaxCount;
}
public void setIsoName(String isoName) {
this.isoName = isoName;
}

View File

@ -23,11 +23,11 @@ import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.vm.schedule.VMSchedule;
import org.apache.cloudstack.schedule.ResourceSchedule;
import java.util.Date;
@EntityReference(value = VMSchedule.class)
@EntityReference(value = ResourceSchedule.class)
public class VMScheduleResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "The ID of Instance schedule")
@ -51,7 +51,7 @@ public class VMScheduleResponse extends BaseResponse {
@SerializedName(ApiConstants.ACTION)
@Param(description = "Action")
private VMSchedule.Action action;
private ResourceSchedule.Action action;
@SerializedName(ApiConstants.ENABLED)
@Param(description = "VM schedule is enabled")
@ -69,6 +69,20 @@ public class VMScheduleResponse extends BaseResponse {
@Param(description = "Date when the schedule was created")
private Date created;
public VMScheduleResponse(ResourceScheduleResponse scheduleResponse) {
super("vmschedule");
this.id = scheduleResponse.getId();
this.vmId = scheduleResponse.getResourceId();
this.description = scheduleResponse.getDescription();
this.schedule = scheduleResponse.getSchedule();
this.timeZone = scheduleResponse.getTimeZone();
this.action = scheduleResponse.getAction();
this.enabled = scheduleResponse.getEnabled();
this.startDate = scheduleResponse.getStartDate();
this.endDate = scheduleResponse.getEndDate();
this.created = scheduleResponse.getCreated();
}
public void setId(String id) {
this.id = id;
}
@ -89,7 +103,7 @@ public class VMScheduleResponse extends BaseResponse {
this.timeZone = timeZone;
}
public void setAction(VMSchedule.Action action) {
public void setAction(ResourceSchedule.Action action) {
this.action = action;
}
@ -105,5 +119,7 @@ public class VMScheduleResponse extends BaseResponse {
this.endDate = endDate;
}
public void setCreated(Date created) {this.created = created;}
public void setCreated(Date created) {
this.created = created;
}
}

View File

@ -30,8 +30,16 @@ import com.cloud.storage.Volume;
public interface Backup extends ControlledEntity, InternalIdentity, Identity {
String getFromCheckpointId();
String getToCheckpointId();
Long getCheckpointCreateTime();
Long getHostId();
enum Status {
Allocated, Queued, BackingUp, BackedUp, Error, Failed, Restoring, Removed, Expunged
Allocated, Queued, BackingUp, ReadyForImageTransfer, FinalizingImageTransfer, BackedUp, Error, Failed, Restoring, Removed, Expunged
}
class Metric {

View File

@ -0,0 +1,61 @@
// 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 org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.InternalIdentity;
public interface ImageTransfer extends ControlledEntity, InternalIdentity {
long getDataCenterId();
public enum Direction {
upload, download
}
public enum Format {
raw,
cow
}
public enum Backend {
nbd,
file
}
public enum Phase {
initializing, transferring, finished, failed
}
String getUuid();
Long getBackupId();
long getVolumeId();
long getHostId();
String getTransferUrl();
Phase getPhase();
Direction getDirection();
Backend getBackend();
String getSignedTicketId();
}

View File

@ -0,0 +1,106 @@
//Licensed to the Apache Software Foundation (ASF) under one
//or more contributor license agreements. See the NOTICE file
//distributed with this work for additional information
//regarding copyright ownership. The ASF licenses this file
//to you under the Apache License, Version 2.0 (the
//"License"); you may not use this file except in compliance
//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 java.util.List;
import org.apache.cloudstack.api.command.admin.backup.CreateImageTransferCmd;
import org.apache.cloudstack.api.command.admin.backup.DeleteVmCheckpointCmd;
import org.apache.cloudstack.api.command.admin.backup.FinalizeBackupCmd;
import org.apache.cloudstack.api.command.admin.backup.FinalizeImageTransferCmd;
import org.apache.cloudstack.api.command.admin.backup.ListImageTransfersCmd;
import org.apache.cloudstack.api.command.admin.backup.ListVmCheckpointsCmd;
import org.apache.cloudstack.api.command.admin.backup.StartBackupCmd;
import org.apache.cloudstack.api.response.CheckpointResponse;
import org.apache.cloudstack.api.response.ImageTransferResponse;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import com.cloud.utils.component.PluggableService;
/**
* Service for Creating Backups and ImageTransfer sessions which will be consumed by an external orchestrator.
*/
public interface KVMBackupExportService extends Configurable, PluggableService {
ConfigKey<Integer> ImageTransferIdleTimeoutSeconds = new ConfigKey<>("Advanced", Integer.class,
"image.transfer.idle.timeout.seconds",
"600",
"Seconds since last completed HTTP request to an image transfer before the image server unregisters it (idle timeout).",
true, ConfigKey.Scope.Zone);
ConfigKey<Boolean> ExposeKVMBackupExportServiceApis = new ConfigKey<>("Advanced", Boolean.class,
"expose.kvm.backup.export.service.apis",
"false",
"Enable to expose APIs for testing the KVM Backup Export Service.",
false, ConfigKey.Scope.Global);
/**
* Creates a backup session for a VM
*/
Backup createBackup(StartBackupCmd cmd);
/**
* Start a backup session for a VM
* Creates a new checkpoint and starts NBD server for pull-mode backup
*/
Backup startBackup(StartBackupCmd cmd);
/**
* Finalize a backup session
* Stops NBD server, updates checkpoint tracking, deletes old checkpoints
*/
Backup finalizeBackup(FinalizeBackupCmd cmd);
/**
* Create an image transfer object for a disk
* Registers NBD endpoint with ImageIO (stubbed for POC)
*/
ImageTransferResponse createImageTransfer(CreateImageTransferCmd cmd);
ImageTransfer createImageTransfer(long volumeId, Long backupId, ImageTransfer.Direction direction, ImageTransfer.Format format);
boolean cancelImageTransfer(long imageTransferId);
/**
* Finalize an image transfer
* Marks transfer as complete (NBD is closed globally in finalize backup)
*/
boolean finalizeImageTransfer(FinalizeImageTransferCmd cmd);
boolean finalizeImageTransfer(long imageTransferId);
/**
* List image transfers for a backup
*/
List<ImageTransferResponse> listImageTransfers(ListImageTransfersCmd cmd);
/**
* List checkpoints for a VM
*/
List<CheckpointResponse> listVmCheckpoints(ListVmCheckpointsCmd cmd);
/**
* Delete a VM checkpoint (no-op for normal flow, kept for API parity)
*/
boolean deleteVmCheckpoint(DeleteVmCheckpointCmd cmd);
/**
* List Compatible Data Center Ids for the service
*/
List<Long> listCompatibleDataCenterIds();
}

View File

@ -23,6 +23,8 @@ import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;
import com.trilead.ssh2.Connection;
import org.apache.cloudstack.framework.ca.CAProvider;
import org.apache.cloudstack.framework.ca.CAService;
import org.apache.cloudstack.framework.ca.Certificate;
@ -39,7 +41,10 @@ public interface CAManager extends CAService, Configurable, PluggableService {
ConfigKey<String> CAProviderPlugin = new ConfigKey<>("Advanced", String.class,
"ca.framework.provider.plugin",
"root",
"The CA provider plugin that is used for secure CloudStack management server-agent communication for encryption and authentication. Restart management server(s) when changed.", true);
"The CA provider plugin used for CloudStack internal certificate management (MS-agent encryption and authentication). " +
"The default 'root' provider auto-generates a CA on first startup, but also supports user-provided custom CA material " +
"via the ca.plugin.root.private.key, ca.plugin.root.public.key, and ca.plugin.root.ca.certificate settings. " +
"Restart management server(s) when changed.", false);
ConfigKey<Integer> CertKeySize = new ConfigKey<>("Advanced", Integer.class,
"ca.framework.cert.keysize",
@ -85,6 +90,12 @@ public interface CAManager extends CAService, Configurable, PluggableService {
"The actual implementation will depend on the configured CA provider.",
false);
ConfigKey<Boolean> CaInjectDefaultTruststore = new ConfigKey<>("Advanced", Boolean.class,
"ca.framework.inject.default.truststore", "true",
"When true, injects the CA provider's certificate into the JVM default truststore on management server startup. " +
"This allows outgoing HTTPS connections from the management server to trust servers with certificates signed by the configured CA. " +
"Restart management server(s) when changed.", false);
/**
* Returns a list of available CA provider plugins
* @return returns list of CAProvider
@ -130,12 +141,26 @@ public interface CAManager extends CAService, Configurable, PluggableService {
boolean revokeCertificate(final BigInteger certSerial, final String certCn, final String provider);
/**
* Provisions certificate for given active and connected agent host
* Provisions certificate for given agent host.
* When forced=true, uses SSH to re-provision bypassing the NIO agent connection (for disconnected agents).
* @param host
* @param reconnect
* @param provider
* @param forced when true, provisions via SSH instead of NIO; supports KVM hosts and SystemVMs
* @return returns success/failure as boolean
*/
boolean provisionCertificate(final Host host, final Boolean reconnect, final String provider);
boolean provisionCertificate(final Host host, final Boolean reconnect, final String provider, final boolean forced);
/**
* Provisions certificate for a KVM host using an existing SSH connection.
* Runs keystore-setup to generate a CSR, issues a certificate, then runs keystore-cert-import.
* Used during host discovery and for forced re-provisioning when the NIO agent is unreachable.
* @param sshConnection active SSH connection to the KVM host
* @param agentIp IP address of the KVM host agent
* @param agentHostname hostname of the KVM host agent
* @param caProvider optional CA provider plugin name (null uses default)
*/
void provisionCertificateViaSsh(Connection sshConnection, String agentIp, String agentHostname, String caProvider);
/**
* Setups up a new keystore and generates CSR for a host

View File

@ -16,20 +16,31 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.vm.schedule;
package org.apache.cloudstack.schedule;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
import java.time.ZoneId;
import java.util.Date;
public interface VMSchedule extends Identity, InternalIdentity {
enum Action {
START, STOP, REBOOT, FORCE_STOP, FORCE_REBOOT
public interface ResourceSchedule extends Identity, InternalIdentity {
/**
* Common contract for scheduler actions. Each provider defines its own enum
* implementing this interface so the generic machinery can call {@link #name()}
* and {@link #getEventType()} without knowing the concrete type.
*/
interface Action {
String name();
String getEventType();
}
long getVmId();
ApiCommandResourceType getResourceType();
long getResourceId();
String getDescription();
@ -37,7 +48,7 @@ public interface VMSchedule extends Identity, InternalIdentity {
String getTimeZone();
Action getAction();
String getActionName();
boolean getEnabled();

View File

@ -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 org.apache.cloudstack.schedule;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ResourceScheduleResponse;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface ResourceScheduleManager {
ResourceScheduleResponse createSchedule(ApiCommandResourceType resourceType, String resourceUuid,
String description, String schedule, String timeZone, String action,
Date startDate, Date endDate, boolean enabled, Map<String, String> details);
ResourceScheduleResponse updateSchedule(Long id, String description, String schedule, String timeZone,
Date startDate, Date endDate, Boolean enabled, Map<String, String> details);
ListResponse<ResourceScheduleResponse> listSchedule(Long id, List<Long> ids, ApiCommandResourceType resourceType,
String resourceUuid, String action, Boolean enabled,
Long startIndex, Long pageSize);
Long removeSchedule(ApiCommandResourceType resourceType, String resourceUuid, Long id, List<Long> ids);
void removeSchedulesForResource(ApiCommandResourceType resourceType, long resourceId);
}

View File

@ -16,23 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.vm.schedule;
package org.apache.cloudstack.schedule;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
import java.util.Date;
public interface VMScheduledJob extends Identity, InternalIdentity {
long getVmId();
public interface ResourceScheduledJob extends Identity, InternalIdentity {
ApiCommandResourceType getResourceType();
long getVmScheduleId();
long getResourceId();
long getScheduleId();
Long getAsyncJobId();
void setAsyncJobId(long asyncJobId);
VMSchedule.Action getAction();
String getActionName();
Date getScheduledTime();
}

View File

@ -16,21 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.vm.schedule.dao;
package org.apache.cloudstack.schedule.autoscale;
import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.vm.schedule.VMScheduledJobVO;
import com.cloud.event.EventTypes;
import org.apache.cloudstack.schedule.ResourceSchedule;
import java.util.Date;
import java.util.List;
public interface VMScheduledJobDao extends GenericDao<VMScheduledJobVO, Long> {
List<VMScheduledJobVO> listJobsToStart(Date currentTimestamp);
int expungeJobsForSchedules(List<Long> scheduleId, Date dateAfter);
int expungeJobsBefore(Date currentTimestamp);
VMScheduledJobVO findByScheduleAndTimestamp(long scheduleId, Date scheduledTimestamp);
public enum AutoScaleScheduleAction implements ResourceSchedule.Action {
UPDATE {
@Override
public String getEventType() {
return EventTypes.EVENT_AUTOSCALEVMGROUP_SCHEDULE_UPDATE;
}
}
}

View File

@ -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 org.apache.cloudstack.schedule.vm;
import com.cloud.event.EventTypes;
import org.apache.cloudstack.schedule.ResourceSchedule;
public enum VMScheduleAction implements ResourceSchedule.Action {
START {
@Override
public String getEventType() { return EventTypes.EVENT_VM_SCHEDULE_START; }
},
STOP {
@Override
public String getEventType() { return EventTypes.EVENT_VM_SCHEDULE_STOP; }
},
REBOOT {
@Override
public String getEventType() { return EventTypes.EVENT_VM_SCHEDULE_REBOOT; }
},
FORCE_STOP {
@Override
public String getEventType() { return EventTypes.EVENT_VM_SCHEDULE_FORCE_STOP; }
},
FORCE_REBOOT {
@Override
public String getEventType() { return EventTypes.EVENT_VM_SCHEDULE_FORCE_REBOOT; }
};
}

View File

@ -23,6 +23,10 @@ import org.apache.cloudstack.api.command.user.storage.sharedfs.ChangeSharedFSDis
import org.apache.cloudstack.api.command.user.storage.sharedfs.ChangeSharedFSServiceOfferingCmd;
import org.apache.cloudstack.api.command.user.storage.sharedfs.CreateSharedFSCmd;
import org.apache.cloudstack.api.command.user.storage.sharedfs.DestroySharedFSCmd;
import org.apache.cloudstack.api.command.user.storage.sharedfs.ListSharedFSCmd;
import org.apache.cloudstack.api.command.user.storage.sharedfs.UpdateSharedFSCmd;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.SharedFSResponse;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ManagementServerException;
@ -31,11 +35,6 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.VirtualMachineMigrationException;
import org.apache.cloudstack.api.command.user.storage.sharedfs.ListSharedFSCmd;
import org.apache.cloudstack.api.command.user.storage.sharedfs.UpdateSharedFSCmd;
import org.apache.cloudstack.api.response.SharedFSResponse;
import org.apache.cloudstack.api.response.ListResponse;
public interface SharedFSService {
List<SharedFSProvider> getSharedFSProviders();
@ -69,4 +68,10 @@ public interface SharedFSService {
SharedFS recoverSharedFS(Long sharedFSId);
void deleteSharedFS(Long sharedFSId);
SharedFS getSharedFSByUuid(String uuid);
SharedFS getSharedFSForVmId(long vmId);
SharedFS updateSharedFSPostRestore(long sharedFsId, long volumeId);
}

Some files were not shown because too many files have changed in this diff Show More