Merge release branch 4.22 to main

* 4.22:
      VM Deployment using snapshot in new zone (#13178)
      Change exception treatment on incremental snapshot wait (#12665)
      Move checkRoleEscalation outside DB transaction in createAccount (#13044)
      Fix/flasharray delete rename destroy patch conflict (#13049)
      Fix VPC network offerings listing in isolated network creation form (#12645)
      systemvm: accept ipv6 established/related return traffic (#13173)
      update debian change log
      Updating pom.xml version numbers for release 4.22.2.0-SNAPSHOT
      Updating pom.xml version numbers for release 4.22.1.0
      Update suse15 packaging spec, use qemu-ovmf-x86_64 package instead of edk2-ovmf for agent (#13133)
      Change disk-only VM snapshot removal message (#11182)
      Update mysql java connector version to 8.4.0 (matching version for MySQL 8.4) (#12640)
      adaptive: honor user-provided capacityBytes when provider stats are unavailable (#13059)
      Flexibilize public IP selection (#11076)
This commit is contained in:
Fabricio Duarte 2026-05-22 10:30:01 -03:00
commit 67b849f3ef
35 changed files with 1428 additions and 386 deletions

View File

@ -283,7 +283,7 @@ jobs:
# https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2004-Readme.md#mysql # https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2004-Readme.md#mysql
sudo apt-get install -y mysql-server sudo apt-get install -y mysql-server
sudo systemctl start mysql 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 systemctl restart mysql
sudo mysql -uroot -e "SELECT VERSION();" sudo mysql -uroot -e "SELECT VERSION();"

18
debian/changelog vendored
View File

@ -2,14 +2,20 @@ cloudstack (4.23.0.0-SNAPSHOT) unstable; urgency=low
* Update the version to 4.23.0.0-SNAPSHOT * Update the version to 4.23.0.0-SNAPSHOT
-- the Apache CloudStack project <dev@cloudstack.apache.org> Fri, 22 May 2026 10:20:00 -0300
cloudstack (4.22.1.0) unstable; urgency=low
* Update the version to 4.22.1.0
-- the Apache CloudStack project <dev@cloudstack.apache.org> Mon, 11 May 2026 20:26:07 +0530
cloudstack (4.22.0.0) unstable; urgency=low
* Update the version to 4.22.0.0
-- the Apache CloudStack project <dev@cloudstack.apache.org> Thu, 30 Oct 2025 19:23:55 +0530 -- the Apache CloudStack project <dev@cloudstack.apache.org> Thu, 30 Oct 2025 19:23:55 +0530
cloudstack (4.23.0.0-SNAPSHOT-SNAPSHOT) unstable; urgency=low
* Update the version to 4.23.0.0-SNAPSHOT-SNAPSHOT
-- the Apache CloudStack project <dev@cloudstack.apache.org> Thu, Aug 28 11:58:36 2025 +0530
cloudstack (4.21.0.0) unstable; urgency=low cloudstack (4.21.0.0) unstable; urgency=low
* Update the version to 4.21.0.0 * Update the version to 4.21.0.0

View File

@ -19,9 +19,21 @@ package com.cloud.network.dao;
import com.cloud.network.vo.PublicIpQuarantineVO; import com.cloud.network.vo.PublicIpQuarantineVO;
import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDao;
import java.util.Date;
import java.util.List;
public interface PublicIpQuarantineDao extends GenericDao<PublicIpQuarantineVO, Long> { public interface PublicIpQuarantineDao extends GenericDao<PublicIpQuarantineVO, Long> {
PublicIpQuarantineVO findByPublicIpAddressId(long publicIpAddressId); PublicIpQuarantineVO findByPublicIpAddressId(long publicIpAddressId);
PublicIpQuarantineVO findByIpAddress(String publicIpAddress); PublicIpQuarantineVO findByIpAddress(String publicIpAddress);
/**
* Returns a list of public IP addresses that are actively quarantined at the specified date and the previous owner differs from the specified user.
*
* @param userId used to check against the IP's previous owner;
* @param date used to check if the quarantine is active;
* @return a list of PublicIpQuarantineVOs.
*/
List<PublicIpQuarantineVO> listQuarantinedIpAddressesToUser(Long userId, Date date);
} }

View File

@ -26,6 +26,8 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Date;
import java.util.List;
@Component @Component
public class PublicIpQuarantineDaoImpl extends GenericDaoBase<PublicIpQuarantineVO, Long> implements PublicIpQuarantineDao { public class PublicIpQuarantineDaoImpl extends GenericDaoBase<PublicIpQuarantineVO, Long> implements PublicIpQuarantineDao {
@ -33,6 +35,8 @@ public class PublicIpQuarantineDaoImpl extends GenericDaoBase<PublicIpQuarantine
private SearchBuilder<IPAddressVO> ipAddressSearchBuilder; private SearchBuilder<IPAddressVO> ipAddressSearchBuilder;
private SearchBuilder<PublicIpQuarantineVO> quarantinedIpAddressesSearch;
@Inject @Inject
IPAddressDao ipAddressDao; IPAddressDao ipAddressDao;
@ -47,8 +51,16 @@ public class PublicIpQuarantineDaoImpl extends GenericDaoBase<PublicIpQuarantine
publicIpAddressByIdSearch.join("quarantineJoin", ipAddressSearchBuilder, ipAddressSearchBuilder.entity().getId(), publicIpAddressByIdSearch.join("quarantineJoin", ipAddressSearchBuilder, ipAddressSearchBuilder.entity().getId(),
publicIpAddressByIdSearch.entity().getPublicIpAddressId(), JoinBuilder.JoinType.INNER); publicIpAddressByIdSearch.entity().getPublicIpAddressId(), JoinBuilder.JoinType.INNER);
quarantinedIpAddressesSearch = createSearchBuilder();
quarantinedIpAddressesSearch.and("previousOwnerId", quarantinedIpAddressesSearch.entity().getPreviousOwnerId(), SearchCriteria.Op.NEQ);
quarantinedIpAddressesSearch.and();
quarantinedIpAddressesSearch.op("removedIsNull", quarantinedIpAddressesSearch.entity().getRemoved(), SearchCriteria.Op.NULL);
quarantinedIpAddressesSearch.and("endDate", quarantinedIpAddressesSearch.entity().getEndDate(), SearchCriteria.Op.GT);
quarantinedIpAddressesSearch.cp();
ipAddressSearchBuilder.done(); ipAddressSearchBuilder.done();
publicIpAddressByIdSearch.done(); publicIpAddressByIdSearch.done();
quarantinedIpAddressesSearch.done();
} }
@Override @Override
@ -68,4 +80,14 @@ public class PublicIpQuarantineDaoImpl extends GenericDaoBase<PublicIpQuarantine
return findOneBy(sc, filter); return findOneBy(sc, filter);
} }
@Override
public List<PublicIpQuarantineVO> listQuarantinedIpAddressesToUser(Long userId, Date date) {
SearchCriteria<PublicIpQuarantineVO> sc = quarantinedIpAddressesSearch.create();
sc.setParameters("previousOwnerId", userId);
sc.setParameters("endDate", date);
return searchIncludingRemoved(sc, null, false, false);
}
} }

View File

@ -117,7 +117,7 @@ Requires: ipset
Requires: perl Requires: perl
Requires: rsync Requires: rsync
Requires: cifs-utils Requires: cifs-utils
Requires: edk2-ovmf Requires: (edk2-ovmf or qemu-ovmf-x86_64)
Requires: swtpm Requires: swtpm
Requires: (python3-libvirt or python3-libvirt-python) Requires: (python3-libvirt or python3-libvirt-python)
Requires: (qemu-img or qemu-tools) Requires: (qemu-img or qemu-tools)

View File

@ -1 +0,0 @@
el8

View File

@ -0,0 +1 @@
../el8/cloud-ipallocator.rc

View File

@ -0,0 +1 @@
../el8/cloud.limits

750
packaging/suse15/cloud.spec Normal file
View File

@ -0,0 +1,750 @@
# 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.
%define __os_install_post %{nil}
%global debug_package %{nil}
%global __requires_exclude libc\\.so\\..*|libc\\.so\\.6\\(GLIBC_.*\\)
%define _binaries_in_noarch_packages_terminate_build 0
# DISABLE the post-percentinstall java repacking and line number stripping
# we need to find a way to just disable the java repacking and line number stripping, but not the autodeps
Name: cloudstack
Summary: CloudStack IaaS Platform
#http://fedoraproject.org/wiki/PackageNamingGuidelines#Pre-Release_packages
%define _maventag %{_fullver}
Release: %{_rel}
Version: %{_ver}
License: ASL 2.0
Vendor: Apache CloudStack <dev@cloudstack.apache.org>
Packager: Apache CloudStack <dev@cloudstack.apache.org>
Group: System Environment/Libraries
# FIXME do groups for every single one of the subpackages
Source0: %{name}-%{_maventag}.tgz
BuildRoot: %{_tmppath}/%{name}-%{_maventag}-%{release}-build
BuildArch: noarch
BuildRequires: (java-11-openjdk-devel or java-17-openjdk-devel or java-21-openjdk-devel)
#BuildRequires: ws-commons-util
BuildRequires: jpackage-utils
BuildRequires: gcc
BuildRequires: glibc-devel
BuildRequires: /usr/bin/mkisofs
BuildRequires: python3-setuptools
BuildRequires: wget
BuildRequires: nodejs
%description
CloudStack is a highly-scalable elastic, open source,
intelligent IaaS cloud implementation.
%package management
Summary: CloudStack management server UI
Requires: (java-17-openjdk or java-21-openjdk)
Requires: (tzdata-java or timezone-java)
Requires: python3
Requires: bash
Requires: gawk
Requires: which
Requires: file
Requires: tar
Requires: bzip2
Requires: gzip
Requires: unzip
Requires: (/sbin/mount.nfs or /usr/sbin/mount.nfs)
Requires: (openssh-clients or openssh)
Requires: (nfs-utils or nfs-client)
Requires: iproute
Requires: wget
Requires: (mysql or mariadb or mysql8.4)
Requires: sudo
Requires: /sbin/service
Requires: /sbin/chkconfig
Requires: /usr/bin/ssh-keygen
Requires: (genisoimage or mkisofs or xorrisofs)
Requires: ipmitool
Requires: %{name}-common = %{_ver}
Requires: (iptables-services or iptables)
Requires: rng-tools
Requires: (qemu-img or qemu-tools)
Requires: python3-pip
Requires: python3-six
Requires: python3-protobuf
Requires: python3-setuptools
Requires: (libgcrypt > 1.8.3 or libgcrypt20)
Group: System Environment/Libraries
%description management
The CloudStack management server is the central point of coordination,
management, and intelligence in CloudStack.
%package common
Summary: Apache CloudStack common files and scripts
Requires: python3
Group: System Environment/Libraries
%description common
The Apache CloudStack files shared between agent and management server
%global __requires_exclude libc\\.so\\..*|libc\\.so\\.6\\(GLIBC_.*\\)|^(libuuid\\.so\\.1|/usr/bin/python)$
%package agent
Summary: CloudStack Agent for KVM hypervisors
Requires: (openssh-clients or openssh)
Requires: (java-17-openjdk or java-21-openjdk)
Requires: (tzdata-java or timezone-java)
Requires: %{name}-common = %{_ver}
Requires: libvirt
Requires: libvirt-daemon-driver-storage-rbd
Requires: ebtables
Requires: iptables
Requires: ethtool
Requires: (net-tools or net-tools-deprecated)
Requires: iproute
Requires: ipset
Requires: perl
Requires: rsync
Requires: cifs-utils
Requires: (edk2-ovmf or qemu-ovmf-x86_64)
Requires: swtpm
Requires: (python3-libvirt or python3-libvirt-python)
Requires: (qemu-img or qemu-tools)
Requires: qemu-kvm
Requires: cryptsetup
Requires: rng-tools
Requires: (libgcrypt > 1.8.3 or libgcrypt20)
Requires: (selinux-tools if selinux-tools)
Requires: sysstat
Provides: cloud-agent
Group: System Environment/Libraries
%description agent
The CloudStack agent for KVM hypervisors
%package baremetal-agent
Summary: CloudStack baremetal agent
Requires: tftp-server
Requires: xinetd
Requires: syslinux
Requires: chkconfig
Requires: dhcp
Requires: httpd
Group: System Environment/Libraries
%description baremetal-agent
The CloudStack baremetal agent
%package usage
Summary: CloudStack Usage calculation server
Requires: (java-17-openjdk or java-21-openjdk)
Requires: (tzdata-java or timezone-java)
Group: System Environment/Libraries
%description usage
The CloudStack usage calculation service
%package ui
Summary: CloudStack UI
Group: System Environment/Libraries
%description ui
The CloudStack UI
%package marvin
Summary: Apache CloudStack Marvin library
Requires: python3-pip
Requires: gcc
Requires: python3-devel
Requires: libffi-devel
Requires: openssl-devel
Group: System Environment/Libraries
%description marvin
Apache CloudStack Marvin library
%package integration-tests
Summary: Apache CloudStack Marvin integration tests
Requires: %{name}-marvin = %{_ver}
Group: System Environment/Libraries
%description integration-tests
Apache CloudStack Marvin integration tests
%if "%{_ossnoss}" == "noredist"
%package mysql-ha
Summary: Apache CloudStack Balancing Strategy for MySQL
Group: System Environmnet/Libraries
%description mysql-ha
Apache CloudStack Balancing Strategy for MySQL
%endif
%prep
echo Doing CloudStack build
%setup -q -n %{name}-%{_maventag}
%build
cp packaging/suse15/replace.properties build/replace.properties
echo VERSION=%{_maventag} >> build/replace.properties
echo PACKAGE=%{name} >> build/replace.properties
touch build/gitrev.txt
echo $(git rev-parse HEAD) > build/gitrev.txt
if [ "%{_ossnoss}" == "NOREDIST" -o "%{_ossnoss}" == "noredist" ] ; then
echo "Adding noredist flag to the maven build"
FLAGS="$FLAGS -Dnoredist"
fi
if [ "%{_sim}" == "SIMULATOR" -o "%{_sim}" == "simulator" ] ; then
echo "Adding simulator flag to the maven build"
FLAGS="$FLAGS -Dsimulator"
fi
if [ \"%{_temp}\" != "" ]; then
echo "Adding flags to package requested templates"
FLAGS="$FLAGS `rpm --eval %{?_temp}`"
fi
mvn -Psystemvm,developer $FLAGS clean package
cd ui && npm install && npm run build && cd ..
%install
[ ${RPM_BUILD_ROOT} != "/" ] && rm -rf ${RPM_BUILD_ROOT}
# Common directories
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/agent
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/ipallocator
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/cache/%{name}/management/work
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/cache/%{name}/management/temp
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/%{name}/mnt
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/%{name}/management
mkdir -p ${RPM_BUILD_ROOT}%{_initrddir}
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/default
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/profile.d
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d
# Common
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/python-site
mkdir -p ${RPM_BUILD_ROOT}/usr/bin
cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts
install -D systemvm/dist/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/
install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/python-site/cloud_utils.py
cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/python-site/
python3 -m py_compile ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/python-site/cloud_utils.py
python3 -m compileall ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/python-site/cloudutils
cp build/gitrev.txt ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts
cp packaging/suse15/cloudstack-sccs ${RPM_BUILD_ROOT}/usr/bin
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts/network/cisco
cp -r plugins/network-elements/cisco-vnmc/src/main/scripts/network/cisco/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts/network/cisco
# Management
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/lib
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/setup
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/cks/conf
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/management
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/systemd/system/%{name}-management.service.d
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/run
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/setup/wheel
# Setup Jetty
ln -sf /etc/%{name}/management ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/conf
ln -sf /var/log/%{name}/management ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/logs
install -D client/target/utilities/bin/cloud-migrate-databases ${RPM_BUILD_ROOT}%{_bindir}/%{name}-migrate-databases
install -D client/target/utilities/bin/cloud-set-guest-password ${RPM_BUILD_ROOT}%{_bindir}/%{name}-set-guest-password
install -D client/target/utilities/bin/cloud-set-guest-sshkey ${RPM_BUILD_ROOT}%{_bindir}/%{name}-set-guest-sshkey
install -D client/target/utilities/bin/cloud-setup-databases ${RPM_BUILD_ROOT}%{_bindir}/%{name}-setup-databases
install -D client/target/utilities/bin/cloud-setup-encryption ${RPM_BUILD_ROOT}%{_bindir}/%{name}-setup-encryption
install -D client/target/utilities/bin/cloud-setup-management ${RPM_BUILD_ROOT}%{_bindir}/%{name}-setup-management
install -D client/target/utilities/bin/cloud-setup-baremetal ${RPM_BUILD_ROOT}%{_bindir}/%{name}-setup-baremetal
install -D client/target/utilities/bin/cloud-sysvmadm ${RPM_BUILD_ROOT}%{_bindir}/%{name}-sysvmadm
install -D client/target/utilities/bin/cloud-update-xenserver-licenses ${RPM_BUILD_ROOT}%{_bindir}/%{name}-update-xenserver-licenses
# Bundle cmk in cloudstack-management
wget https://github.com/apache/cloudstack-cloudmonkey/releases/latest/download/cmk.linux.x86-64 -O ${RPM_BUILD_ROOT}%{_bindir}/cmk
chmod +x ${RPM_BUILD_ROOT}%{_bindir}/cmk
cp -r client/target/utilities/scripts/db/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/setup
cp -r plugins/integrations/kubernetes-service/src/main/resources/conf/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/cks/conf
cp -r client/target/cloud-client-ui-%{_maventag}.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/
cp -r client/target/classes/META-INF/webapp ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapp
cp ui/dist/config.json ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/
cp -r ui/dist/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapp/
rm -f ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapp/config.json
ln -sf /etc/%{name}/management/config.json ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapp/config.json
mv ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/cloud-client-ui-%{_maventag}.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/lib/cloudstack-%{_maventag}.jar
cp client/target/lib/*jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/lib/
# Don't package the scripts in the management webapp
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/scripts
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/vms
for name in db.properties server.properties log4j-cloud.xml environment.properties java.security.ciphers
do
cp client/target/conf/$name ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/$name
done
ln -sf log4j-cloud.xml ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/log4j2.xml
install python/bindir/cloud-external-ipallocator.py ${RPM_BUILD_ROOT}%{_bindir}/%{name}-external-ipallocator.py
install -D client/target/pythonlibs/jasypt-1.9.3.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/lib/jasypt-1.9.3.jar
install -D utils/target/cloud-utils-%{_maventag}-bundled.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/lib/%{name}-utils.jar
install -D packaging/suse15/cloud-ipallocator.rc ${RPM_BUILD_ROOT}%{_initrddir}/%{name}-ipallocator
install -D packaging/suse15/cloud.limits ${RPM_BUILD_ROOT}%{_sysconfdir}/security/limits.d/cloud
install -D packaging/suse15/filelimit.conf ${RPM_BUILD_ROOT}%{_sysconfdir}/systemd/system/%{name}-management.service.d
install -D packaging/systemd/cloudstack-management.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-management.service
install -D packaging/systemd/cloudstack-management.default ${RPM_BUILD_ROOT}%{_sysconfdir}/default/%{name}-management
install -D server/target/conf/cloudstack-sudoers ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management
touch ${RPM_BUILD_ROOT}%{_localstatedir}/run/%{name}-management.pid
#install -D server/target/conf/cloudstack-catalina.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-catalina
install -D server/target/conf/cloudstack-management.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-management
install -D plugins/integrations/kubernetes-service/src/main/resources/conf/etcd-node.yml ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/cks/conf/etcd-node.yml
install -D plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node.yml ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/cks/conf/k8s-control-node.yml
install -D plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node-add.yml ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/cks/conf/k8s-control-node-add.yml
install -D plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-node.yml ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/cks/conf/k8s-node.yml
# SystemVM template
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/templates/systemvm
cp -r engine/schema/dist/systemvm-templates/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/templates/systemvm
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/templates/systemvm/sha512sum.txt
# Sample Extensions
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/extensions
cp -r extensions/* ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/extensions
ln -sf %{_sysconfdir}/%{name}/extensions ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/extensions
# UI
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/ui
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-ui/
cp -r client/target/classes/META-INF/webapp/WEB-INF ${RPM_BUILD_ROOT}%{_datadir}/%{name}-ui
cp ui/dist/config.json ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/ui/
cp -r ui/dist/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-ui/
rm -f ${RPM_BUILD_ROOT}%{_datadir}/%{name}-ui/config.json
ln -sf /etc/%{name}/ui/config.json ${RPM_BUILD_ROOT}%{_datadir}/%{name}-ui/config.json
# Package mysql-connector-python (bundled to avoid dependency on external community repo)
# Version 8.0.31 is the last version supporting Python 3.6 (EL8)
wget -P ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/setup/wheel https://files.pythonhosted.org/packages/08/1f/42d74bae9dd6dcfec67c9ed0f3fa482b1ae5ac5f117ca82ab589ecb3ca19/mysql_connector_python-8.0.31-py2.py3-none-any.whl
# Version 8.3.0 supports Python 3.8 to 3.12 (EL9, EL10)
wget -P ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/setup/wheel https://files.pythonhosted.org/packages/53/ed/26a4b8cacb8852c6fd97d2d58a7f2591c41989807ea82bd8d9725a4e6937/mysql_connector_python-8.3.0-py2.py3-none-any.whl
chmod 440 ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management
chmod 770 ${RPM_BUILD_ROOT}%{_localstatedir}/%{name}/mnt
chmod 770 ${RPM_BUILD_ROOT}%{_localstatedir}/%{name}/management
chmod 770 ${RPM_BUILD_ROOT}%{_localstatedir}/cache/%{name}/management/work
chmod 770 ${RPM_BUILD_ROOT}%{_localstatedir}/cache/%{name}/management/temp
chmod 770 ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/management
chmod 770 ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/agent
# KVM Agent
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/agent
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/agent
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/lib
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/plugins
install -D packaging/systemd/cloudstack-agent.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-agent.service
install -D packaging/systemd/cloudstack-rolling-maintenance@.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-rolling-maintenance@.service
install -D packaging/systemd/cloudstack-agent.default ${RPM_BUILD_ROOT}%{_sysconfdir}/default/%{name}-agent
install -D agent/target/transformed/agent.properties ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/agent/agent.properties
install -D agent/target/transformed/uefi.properties ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/agent/uefi.properties
install -D agent/target/transformed/environment.properties ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/agent/environment.properties
install -D agent/target/transformed/log4j-cloud.xml ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/agent/log4j-cloud.xml
install -D agent/target/transformed/cloud-setup-agent ${RPM_BUILD_ROOT}%{_bindir}/%{name}-setup-agent
install -D agent/target/transformed/cloudstack-agent-upgrade ${RPM_BUILD_ROOT}%{_bindir}/%{name}-agent-upgrade
install -D agent/target/transformed/cloud-guest-tool ${RPM_BUILD_ROOT}%{_bindir}/%{name}-guest-tool
install -D agent/target/transformed/libvirtqemuhook ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/lib/libvirtqemuhook
install -D agent/target/transformed/rolling-maintenance ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/lib/rolling-maintenance
install -D agent/target/transformed/cloud-ssh ${RPM_BUILD_ROOT}%{_bindir}/%{name}-ssh
install -D agent/target/transformed/cloudstack-agent-profile.sh ${RPM_BUILD_ROOT}%{_sysconfdir}/profile.d/%{name}-agent-profile.sh
install -D agent/target/transformed/cloudstack-agent.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-agent
install -D plugins/hypervisors/kvm/target/cloud-plugin-hypervisor-kvm-%{_maventag}.jar ${RPM_BUILD_ROOT}%{_datadir}/%name-agent/lib/cloud-plugin-hypervisor-kvm-%{_maventag}.jar
cp plugins/hypervisors/kvm/target/dependencies/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/lib
cp plugins/storage/volume/storpool/target/*.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/lib
cp plugins/storage/volume/linstor/target/*.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/lib
# Usage server
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/usage
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-usage/lib
install -D usage/target/cloud-usage-%{_maventag}.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-usage/cloud-usage-%{_maventag}.jar
install -D usage/target/transformed/db.properties ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/usage/db.properties
install -D usage/target/transformed/log4j-cloud_usage.xml ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/usage/log4j-cloud.xml
cp usage/target/dependencies/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-usage/lib/
cp client/target/lib/mysql*jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-usage/lib/
install -D packaging/systemd/cloudstack-usage.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-usage.service
install -D packaging/systemd/cloudstack-usage.default ${RPM_BUILD_ROOT}%{_sysconfdir}/default/%{name}-usage
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/usage/
install -D usage/target/transformed/cloudstack-usage.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-usage
# Marvin
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-marvin
cp tools/marvin/dist/Marvin-*.tar.gz ${RPM_BUILD_ROOT}%{_datadir}/%{name}-marvin/
# integration-tests
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-integration-tests
cp -r test/integration/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-integration-tests/
# MYSQL HA
if [ "x%{_ossnoss}" == "xnoredist" ] ; then
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-mysql-ha/lib
cp -r plugins/database/mysql-ha/target/cloud-plugin-database-mysqlha-%{_maventag}.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-mysql-ha/lib
fi
#License files from whisker
install -D tools/whisker/NOTICE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-management-%{version}/NOTICE
install -D tools/whisker/LICENSE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-management-%{version}/LICENSE
install -D tools/whisker/NOTICE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-common-%{version}/NOTICE
install -D tools/whisker/LICENSE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-common-%{version}/LICENSE
install -D tools/whisker/NOTICE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-agent-%{version}/NOTICE
install -D tools/whisker/LICENSE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-agent-%{version}/LICENSE
install -D tools/whisker/NOTICE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-usage-%{version}/NOTICE
install -D tools/whisker/LICENSE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-usage-%{version}/LICENSE
install -D tools/whisker/NOTICE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-ui-%{version}/NOTICE
install -D tools/whisker/LICENSE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-ui-%{version}/LICENSE
install -D tools/whisker/NOTICE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-marvin-%{version}/NOTICE
install -D tools/whisker/LICENSE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-marvin-%{version}/LICENSE
install -D tools/whisker/NOTICE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-integration-tests-%{version}/NOTICE
install -D tools/whisker/LICENSE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-integration-tests-%{version}/LICENSE
%clean
[ ${RPM_BUILD_ROOT} != "/" ] && rm -rf ${RPM_BUILD_ROOT}
%posttrans common
unalias cp
python_dir=$(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")
if [ ! -z $python_dir ];then
cp -f -r /usr/share/cloudstack-common/python-site/* $python_dir/
fi
%preun management
/usr/bin/systemctl stop cloudstack-management || true
/usr/bin/systemctl disable cloudstack-management || true
%pre management
id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -U -c "CloudStack unprivileged user" \
-r -s /bin/sh -d %{_localstatedir}/cloudstack/management cloud || true
rm -rf %{_localstatedir}/cache/cloudstack
# in case of upgrade to 4.9+ copy commands.properties if not exists in /etc/cloudstack/management/
if [ "$1" == "2" ] ; then
if [ -f "%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties" ] && [ ! -f "%{_sysconfdir}/%{name}/management/commands.properties" ] ; then
cp -p %{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties %{_sysconfdir}/%{name}/management/commands.properties
fi
fi
# Remove old tomcat symlinks and env config file
if [ -L "%{_datadir}/%{name}-management/lib" ]
then
rm -f %{_datadir}/%{name}-management/bin
rm -f %{_datadir}/%{name}-management/lib
rm -f %{_datadir}/%{name}-management/temp
rm -f %{_datadir}/%{name}-management/work
rm -f %{_sysconfdir}/default/%{name}-management
fi
%post management
# Install mysql-connector-python wheel
# Detect Python version to install compatible wheel
if python3 -c 'import sys; sys.exit(0 if sys.version_info >= (3, 7) else 1)'; then
pip3 install %{_datadir}/%{name}-management/setup/wheel/mysql_connector_python-8.3.0-py2.py3-none-any.whl
else
pip3 install %{_datadir}/%{name}-management/setup/wheel/mysql_connector_python-8.0.31-py2.py3-none-any.whl
fi
/usr/bin/systemctl enable cloudstack-management > /dev/null 2>&1 || true
/usr/bin/systemctl enable --now rngd > /dev/null 2>&1 || true
grep -s -q "db.cloud.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.cloud.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties"
grep -s -q "db.usage.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.usage.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties"
grep -s -q "db.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties"
# Update DB properties having master and slave(s), with source and replica(s) respectively (for inclusiveness)
grep -s -q "^db.cloud.slaves=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.cloud.slaves=/db.cloud.replicas=/g" "%{_sysconfdir}/%{name}/management/db.properties"
grep -s -q "^db.cloud.secondsBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.cloud.secondsBeforeRetryMaster=/db.cloud.secondsBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties"
grep -s -q "^db.cloud.queriesBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.cloud.queriesBeforeRetryMaster=/db.cloud.queriesBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties"
grep -s -q "^db.usage.slaves=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.usage.slaves=/db.usage.replicas=/g" "%{_sysconfdir}/%{name}/management/db.properties"
grep -s -q "^db.usage.secondsBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.usage.secondsBeforeRetryMaster=/db.usage.secondsBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties"
grep -s -q "^db.usage.queriesBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.usage.queriesBeforeRetryMaster=/db.usage.queriesBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties"
if [ ! -f %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/vhd-util ] ; then
echo Please download vhd-util from http://download.cloudstack.org/tools/vhd-util and put it in
echo %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/
fi
if [ -f %{_sysconfdir}/sysconfig/%{name}-management ] ; then
rm -f %{_sysconfdir}/sysconfig/%{name}-management
fi
chown -R cloud:cloud /var/log/cloudstack/management
chown -R cloud:cloud /usr/share/cloudstack-management/templates
find /usr/share/cloudstack-management/templates -type d -exec chmod 0770 {} \;
systemctl daemon-reload
%posttrans management
# Print help message
if [ -f "/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text" ];then
sed -i "s,^ACS_VERSION=.*,ACS_VERSION=%{_maventag},g" /usr/share/cloudstack-common/scripts/installer/cloudstack-help-text
/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text management
fi
%preun agent
/sbin/service cloudstack-agent stop || true
if [ "$1" == "0" ] ; then
/sbin/chkconfig --del cloudstack-agent > /dev/null 2>&1 || true
fi
%pre agent
# save old configs if they exist (for upgrade). Otherwise we may lose them
# when the old packages are erased. There are a lot of properties files here.
if [ -d "%{_sysconfdir}/cloud" ] ; then
mv %{_sysconfdir}/cloud %{_sysconfdir}/cloud.rpmsave
fi
%posttrans agent
if [ "$1" == "2" ] ; then
echo "Running %{_bindir}/%{name}-agent-upgrade to update bridge name for upgrade from CloudStack 4.0.x (and before) to CloudStack 4.1 (and later)"
%{_bindir}/%{name}-agent-upgrade
fi
if [ ! -d %{_sysconfdir}/libvirt/hooks ] ; then
mkdir %{_sysconfdir}/libvirt/hooks
fi
cp -a ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/lib/libvirtqemuhook %{_sysconfdir}/libvirt/hooks/qemu
mkdir -m 0755 -p /usr/share/cloudstack-agent/tmp
/usr/bin/systemctl restart libvirtd
/usr/bin/systemctl enable cloudstack-agent > /dev/null 2>&1 || true
/usr/bin/systemctl enable cloudstack-rolling-maintenance@p > /dev/null 2>&1 || true
/usr/bin/systemctl enable --now rngd > /dev/null 2>&1 || true
# if saved agent.properties from upgrade exist, copy them over
if [ -f "%{_sysconfdir}/cloud.rpmsave/agent/agent.properties" ]; then
mv %{_sysconfdir}/%{name}/agent/agent.properties %{_sysconfdir}/%{name}/agent/agent.properties.rpmnew
cp -p %{_sysconfdir}/cloud.rpmsave/agent/agent.properties %{_sysconfdir}/%{name}/agent
# make sure we only do this on the first install of this RPM, don't want to overwrite on a reinstall
mv %{_sysconfdir}/cloud.rpmsave/agent/agent.properties %{_sysconfdir}/cloud.rpmsave/agent/agent.properties.rpmsave
fi
# if saved uefi.properties from upgrade exist, copy them over
if [ -f "%{_sysconfdir}/cloud.rpmsave/agent/uefi.properties" ]; then
mv %{_sysconfdir}/%{name}/agent/uefi.properties %{_sysconfdir}/%{name}/agent/uefi.properties.rpmnew
cp -p %{_sysconfdir}/cloud.rpmsave/agent/uefi.properties %{_sysconfdir}/%{name}/agent
# make sure we only do this on the first install of this RPM, don't want to overwrite on a reinstall
mv %{_sysconfdir}/cloud.rpmsave/agent/uefi.properties %{_sysconfdir}/cloud.rpmsave/agent/uefi.properties.rpmsave
fi
systemctl daemon-reload
# Print help message
if [ -f "/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text" ];then
sed -i "s,^ACS_VERSION=.*,ACS_VERSION=%{_maventag},g" /usr/share/cloudstack-common/scripts/installer/cloudstack-help-text
/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text agent
fi
%pre usage
id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -U -c "CloudStack unprivileged user" \
-r -s /bin/sh -d %{_localstatedir}/cloudstack/management cloud|| true
%preun usage
/sbin/service cloudstack-usage stop || true
if [ "$1" == "0" ] ; then
/sbin/chkconfig --del cloudstack-usage > /dev/null 2>&1 || true
fi
%post usage
if [ -f "%{_sysconfdir}/%{name}/management/db.properties" ]; then
echo "Replacing usage server's db.properties with a link to the management server's db.properties"
rm -f %{_sysconfdir}/%{name}/usage/db.properties
ln -s %{_sysconfdir}/%{name}/management/db.properties %{_sysconfdir}/%{name}/usage/db.properties
/usr/bin/systemctl enable cloudstack-usage > /dev/null 2>&1 || true
fi
if [ -f "%{_sysconfdir}/%{name}/management/key" ]; then
echo "Replacing usage server's key with a link to the management server's key"
rm -f %{_sysconfdir}/%{name}/usage/key
ln -s %{_sysconfdir}/%{name}/management/key %{_sysconfdir}/%{name}/usage/key
fi
if [ ! -f "%{_sysconfdir}/%{name}/usage/key" ]; then
ln -s %{_sysconfdir}/%{name}/management/key %{_sysconfdir}/%{name}/usage/key
fi
mkdir -p /usr/local/libexec
if [ ! -f "/usr/local/libexec/sanity-check-last-id" ]; then
echo 1 > /usr/local/libexec/sanity-check-last-id
fi
chown cloud:cloud /usr/local/libexec/sanity-check-last-id
%posttrans usage
# Print help message
if [ -f "/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text" ];then
sed -i "s,^ACS_VERSION=.*,ACS_VERSION=%{_maventag},g" /usr/share/cloudstack-common/scripts/installer/cloudstack-help-text
/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text usage
fi
%post marvin
pip3 install --upgrade https://files.pythonhosted.org/packages/08/1f/42d74bae9dd6dcfec67c9ed0f3fa482b1ae5ac5f117ca82ab589ecb3ca19/mysql_connector_python-8.0.31-py2.py3-none-any.whl
pip3 install --upgrade /usr/share/cloudstack-marvin/Marvin-*.tar.gz
#No default permission as the permission setup is complex
%files management
%defattr(-,root,root,-)
%dir %{_datadir}/%{name}-management
%dir %attr(0770,root,cloud) %{_localstatedir}/%{name}/mnt
%dir %attr(0770,cloud,cloud) %{_localstatedir}/%{name}/management
%dir %attr(0770,root,cloud) %{_localstatedir}/cache/%{name}/management
%dir %attr(0770,root,cloud) %{_localstatedir}/log/%{name}/management
%config(noreplace) %{_sysconfdir}/default/%{name}-management
%config(noreplace) %{_sysconfdir}/sudoers.d/%{name}-management
%config(noreplace) %{_sysconfdir}/security/limits.d/cloud
%config(noreplace) %{_sysconfdir}/systemd/system/%{name}-management.service.d
%config(noreplace) %attr(0640,root,cloud) %{_sysconfdir}/%{name}/management/db.properties
%config(noreplace) %attr(0640,root,cloud) %{_sysconfdir}/%{name}/management/server.properties
%config(noreplace) %attr(0640,root,cloud) %{_sysconfdir}/%{name}/management/config.json
%config(noreplace) %{_sysconfdir}/%{name}/management/log4j-cloud.xml
%config(noreplace) %{_sysconfdir}/%{name}/management/log4j2.xml
%config(noreplace) %{_sysconfdir}/%{name}/management/environment.properties
%config(noreplace) %{_sysconfdir}/%{name}/management/java.security.ciphers
%config(noreplace) %attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-management
%attr(0644,root,root) %{_unitdir}/%{name}-management.service
%attr(0755,cloud,cloud) %{_localstatedir}/run/%{name}-management.pid
%attr(0755,root,root) %{_bindir}/%{name}-setup-management
%attr(0755,root,root) %{_bindir}/%{name}-update-xenserver-licenses
%{_datadir}/%{name}-management/conf
%{_datadir}/%{name}-management/lib/*.jar
%{_datadir}/%{name}-management/logs
%{_datadir}/%{name}-management/templates
%{_datadir}/%{name}-management/extensions
%attr(0755,root,root) %{_bindir}/%{name}-setup-databases
%attr(0755,root,root) %{_bindir}/%{name}-migrate-databases
%attr(0755,root,root) %{_bindir}/%{name}-set-guest-password
%attr(0755,root,root) %{_bindir}/%{name}-set-guest-sshkey
%attr(0755,root,root) %{_bindir}/%{name}-sysvmadm
%attr(0755,root,root) %{_bindir}/%{name}-setup-encryption
%attr(0755,root,root) %{_bindir}/cmk
%{_datadir}/%{name}-management/cks/conf/*.yml
%{_datadir}/%{name}-management/setup/*.sql
%{_datadir}/%{name}-management/setup/*.sh
%{_datadir}/%{name}-management/setup/server-setup.xml
%{_datadir}/%{name}-management/webapp/*
%dir %attr(0770, cloud, cloud) %{_datadir}/%{name}-management/templates
%dir %attr(0770, cloud, cloud) %{_datadir}/%{name}-management/templates/systemvm
%attr(0644, cloud, cloud) %{_datadir}/%{name}-management/templates/systemvm/*
%attr(0755,root,root) %{_bindir}/%{name}-external-ipallocator.py
%attr(0755,root,root) %{_initrddir}/%{name}-ipallocator
%dir %attr(0770,root,root) %{_localstatedir}/log/%{name}/ipallocator
%{_defaultdocdir}/%{name}-management-%{version}/LICENSE
%{_defaultdocdir}/%{name}-management-%{version}/NOTICE
%{_datadir}/%{name}-management/setup/wheel/*.whl
%dir %attr(0755,cloud,cloud) %{_sysconfdir}/%{name}/extensions
%attr(0755,cloud,cloud) %{_sysconfdir}/%{name}/extensions/*
%files agent
%attr(0755,root,root) %{_bindir}/%{name}-setup-agent
%attr(0755,root,root) %{_bindir}/%{name}-agent-upgrade
%attr(0755,root,root) %{_bindir}/%{name}-guest-tool
%attr(0755,root,root) %{_bindir}/%{name}-ssh
%attr(0644,root,root) %{_unitdir}/%{name}-agent.service
%attr(0644,root,root) %{_unitdir}/%{name}-rolling-maintenance@.service
%config(noreplace) %{_sysconfdir}/default/%{name}-agent
%attr(0644,root,root) %{_sysconfdir}/profile.d/%{name}-agent-profile.sh
%config(noreplace) %attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-agent
%attr(0755,root,root) %{_datadir}/%{name}-common/scripts/network/cisco
%config(noreplace) %{_sysconfdir}/%{name}/agent
%dir %{_localstatedir}/log/%{name}/agent
%attr(0644,root,root) %{_datadir}/%{name}-agent/lib/*.jar
%attr(0755,root,root) %{_datadir}/%{name}-agent/lib/libvirtqemuhook
%attr(0755,root,root) %{_datadir}/%{name}-agent/lib/rolling-maintenance
%dir %{_datadir}/%{name}-agent/plugins
%{_defaultdocdir}/%{name}-agent-%{version}/LICENSE
%{_defaultdocdir}/%{name}-agent-%{version}/NOTICE
%files common
%dir %attr(0755,root,root) %{_datadir}/%{name}-common/python-site/cloudutils
%dir %attr(0755,root,root) %{_datadir}/%{name}-common/vms
%attr(0755,root,root) %{_datadir}/%{name}-common/scripts
%attr(0755,root,root) /usr/bin/cloudstack-sccs
%attr(0644, root, root) %{_datadir}/%{name}-common/vms/agent.zip
%attr(0644, root, root) %{_datadir}/%{name}-common/vms/cloud-scripts.tgz
%attr(0644, root, root) %{_datadir}/%{name}-common/vms/patch-sysvms.sh
%attr(0644,root,root) %{_datadir}/%{name}-common/python-site/cloud_utils.py
%attr(0644,root,root) %{_datadir}/%{name}-common/python-site/__pycache__/*
%attr(0644,root,root) %{_datadir}/%{name}-common/python-site/cloudutils/*
%attr(0644, root, root) %{_datadir}/%{name}-common/lib/jasypt-1.9.3.jar
%attr(0644, root, root) %{_datadir}/%{name}-common/lib/%{name}-utils.jar
%{_defaultdocdir}/%{name}-common-%{version}/LICENSE
%{_defaultdocdir}/%{name}-common-%{version}/NOTICE
%files ui
%config(noreplace) %attr(0640,root,cloud) %{_sysconfdir}/%{name}/ui/config.json
%{_datadir}/%{name}-ui/*
%{_defaultdocdir}/%{name}-ui-%{version}/LICENSE
%{_defaultdocdir}/%{name}-ui-%{version}/NOTICE
%files usage
%attr(0644,root,root) %{_unitdir}/%{name}-usage.service
%config(noreplace) %{_sysconfdir}/default/%{name}-usage
%config(noreplace) %attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-usage
%attr(0644,root,root) %{_datadir}/%{name}-usage/*.jar
%attr(0644,root,root) %{_datadir}/%{name}-usage/lib/*.jar
%dir %attr(0770,root,cloud) %{_localstatedir}/log/%{name}/usage
%attr(0644,root,root) %{_sysconfdir}/%{name}/usage/db.properties
%attr(0644,root,root) %{_sysconfdir}/%{name}/usage/log4j-cloud.xml
%{_defaultdocdir}/%{name}-usage-%{version}/LICENSE
%{_defaultdocdir}/%{name}-usage-%{version}/NOTICE
%files marvin
%attr(0644,root,root) %{_datadir}/%{name}-marvin/Marvin*.tar.gz
%{_defaultdocdir}/%{name}-marvin-%{version}/LICENSE
%{_defaultdocdir}/%{name}-marvin-%{version}/NOTICE
%files integration-tests
%attr(0755,root,root) %{_datadir}/%{name}-integration-tests/*
%{_defaultdocdir}/%{name}-integration-tests-%{version}/LICENSE
%{_defaultdocdir}/%{name}-integration-tests-%{version}/NOTICE
%if "%{_ossnoss}" == "noredist"
%files mysql-ha
%defattr(0644,cloud,cloud,0755)
%attr(0644,root,root) %{_datadir}/%{name}-mysql-ha/lib/*
%endif
%files baremetal-agent
%attr(0755,root,root) %{_bindir}/cloudstack-setup-baremetal
%changelog
* Thu Dec 22 2022 Rohit Yadav <rohit@apache.org> 4.18.0
- Add support for EL9
* Fri Oct 14 2022 Daan Hoogland <daan.hoogland@gmail.com> 4.18.0
- initialising sanity check pointer file
* Tue Jun 29 2021 David Jumani <dj.davidjumani1994@gmail.com> 4.16.0
- Adding SUSE 15 support
* Thu Apr 30 2015 Rohit Yadav <bhaisaab@apache.org> 4.6.0
- Remove awsapi package
* Wed Nov 19 2014 Hugo Trippaers <hugo@apache.org> 4.6.0
- Create a specific spec for CentOS 7
* Fri Jul 4 2014 Hugo Trippaers <hugo@apache.org> 4.5.0
- Add a package for the mysql ha module
* Fri Oct 5 2012 Hugo Trippaers <hugo@apache.org> 4.1.0
- new style spec file

View File

@ -0,0 +1 @@
../el8/cloudstack-agent.te

View File

@ -0,0 +1 @@
../el8/cloudstack-sccs

View File

@ -0,0 +1 @@
../el8/filelimit.conf

View File

@ -0,0 +1,65 @@
# 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.
DBUSER=cloud
DBPW=cloud
DBROOTPW=
MSLOG=vmops.log
APISERVERLOG=api.log
DBHOST=localhost
DBDRIVER=jdbc:mysql
COMPONENTS-SPEC=components-premium.xml
REMOTEHOST=localhost
AGENTCLASSPATH=
AGENTLOG=/var/log/cloudstack/agent/agent.log
AGENTLOGDIR=/var/log/cloudstack/agent/
AGENTSYSCONFDIR=/etc/cloudstack/agent
APISERVERLOG=/var/log/cloudstack/management/apilog.log
BINDIR=/usr/bin
COMMONLIBDIR=/usr/share/cloudstack-common
CONFIGUREVARS=
DEPSCLASSPATH=
DOCDIR=
IPALOCATORLOG=/var/log/cloudstack/management/ipallocator.log
JAVADIR=/usr/share/java
LIBEXECDIR=/usr/libexec
LOCKDIR=/var/lock
MSCLASSPATH=
MSCONF=/etc/cloudstack/management
MSENVIRON=/usr/share/cloudstack-management
MSLOG=/var/log/cloudstack/management/management-server.log
MSLOGDIR=/var/log/cloudstack/management/
MSMNTDIR=/var/cloudstack/mnt
MSUSER=cloud
PIDDIR=/var/run
PLUGINJAVADIR=/usr/share/cloudstack-management/plugin
PREMIUMJAVADIR=/usr/share/cloudstack-management/premium
PYTHONDIR=/usr/share/cloudstack-common/python-site/
SERVERSYSCONFDIR=/etc/sysconfig
SETUPDATADIR=/usr/share/cloudstack-management/setup
SYSCONFDIR=/etc/sysconfig
SYSTEMCLASSPATH=
SYSTEMJARS=
USAGECLASSPATH=
USAGELOG=/var/log/cloudstack/usage/usage.log
USAGESYSCONFDIR=/etc/sysconfig
EXTENSIONSDEPLOYMENTMODE=production
GUESTNVRAMTEMPLATELEGACY=/usr/share/qemu/ovmf-x86_64-vars.bin
GUESTLOADERLEGACY=/usr/share/qemu/ovmf-x86_64-code.bin
GUESTNVRAMTEMPLATESECURE=/usr/share/qemu/ovmf-x86_64-ms-vars.bin
GUESTLOADERSECURE=/usr/share/qemu/ovmf-x86_64-ms-code.bin
GUESTNVRAMPATH=/var/lib/libvirt/qemu/nvram/

View File

@ -17,7 +17,7 @@
JAVA_OPTS="-Djava.security.properties=/etc/cloudstack/management/java.security.ciphers -Djava.awt.headless=true -Xmx2G -XX:+UseParallelGC -XX:MaxGCPauseMillis=500 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/cloudstack/management/ -XX:ErrorFile=/var/log/cloudstack/management/cloudstack-management.err --add-opens=java.base/java.lang=ALL-UNNAMED --add-exports=java.base/sun.security.x509=ALL-UNNAMED" JAVA_OPTS="-Djava.security.properties=/etc/cloudstack/management/java.security.ciphers -Djava.awt.headless=true -Xmx2G -XX:+UseParallelGC -XX:MaxGCPauseMillis=500 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/cloudstack/management/ -XX:ErrorFile=/var/log/cloudstack/management/cloudstack-management.err --add-opens=java.base/java.lang=ALL-UNNAMED --add-exports=java.base/sun.security.x509=ALL-UNNAMED"
CLASSPATH="/usr/share/cloudstack-management/lib/*:/etc/cloudstack/management:/usr/share/cloudstack-common:/usr/share/cloudstack-management/setup:/usr/share/cloudstack-management:/usr/share/java/mysql-connector-java.jar:/usr/share/cloudstack-mysql-ha/lib/*" CLASSPATH="/usr/share/cloudstack-management/lib/*:/etc/cloudstack/management:/usr/share/cloudstack-common:/usr/share/cloudstack-management/setup:/usr/share/cloudstack-management:/usr/share/cloudstack-mysql-ha/lib/*"
BOOTSTRAP_CLASS=org.apache.cloudstack.ServerDaemon BOOTSTRAP_CLASS=org.apache.cloudstack.ServerDaemon

View File

@ -17,7 +17,7 @@
JAVA_OPTS="-Xms256m -Xmx2048m --add-opens=java.base/java.lang=ALL-UNNAMED" JAVA_OPTS="-Xms256m -Xmx2048m --add-opens=java.base/java.lang=ALL-UNNAMED"
CLASSPATH="/usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage:/usr/share/java/mysql-connector-java.jar" CLASSPATH="/usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage"
JAVA_CLASS=com.cloud.usage.UsageServer JAVA_CLASS=com.cloud.usage.UsageServer

View File

@ -2047,7 +2047,7 @@ public class KVMStorageProcessor implements StorageProcessor {
try { try {
Thread.sleep(10000); Thread.sleep(10000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new CloudRuntimeException(e); logger.trace("Thread that was tracking the progress for backup of VM [{}] was interrupted. Ignoring.", vmName);
} }
} }

View File

@ -217,13 +217,14 @@ public class AdaptiveDataStoreLifeCycleImpl extends BasePrimaryDataStoreLifeCycl
// validate the provided details are correct/valid for the provider // validate the provided details are correct/valid for the provider
api.validate(); api.validate();
// if we have user-provided capacity bytes, validate they do not exceed the manaaged storage capacity bytes // User-provided capacityBytes always wins; validate against storage stats only when
// the provider could actually report them. If the provider cannot (empty pod with no
// footprint, no quota set, transient probe failure), fall through and use what the
// user supplied rather than failing the whole registration.
ProviderVolumeStorageStats stats = api.getManagedStorageStats(); ProviderVolumeStorageStats stats = api.getManagedStorageStats();
if (capacityBytes != null && capacityBytes != 0 && stats != null) { if (capacityBytes != null && capacityBytes > 0) {
if (stats.getCapacityInBytes() > 0) { if (stats != null && stats.getCapacityInBytes() > 0 && stats.getCapacityInBytes() < capacityBytes) {
if (stats.getCapacityInBytes() < capacityBytes) { throw new InvalidParameterValueException("Provided capacity bytes exceed the capacity of the storage endpoint: provided by user: " + capacityBytes + ", storage capacity from storage provider: " + stats.getCapacityInBytes());
throw new InvalidParameterValueException("Capacity bytes provided exceeds the capacity of the storage endpoint: provided by user: " + capacityBytes + ", storage capacity from storage provider: " + stats.getCapacityInBytes());
}
} }
parameters.setCapacityBytes(capacityBytes); parameters.setCapacityBytes(capacityBytes);
} }

View File

@ -23,7 +23,8 @@ import java.net.URL;
import java.security.KeyManagementException; import java.security.KeyManagementException;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat; import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -88,6 +89,9 @@ public class FlashArrayAdapter implements ProviderAdapter {
static final ObjectMapper mapper = new ObjectMapper(); static final ObjectMapper mapper = new ObjectMapper();
public String pod = null; public String pod = null;
public String hostgroup = null; public String hostgroup = null;
private static final DateTimeFormatter DELETION_TIMESTAMP_FORMAT =
DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneOffset.UTC);
private String username; private String username;
private String password; private String password;
private String accessToken; private String accessToken;
@ -200,28 +204,63 @@ public class FlashArrayAdapter implements ProviderAdapter {
@Override @Override
public void delete(ProviderAdapterContext context, ProviderAdapterDataObject dataObject) { public void delete(ProviderAdapterContext context, ProviderAdapterDataObject dataObject) {
// first make sure we are disconnected
removeVlunsAll(context, pod, dataObject.getExternalName());
String fullName = normalizeName(pod, dataObject.getExternalName()); String fullName = normalizeName(pod, dataObject.getExternalName());
FlashArrayVolume volume = new FlashArrayVolume(); // Snapshots live under /volume-snapshots and already use the array's
// reserved form <volume>.<suffix>, which legitimately contains ".".
// The stricter [A-Za-z0-9_-] naming rule applies to regular volume
// names and free-form rename targets, not to these reserved snapshot
// names. Since FlashArray snapshot names are system-defined rather
// than arbitrary rename targets, we skip the usual timestamped rename
// and only mark snapshots destroyed; the array's own ".N" suffix
// already disambiguates them in the recycle bin.
if (dataObject.getType() == ProviderAdapterDataObject.Type.SNAPSHOT) {
try {
FlashArrayVolume destroy = new FlashArrayVolume();
destroy.setDestroyed(true);
PATCH("/volume-snapshots?names=" + fullName, destroy, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
});
} catch (CloudRuntimeException e) {
String msg = e.getMessage();
if (msg != null && (msg.contains("No such volume or snapshot")
|| msg.contains("Volume does not exist"))) {
return;
}
throw e;
}
return;
}
// rename as we delete so it doesn't conflict if the template or volume is ever recreated // first make sure we are disconnected
// pure keeps the volume(s) around in a Destroyed bucket for a period of time post delete removeVlunsAll(context, pod, dataObject.getExternalName());
String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
volume.setExternalName(fullName + "-" + timestamp); // Rename then destroy: FlashArray keeps destroyed volumes in a recycle
// bin (default 24h) from which they can be recovered. Renaming with a
// deletion timestamp gives operators a forensic trail when browsing the
// array - they can see when each destroyed copy was deleted on the
// CloudStack side. FlashArray rejects a single PATCH that combines
// {name, destroyed}, so the rename and the destroy must be issued as
// two separate requests each carrying only its own field.
// Use UTC so the rename suffix is stable regardless of the management
// server's local timezone or DST changes - operators correlating the
// CloudStack delete event with the array's audit log get a consistent
// wall-clock value.
String timestamp = DELETION_TIMESTAMP_FORMAT.format(java.time.Instant.now());
String renamedName = fullName + "-" + timestamp;
try { try {
PATCH("/volumes?names=" + fullName, volume, new TypeReference<FlashArrayList<FlashArrayVolume>>() { FlashArrayVolume rename = new FlashArrayVolume();
rename.setExternalName(renamedName);
PATCH("/volumes?names=" + fullName, rename, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
}); });
// now delete it with new name FlashArrayVolume destroy = new FlashArrayVolume();
volume.setDestroyed(true); destroy.setDestroyed(true);
PATCH("/volumes?names=" + renamedName, destroy, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
PATCH("/volumes?names=" + fullName + "-" + timestamp, volume, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
}); });
} catch (CloudRuntimeException e) { } catch (CloudRuntimeException e) {
if (e.toString().contains("Volume does not exist")) { String msg = e.getMessage();
if (msg != null && msg.contains("Volume does not exist")) {
return; return;
} else { } else {
throw e; throw e;

View File

@ -170,7 +170,7 @@
<cs.libvirt-java.version>0.5.3</cs.libvirt-java.version> <cs.libvirt-java.version>0.5.3</cs.libvirt-java.version>
<cs.mail.version>1.5.0-b01</cs.mail.version> <cs.mail.version>1.5.0-b01</cs.mail.version>
<cs.mustache.version>0.9.14</cs.mustache.version> <cs.mustache.version>0.9.14</cs.mustache.version>
<cs.mysql.version>8.0.33</cs.mysql.version> <cs.mysql.version>8.4.0</cs.mysql.version>
<cs.neethi.version>2.0.4</cs.neethi.version> <cs.neethi.version>2.0.4</cs.neethi.version>
<cs.nitro.version>10.1</cs.nitro.version> <cs.nitro.version>10.1</cs.nitro.version>
<cs.opensaml.version>2.6.6</cs.opensaml.version> <cs.opensaml.version>2.6.6</cs.opensaml.version>

View File

@ -539,6 +539,9 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL); AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL);
AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN); AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN);
AssignIpAddressSearch.and("forSystemVms", AssignIpAddressSearch.entity().isForSystemVms(), Op.EQ); AssignIpAddressSearch.and("forSystemVms", AssignIpAddressSearch.entity().isForSystemVms(), Op.EQ);
AssignIpAddressSearch.and("id", AssignIpAddressSearch.entity().getId(), Op.NIN);
AssignIpAddressSearch.and("requestedAddress", AssignIpAddressSearch.entity().getAddress(), Op.EQ);
AssignIpAddressSearch.and("routerAddress", AssignIpAddressSearch.entity().getAddress(), Op.NEQ);
SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder(); SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder();
vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ); vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ);
@ -945,10 +948,23 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
if (podId != null) { if (podId != null) {
sc = AssignIpAddressFromPodVlanSearch.create(); sc = AssignIpAddressFromPodVlanSearch.create();
sc.setJoinParameters("podVlanMapSB", "podId", podId); sc.setJoinParameters("podVlanMapSB", "podId", podId);
errorMessage.append(" pod id=" + podId); errorMessage.append(" pod id=").append(podId);
} else { } else {
sc = AssignIpAddressSearch.create(); sc = AssignIpAddressSearch.create();
errorMessage.append(" zone id=" + dcId); errorMessage.append(" zone id=").append(dcId);
}
if (lockOneRow) {
logger.debug("Listing quarantined public IPs to ignore on search for public IP for system VM. The IPs ignored will be the ones that: were not associated to account [{}]; were not removed yet; and with quarantine end dates after [{}].", owner.getUuid(), new Date());
List<PublicIpQuarantineVO> quarantinedAddresses = publicIpQuarantineDao.listQuarantinedIpAddressesToUser(owner.getId(), new Date());
List<Long> quarantinedAddressesIDs = quarantinedAddresses.stream().map(PublicIpQuarantineVO::getPublicIpAddressId).collect(Collectors.toList());
logger.debug("Found addresses with the following IDs: [{}] that will be ignored when searching for available public IPs.", quarantinedAddressesIDs);
if (CollectionUtils.isNotEmpty(quarantinedAddressesIDs)) {
sc.setParameters("id", quarantinedAddressesIDs.toArray());
}
} }
sc.setParameters("dc", dcId); sc.setParameters("dc", dcId);
@ -956,11 +972,11 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
// for direct network take ip addresses only from the vlans belonging to the network // for direct network take ip addresses only from the vlans belonging to the network
if (vlanUse == VlanType.DirectAttached) { if (vlanUse == VlanType.DirectAttached) {
sc.setJoinParameters("vlan", "networkId", guestNetworkId); sc.setJoinParameters("vlan", "networkId", guestNetworkId);
errorMessage.append(", network id=" + guestNetworkId); errorMessage.append(", network id=").append(guestNetworkId);
} }
if (requestedGateway != null) { if (requestedGateway != null) {
sc.setJoinParameters("vlan", "vlanGateway", requestedGateway); sc.setJoinParameters("vlan", "vlanGateway", requestedGateway);
errorMessage.append(", requested gateway=" + requestedGateway); errorMessage.append(", requested gateway=").append(requestedGateway);
} }
sc.setJoinParameters("vlan", "type", vlanUse); sc.setJoinParameters("vlan", "type", vlanUse);
@ -970,38 +986,39 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
NetworkDetailVO routerIpDetail = _networkDetailsDao.findDetail(network.getId(), ApiConstants.ROUTER_IP); NetworkDetailVO routerIpDetail = _networkDetailsDao.findDetail(network.getId(), ApiConstants.ROUTER_IP);
routerIpAddress = routerIpDetail != null ? routerIpDetail.getValue() : null; routerIpAddress = routerIpDetail != null ? routerIpDetail.getValue() : null;
} }
if (requestedIp != null) { if (requestedIp != null) {
sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp); sc.setParameters("requestedAddress", requestedIp);
errorMessage.append(": requested ip " + requestedIp + " is not available"); errorMessage.append(": requested ip ").append(requestedIp).append(" is not available");
} else if (routerIpAddress != null) { } else if (routerIpAddress != null) {
sc.addAnd("address", Op.NEQ, routerIpAddress); sc.setParameters("routerAddress", routerIpAddress);
} }
boolean ascOrder = ! forSystemVms; boolean ascOrder = ! forSystemVms;
Filter filter = new Filter(IPAddressVO.class, "forSystemVms", ascOrder, 0l, 1l); Filter filter = new Filter(IPAddressVO.class, "forSystemVms", ascOrder, 0L, 1L);
filter.addOrderBy(IPAddressVO.class,"vlanId", true); filter.addOrderBy(IPAddressVO.class,"vlanId", true);
List<IPAddressVO> addrs = new ArrayList<>(); List<IPAddressVO> addresses = new ArrayList<>();
if (forSystemVms) { if (forSystemVms) {
// Get Public IPs for system vms in dedicated ranges // Get Public IPs for system vms in dedicated ranges
sc.setParameters("forSystemVms", true); sc.setParameters("forSystemVms", true);
if (lockOneRow) { if (lockOneRow) {
addrs = _ipAddressDao.lockRows(sc, filter, true); addresses = _ipAddressDao.lockRows(sc, filter, true);
} else { } else {
addrs = new ArrayList<>(_ipAddressDao.search(sc, null)); addresses = new ArrayList<>(_ipAddressDao.search(sc, null));
} }
} }
if ((!lockOneRow || (lockOneRow && CollectionUtils.isEmpty(addrs))) && if ((!lockOneRow || (lockOneRow && CollectionUtils.isEmpty(addresses))) &&
!(forSystemVms && SystemVmPublicIpReservationModeStrictness.value())) { !(forSystemVms && SystemVmPublicIpReservationModeStrictness.value())) {
sc.setParameters("forSystemVms", false); sc.setParameters("forSystemVms", false);
// If owner has dedicated Public IP ranges, fetch IP from the dedicated range // If owner has dedicated Public IP ranges, fetch IP from the dedicated range
// Otherwise fetch IP from the system pool // Otherwise fetch IP from the system pool
// Checking if network is null in the case of system VM's. At the time of allocation of IP address to systemVm, no network is present. // Checking if network is null in the case of system VM's. At the time of allocation of IP address to systemVm, no network is present.
if (network == null || !(network.getGuestType() == GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced)) { if (network == null || !(network.getGuestType() == GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced)) {
List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId()); List<AccountVlanMapVO> accountVlanMaps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId());
for (AccountVlanMapVO map : maps) { for (AccountVlanMapVO map : accountVlanMaps) {
if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId())) if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
dedicatedVlanDbIds.add(map.getVlanDbId()); dedicatedVlanDbIds.add(map.getVlanDbId());
} }
@ -1020,10 +1037,10 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
if (!dedicatedVlanDbIds.isEmpty()) { if (!dedicatedVlanDbIds.isEmpty()) {
fetchFromDedicatedRange = true; fetchFromDedicatedRange = true;
sc.setParameters("vlanId", dedicatedVlanDbIds.toArray()); sc.setParameters("vlanId", dedicatedVlanDbIds.toArray());
errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray())); errorMessage.append(", vlanId id=").append(Arrays.toString(dedicatedVlanDbIds.toArray()));
} else if (!nonDedicatedVlanDbIds.isEmpty()) { } else if (!nonDedicatedVlanDbIds.isEmpty()) {
sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); errorMessage.append(", vlanId id=").append(Arrays.toString(nonDedicatedVlanDbIds.toArray()));
} else { } else {
if (podId != null) { if (podId != null) {
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
@ -1037,13 +1054,13 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
} }
} }
if (lockOneRow) { if (lockOneRow) {
addrs = _ipAddressDao.lockRows(sc, filter, true); addresses = _ipAddressDao.lockRows(sc, filter, true);
} else { } else {
addrs = new ArrayList<>(_ipAddressDao.search(sc, null)); addresses = new ArrayList<>(_ipAddressDao.search(sc, null));
} }
// If all the dedicated IPs of the owner are in use fetch an IP from the system pool // If all the dedicated IPs of the owner are in use fetch an IP from the system pool
if ((!lockOneRow || (lockOneRow && addrs.size() == 0)) && fetchFromDedicatedRange && vlanUse == VlanType.VirtualNetwork) { if ((!lockOneRow || (lockOneRow && addresses.isEmpty())) && fetchFromDedicatedRange && vlanUse == VlanType.VirtualNetwork) {
// Verify if account is allowed to acquire IPs from the system // Verify if account is allowed to acquire IPs from the system
boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId()); boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId());
if (useSystemIps && !nonDedicatedVlanDbIds.isEmpty()) { if (useSystemIps && !nonDedicatedVlanDbIds.isEmpty()) {
@ -1051,15 +1068,15 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
if (lockOneRow) { if (lockOneRow) {
addrs = _ipAddressDao.lockRows(sc, filter, true); addresses = _ipAddressDao.lockRows(sc, filter, true);
} else { } else {
addrs.addAll(_ipAddressDao.search(sc, null)); addresses.addAll(_ipAddressDao.search(sc, null));
} }
} }
} }
} }
if (lockOneRow && addrs.size() == 0) { if (lockOneRow && addresses.isEmpty()) {
if (podId != null) { if (podId != null) {
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
// for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object. // for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object.
@ -1073,13 +1090,12 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
} }
if (lockOneRow) { if (lockOneRow) {
assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size(); IPAddressVO allocatableIp = addresses.get(0);
IpAddress ipAddress = addrs.get(0);
boolean ipCanBeAllocated = canPublicIpAddressBeAllocated(ipAddress, owner);
if (!ipCanBeAllocated) { boolean isPublicIpAllocatable = canPublicIpAddressBeAllocated(allocatableIp, owner);
throw new InsufficientAddressCapacityException(String.format("Failed to allocate public IP address [%s] as it is in quarantine.", ipAddress.getAddress()),
DataCenter.class, dcId); if (!isPublicIpAllocatable) {
throw new InsufficientAddressCapacityException(String.format("Failed to allocate public IP [%s] as it is in quarantine.", allocatableIp.getAddress()), DataCenter.class, dcId);
} }
} }
@ -1088,12 +1104,12 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
try { try {
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip); _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip);
} catch (ResourceAllocationException ex) { } catch (ResourceAllocationException ex) {
logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner); logger.warn("Failed to allocate resource of type {} for account {}", ex.getResourceType(), owner);
throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded."); throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded.");
} }
} }
return addrs; return addresses;
} }
@DB @DB
@ -2558,26 +2574,27 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
PublicIpQuarantineVO publicIpQuarantineVO = publicIpQuarantineDao.findByPublicIpAddressId(ip.getId()); PublicIpQuarantineVO publicIpQuarantineVO = publicIpQuarantineDao.findByPublicIpAddressId(ip.getId());
if (publicIpQuarantineVO == null) { if (publicIpQuarantineVO == null) {
logger.debug(String.format("Public IP address [%s] is not in quarantine; therefore, it is allowed to be allocated.", ip)); logger.debug("Public IP address [{}] is not in quarantine; therefore, it is allowed to be allocated.", ip);
return true; return true;
} }
if (!isPublicIpAddressStillInQuarantine(publicIpQuarantineVO, new Date())) { if (!isPublicIpAddressStillInQuarantine(publicIpQuarantineVO, new Date())) {
logger.debug(String.format("Public IP address [%s] is no longer in quarantine; therefore, it is allowed to be allocated.", ip)); logger.debug("Public IP address [{}] is no longer in quarantine; therefore, it is allowed to be allocated.", ip);
removePublicIpAddressFromQuarantine(publicIpQuarantineVO.getId(), "IP was removed from quarantine because it was no longer in quarantine.");
return true; return true;
} }
Account previousOwner = _accountMgr.getAccount(publicIpQuarantineVO.getPreviousOwnerId()); Account previousOwner = _accountMgr.getAccount(publicIpQuarantineVO.getPreviousOwnerId());
if (Objects.equals(previousOwner.getUuid(), newOwner.getUuid())) { if (Objects.equals(previousOwner.getUuid(), newOwner.getUuid())) {
logger.debug(String.format("Public IP address [%s] is in quarantine; however, the Public IP previous owner [%s] is the same as the new owner [%s]; therefore the IP" + logger.debug("Public IP address [{}] is in quarantine; however, the Public IP previous owner [{}] is the same as the new owner [{}]; therefore the IP" +
" can be allocated. The public IP address will be removed from quarantine.", ip, previousOwner, newOwner)); " can be allocated. The public IP address will be removed from quarantine.", ip, previousOwner, newOwner);
removePublicIpAddressFromQuarantine(publicIpQuarantineVO.getId(), "IP was removed from quarantine because it has been allocated by the previous owner"); removePublicIpAddressFromQuarantine(publicIpQuarantineVO.getId(), "IP was removed from quarantine because it has been allocated by the previous owner");
return true; return true;
} }
logger.error(String.format("Public IP address [%s] is in quarantine and the previous owner [%s] is different than the new owner [%s]; therefore, the IP cannot be " + logger.error("Public IP address [{}] is in quarantine and the previous owner [{}] is different than the new owner [{}]; therefore, the IP cannot be " +
"allocated.", ip, previousOwner, newOwner)); "allocated.", ip, previousOwner, newOwner);
return false; return false;
} }
@ -2628,7 +2645,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
publicIpQuarantineVO.setRemovalReason(removalReason); publicIpQuarantineVO.setRemovalReason(removalReason);
publicIpQuarantineVO.setRemoverAccountId(removerAccountId); publicIpQuarantineVO.setRemoverAccountId(removerAccountId);
logger.debug(String.format("Removing public IP Address [%s] from quarantine by updating the removed date to [%s].", ipAddress, removedDate)); logger.debug("Removing public IP Address [{}] from quarantine by updating the removed date to [{}].", ipAddress, removedDate);
publicIpQuarantineDao.persist(publicIpQuarantineVO); publicIpQuarantineDao.persist(publicIpQuarantineVO);
} }

View File

@ -1389,20 +1389,19 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
final String accountNameFinal = accountName; final String accountNameFinal = accountName;
final Long domainIdFinal = domainId; final Long domainIdFinal = domainId;
final String accountUUIDFinal = accountUUID; final String resolvedAccountUUID = accountUUID != null ? accountUUID : UUID.randomUUID().toString();
// Check role escalation before the transaction this is a read-only check
// that iterates all API commands and doesn't need a write transaction open.
AccountVO requestedAccount = new AccountVO(accountNameFinal, domainIdFinal, networkDomain, accountType, roleId, resolvedAccountUUID);
checkRoleEscalation(getCurrentCallingAccount(), requestedAccount);
Pair<Long, Account> pair = Transaction.execute(new TransactionCallback<>() { Pair<Long, Account> pair = Transaction.execute(new TransactionCallback<>() {
@Override @Override
public Pair<Long, Account> doInTransaction(TransactionStatus status) { public Pair<Long, Account> doInTransaction(TransactionStatus status) {
// create account AccountVO account = createAccount(accountNameFinal, accountType, roleId, domainIdFinal, networkDomain, details, resolvedAccountUUID);
String accountUUID = accountUUIDFinal;
if (accountUUID == null) {
accountUUID = UUID.randomUUID().toString();
}
AccountVO account = createAccount(accountNameFinal, accountType, roleId, domainIdFinal, networkDomain, details, accountUUID);
long accountId = account.getId(); long accountId = account.getId();
checkRoleEscalation(getCurrentCallingAccount(), account);
// create the first user for the account // create the first user for the account
UserVO user = createUser(accountId, userName, password, firstName, lastName, email, timezone, userUUID, source); UserVO user = createUser(accountId, userName, password, firstName, lastName, email, timezone, userUUID, source);

View File

@ -156,7 +156,6 @@ import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -377,6 +376,7 @@ import com.cloud.utils.DateUtil;
import com.cloud.utils.Journal; import com.cloud.utils.Journal;
import com.cloud.utils.NumbersUtil; import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.concurrency.NamedThreadFactory;
@ -890,10 +890,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
private boolean resetVMPasswordInternal(Long vmId, String password) throws ResourceUnavailableException, InsufficientCapacityException { private boolean resetVMPasswordInternal(Long vmId, String password) throws ResourceUnavailableException, InsufficientCapacityException {
Long userId = CallContext.current().getCallingUserId(); long userId = CallContext.current().getCallingUserId();
VMInstanceVO vmInstance = _vmDao.findById(vmId); VMInstanceVO vmInstance = _vmDao.findById(vmId);
if (password == null || password.equals("")) { if (StringUtils.isEmpty(password)) {
return false; return false;
} }
@ -1078,7 +1078,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKeys, String keypairnames) throws ResourceUnavailableException, InsufficientCapacityException { private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKeys, String keypairnames) throws ResourceUnavailableException, InsufficientCapacityException {
Long userId = CallContext.current().getCallingUserId(); long userId = CallContext.current().getCallingUserId();
VMInstanceVO vmInstance = _vmDao.findById(vmId); VMInstanceVO vmInstance = _vmDao.findById(vmId);
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vmInstance.getTemplateId()); VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vmInstance.getTemplateId());
@ -1250,7 +1250,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (vmInstance == null) { if (vmInstance == null) {
throw new InvalidParameterValueException("unable to find an Instance with id " + vmId); throw new InvalidParameterValueException("unable to find an Instance with id " + vmId);
} else if (!(vmInstance.getState().equals(State.Stopped))) { } else if (!(vmInstance.getState().equals(State.Stopped))) {
throw new InvalidParameterValueException("Unable to upgrade Instance " + vmInstance.toString() + " " + " in state " + vmInstance.getState() throw new InvalidParameterValueException("Unable to upgrade Instance " + vmInstance + " " + " in state " + vmInstance.getState()
+ "; make sure the Instance is stopped"); + "; make sure the Instance is stopped");
} }
@ -1743,7 +1743,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
oldNetworkOfferingId = oldDefaultNetwork.getNetworkOfferingId(); oldNetworkOfferingId = oldDefaultNetwork.getNetworkOfferingId();
} }
NicVO existingVO = _nicDao.findById(existing.id); NicVO existingVO = _nicDao.findById(existing.id);
Integer chosenID = nic.getDeviceId(); int chosenID = nic.getDeviceId();
Integer existingID = existing.getDeviceId(); Integer existingID = existing.getDeviceId();
Network newdefault = null; Network newdefault = null;
@ -2172,14 +2172,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// Check vm flag // Check vm flag
if (!vmInstance.isDynamicallyScalable()) { if (!vmInstance.isDynamicallyScalable()) {
throw new CloudRuntimeException(String.format("Unable to scale %s as it does not have tools to support dynamic scaling.", vmInstance.toString())); throw new CloudRuntimeException(String.format("Unable to scale %s as it does not have tools to support dynamic scaling.", vmInstance));
} }
// Check disable threshold for cluster is not crossed // Check disable threshold for cluster is not crossed
HostVO host = _hostDao.findById(vmInstance.getHostId()); HostVO host = _hostDao.findById(vmInstance.getHostId());
_hostDao.loadDetails(host); _hostDao.loadDetails(host);
if (_capacityMgr.checkIfClusterCrossesThreshold(host.getClusterId(), cpuDiff, memoryDiff)) { if (_capacityMgr.checkIfClusterCrossesThreshold(host.getClusterId(), cpuDiff, memoryDiff)) {
throw new CloudRuntimeException(String.format("Unable to scale %s due to insufficient resources.", vmInstance.toString())); throw new CloudRuntimeException(String.format("Unable to scale %s due to insufficient resources.", vmInstance));
} }
while (retry-- != 0) { // It's != so that it can match -1. while (retry-- != 0) { // It's != so that it can match -1.
@ -2227,7 +2227,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
success = true; success = true;
return success; return success;
} catch (InsufficientCapacityException | ResourceUnavailableException | ConcurrentOperationException e) { } catch (InsufficientCapacityException | ResourceUnavailableException | ConcurrentOperationException e) {
logger.error(String.format("Unable to scale %s due to [%s].", vmInstance.toString(), e.getMessage()), e); logger.error(String.format("Unable to scale %s due to [%s].", vmInstance, e.getMessage()), e);
} finally { } finally {
if (!success) { if (!success) {
// Decrement CPU and Memory count accordingly. // Decrement CPU and Memory count accordingly.
@ -4545,7 +4545,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
NetworkOffering ntwkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); NetworkOffering ntwkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId());
Long physicalNetworkId = _networkModel.findPhysicalNetworkId(zone.getId(), ntwkOffering.getTags(), ntwkOffering.getTrafficType()); long physicalNetworkId = _networkModel.findPhysicalNetworkId(zone.getId(), ntwkOffering.getTags(), ntwkOffering.getTrafficType());
String provider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.Connectivity); String provider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.Connectivity);
if (!_networkModel.isProviderEnabledInPhysicalNetwork(physicalNetworkId, provider)) { if (!_networkModel.isProviderEnabledInPhysicalNetwork(physicalNetworkId, provider)) {
@ -4763,7 +4763,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
if (customParameters.containsKey(VmDetailConstants.ROOT_DISK_SIZE)) { if (customParameters.containsKey(VmDetailConstants.ROOT_DISK_SIZE)) {
Long rootDiskSize = NumbersUtil.parseLong(customParameters.get(VmDetailConstants.ROOT_DISK_SIZE), -1); long rootDiskSize = NumbersUtil.parseLong(customParameters.get(VmDetailConstants.ROOT_DISK_SIZE), -1);
if (rootDiskSize <= 0) { if (rootDiskSize <= 0) {
throw new InvalidParameterValueException("Root disk size should be a positive number."); throw new InvalidParameterValueException("Root disk size should be a positive number.");
} }
@ -4882,7 +4882,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
final Map<String, Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, final Map<String, Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs, final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs,
List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException { List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
Long selectedGuestOsId = guestOsId != null ? guestOsId : template.getGuestOSId(); long selectedGuestOsId = guestOsId != null ? guestOsId : template.getGuestOSId();
UserVmVO vm = new UserVmVO(id, instanceName, displayName, template.getId(), hypervisorType, selectedGuestOsId, offering.isOfferHA(), UserVmVO vm = new UserVmVO(id, instanceName, displayName, template.getId(), hypervisorType, selectedGuestOsId, offering.isOfferHA(),
offering.getLimitCpuUse(), owner.getDomainId(), owner.getId(), userId, offering.getId(), userData, userDataId, userDataDetails, hostName); offering.getLimitCpuUse(), owner.getDomainId(), owner.getId(), userId, offering.getId(), userData, userDataId, userDataDetails, hostName);
vm.setUuid(uuidName); vm.setUuid(uuidName);
@ -5441,7 +5441,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (dc.getDns2() != null) { if (dc.getDns2() != null) {
buf.append(" dns2=").append(dc.getDns2()); buf.append(" dns2=").append(dc.getDns2());
} }
logger.info("cmdline details: "+ buf.toString()); logger.info("cmdline details: "+ buf);
} }
@Override @Override
@ -5701,7 +5701,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
public UserVm stopVirtualMachine(long vmId, boolean forced) throws ConcurrentOperationException { public UserVm stopVirtualMachine(long vmId, boolean forced) throws ConcurrentOperationException {
// Input validation // Input validation
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
Long userId = CallContext.current().getCallingUserId(); long userId = CallContext.current().getCallingUserId();
// if account is removed, return error // if account is removed, return error
if (caller != null && caller.getRemoved() != null) { if (caller != null && caller.getRemoved() != null) {
@ -6473,7 +6473,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
_accountMgr.checkAccess(caller, null, true, snapshot); _accountMgr.checkAccess(caller, null, true, snapshot);
VolumeInfo volumeOfSnapshot = getVolume(snapshot.getVolumeId(), templateId, true); VolumeInfo volumeOfSnapshot = getVolume(snapshot.getVolumeId(), templateId, true);
templateId = volumeOfSnapshot.getTemplateId(); if (volumeOfSnapshot != null) {
templateId = volumeOfSnapshot.getTemplateId();
} else if (templateId == null) {
throw new InvalidParameterValueException(
"Could not determine template from snapshot id=" + cmd.getSnapshotId() +
"; the source volume no longer exists. Please specify a templateId.");
}
} }
VirtualMachineTemplate template = null; VirtualMachineTemplate template = null;
@ -6755,7 +6761,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
private VolumeInfo getVolume(long id, Long templateId, boolean isSnapshot) { private VolumeInfo getVolume(long id, Long templateId, boolean isSnapshot) {
VolumeInfo volume = volFactory.getVolume(id); VolumeInfo volume = volFactory.getVolume(id);
if (volume != null) { if (volume != null) {
if (volume.getDataStore() == null || !ScopeType.ZONE.equals(volume.getDataStore().getScope().getScopeType())) { if (!isSnapshot
&& (volume.getDataStore() == null
|| !ScopeType.ZONE.equals(volume.getDataStore().getScope().getScopeType()))) {
throw new InvalidParameterValueException("Deployment of virtual machine is supported only for Zone-wide storage pools"); throw new InvalidParameterValueException("Deployment of virtual machine is supported only for Zone-wide storage pools");
} }
checkIfVolumeTemplateIsTheSameAsTheProvided(volume, templateId); checkIfVolumeTemplateIsTheSameAsTheProvided(volume, templateId);
@ -6971,7 +6979,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} else if (hypervisorType.equals(HypervisorType.VMware)) { } else if (hypervisorType.equals(HypervisorType.VMware)) {
persistExtraConfigVmware(decodedUrl, vm); persistExtraConfigVmware(decodedUrl, vm);
} else { } else {
String msg = String.format("This hypervisor %s is not supported for use with this feature", hypervisorType.toString()); String msg = String.format("This hypervisor %s is not supported for use with this feature", hypervisorType);
throw new CloudRuntimeException(msg); throw new CloudRuntimeException(msg);
} }
} }
@ -7317,7 +7325,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
vm.setLastHostId(null); // Last host does not have higher priority in vm migration vm.setLastHostId(null); // Last host does not have higher priority in vm migration
final ServiceOfferingVO offering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId()); final ServiceOfferingVO offering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offering, null, null); final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offering, null, null);
final Long srcHostId = srcHost.getId(); final long srcHostId = srcHost.getId();
final Host host = _hostDao.findById(srcHostId); final Host host = _hostDao.findById(srcHostId);
ExcludeList excludes = new ExcludeList(); ExcludeList excludes = new ExcludeList();
excludes.addHost(srcHostId); excludes.addHost(srcHostId);
@ -7970,7 +7978,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Long domainId = cmd.getDomainId(); Long domainId = cmd.getDomainId();
Long projectId = cmd.getProjectId(); Long projectId = cmd.getProjectId();
Long oldAccountId = vm.getAccountId(); long oldAccountId = vm.getAccountId();
String newAccountName = cmd.getAccountName(); String newAccountName = cmd.getAccountName();
final Account oldAccount = _accountService.getActiveAccountById(oldAccountId); final Account oldAccount = _accountService.getActiveAccountById(oldAccountId);
final Account newAccount = _accountMgr.finalizeOwner(caller, newAccountName, domainId, projectId); final Account newAccount = _accountMgr.finalizeOwner(caller, newAccountName, domainId, projectId);
@ -8599,7 +8607,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
protected void addDefaultSecurityGroupToSecurityGroupIdList(Account newAccount, List<Long> securityGroupIdList) { protected void addDefaultSecurityGroupToSecurityGroupIdList(Account newAccount, List<Long> securityGroupIdList) {
logger.debug("Adding default security group to security group list if not already in it."); logger.debug("Adding default security group to security group list if not already in it.");
Long newAccountId = newAccount.getId(); long newAccountId = newAccount.getId();
SecurityGroup defaultGroup = _securityGroupMgr.getDefaultSecurityGroup(newAccountId); SecurityGroup defaultGroup = _securityGroupMgr.getDefaultSecurityGroup(newAccountId);
boolean defaultGroupPresent = false; boolean defaultGroupPresent = false;
@ -8746,7 +8754,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
logger.trace("Creating an applicable network to create the VM."); logger.trace("Creating an applicable network to create the VM.");
NetworkVO defaultNetwork; NetworkVO defaultNetwork;
Long zoneId = zone.getId(); long zoneId = zone.getId();
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
NetworkOfferingVO requiredOffering = getOfferingWithRequiredAvailabilityForNetworkCreation(); NetworkOfferingVO requiredOffering = getOfferingWithRequiredAvailabilityForNetworkCreation();
String requiredOfferingTags = requiredOffering.getTags(); String requiredOfferingTags = requiredOffering.getTags();
@ -9506,7 +9514,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
logger.debug("Found {} no. of volumes of type {} for vm with VM ID {}", listVolumes.size(), type, vm); logger.debug("Found {} no. of volumes of type {} for vm with VM ID {}", listVolumes.size(), type, vm);
for (VolumeVO volume : listVolumes) { for (VolumeVO volume : listVolumes) {
Long volumeId = volume.getId(); long volumeId = volume.getId();
logger.debug("Checking status of snapshots for Volume: {}", volume); logger.debug("Checking status of snapshots for Volume: {}", volume);
List<SnapshotVO> ongoingSnapshots = _snapshotDao.listByStatus(volumeId, Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp); List<SnapshotVO> ongoingSnapshots = _snapshotDao.listByStatus(volumeId, Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp);
int ongoingSnapshotsCount = ongoingSnapshots.size(); int ongoingSnapshotsCount = ongoingSnapshots.size();
@ -9525,12 +9533,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
for (VolumeVO volume : volumes) { for (VolumeVO volume : volumes) {
if (volume.getInstanceId() == null || vmId != volume.getInstanceId() || volume.getVolumeType() != Volume.Type.DATADISK) { if (volume.getInstanceId() == null || vmId != volume.getInstanceId() || volume.getVolumeType() != Volume.Type.DATADISK) {
sb.append(volume.toString() + "; "); sb.append(volume + "; ");
} }
} }
if (!StringUtils.isEmpty(sb.toString())) { if (!StringUtils.isEmpty(sb.toString())) {
throw new InvalidParameterValueException("The following supplied volumes are not DATADISK attached to the VM: " + sb.toString()); throw new InvalidParameterValueException("The following supplied volumes are not DATADISK attached to the VM: " + sb);
} }
} }
@ -9538,7 +9546,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
for (VolumeVO volume : volumes) { for (VolumeVO volume : volumes) {
if (!(volume.getVolumeType() == Volume.Type.ROOT || volume.getVolumeType() == Volume.Type.DATADISK)) { if (!(volume.getVolumeType() == Volume.Type.ROOT || volume.getVolumeType() == Volume.Type.DATADISK)) {
throw new InvalidParameterValueException("Please specify volume of type " + Volume.Type.DATADISK.toString() + " or " + Volume.Type.ROOT.toString()); throw new InvalidParameterValueException("Please specify volume of type " + Volume.Type.DATADISK + " or " + Volume.Type.ROOT);
} }
if (volume.isDeleteProtection()) { if (volume.isDeleteProtection()) {
throw new InvalidParameterValueException(String.format( throw new InvalidParameterValueException(String.format(
@ -9632,7 +9640,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
final String uuidName = _uuidMgr.generateUuid(UserVm.class, null); final String uuidName = _uuidMgr.generateUuid(UserVm.class, null);
final Host lastHost = powerState != VirtualMachine.PowerState.PowerOn ? host : null; final Host lastHost = powerState != VirtualMachine.PowerState.PowerOn ? host : null;
final Boolean dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(null, serviceOffering, template, zone.getId()); final boolean dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(null, serviceOffering, template, zone.getId());
return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner, return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner,
null, null, userData, null, null, isDisplayVm, keyboard, null, null, userData, null, null, isDisplayVm, keyboard,
accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), guestOsId, sshPublicKeys, networkNicMap, accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), guestOsId, sshPublicKeys, networkNicMap,
@ -9694,7 +9702,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
private void checkRootDiskSizeAgainstBackup(Long instanceVolumeSize,DiskOffering rootDiskOffering, Long backupVolumeSize) { private void checkRootDiskSizeAgainstBackup(Long instanceVolumeSize,DiskOffering rootDiskOffering, Long backupVolumeSize) {
Long instanceRootDiskSize = rootDiskOffering.isCustomized() ? instanceVolumeSize : rootDiskOffering.getDiskSize() / GiB_TO_BYTES; long instanceRootDiskSize = rootDiskOffering.isCustomized() ? instanceVolumeSize : rootDiskOffering.getDiskSize() / GiB_TO_BYTES;
if (instanceRootDiskSize < backupVolumeSize) { if (instanceRootDiskSize < backupVolumeSize) {
throw new InvalidParameterValueException( throw new InvalidParameterValueException(
String.format("Instance volume root disk size %d[GiB] cannot be less than the backed-up volume size %d[GiB].", String.format("Instance volume root disk size %d[GiB] cannot be less than the backed-up volume size %d[GiB].",
@ -9771,7 +9779,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Long size = cmd.getSize(); Long size = cmd.getSize();
Long diskOfferingId = cmd.getDiskOfferingId(); Long diskOfferingId = cmd.getDiskOfferingId();
Boolean isIso = template.getFormat().equals(ImageFormat.ISO); boolean isIso = template.getFormat().equals(ImageFormat.ISO);
if (diskOfferingId != null) { if (diskOfferingId != null) {
if (!isIso) { if (!isIso) {
throw new InvalidParameterValueException(ApiConstants.DISK_OFFERING_ID + " parameter is supported for creating instance from backup only for ISO. For creating VMs with templates, please use the parameter " + ApiConstants.DATADISKS_DETAILS); throw new InvalidParameterValueException(ApiConstants.DISK_OFFERING_ID + " parameter is supported for creating instance from backup only for ISO. For creating VMs with templates, please use the parameter " + ApiConstants.DATADISKS_DETAILS);

View File

@ -356,6 +356,7 @@ public class IpAddressManagerTest {
Mockito.when(ipAddressMock.getId()).thenReturn(dummyID); Mockito.when(ipAddressMock.getId()).thenReturn(dummyID);
Mockito.when(publicIpQuarantineDaoMock.findByPublicIpAddressId(Mockito.anyLong())).thenReturn(publicIpQuarantineVOMock); Mockito.when(publicIpQuarantineDaoMock.findByPublicIpAddressId(Mockito.anyLong())).thenReturn(publicIpQuarantineVOMock);
Mockito.doReturn(false).when(ipAddressManager).isPublicIpAddressStillInQuarantine(Mockito.any(PublicIpQuarantineVO.class), Mockito.any(Date.class)); Mockito.doReturn(false).when(ipAddressManager).isPublicIpAddressStillInQuarantine(Mockito.any(PublicIpQuarantineVO.class), Mockito.any(Date.class));
Mockito.doNothing().when(ipAddressManager).removePublicIpAddressFromQuarantine(Mockito.anyLong(), Mockito.anyString());
boolean result = ipAddressManager.canPublicIpAddressBeAllocated(ipAddressMock, newOwnerMock); boolean result = ipAddressManager.canPublicIpAddressBeAllocated(ipAddressMock, newOwnerMock);

File diff suppressed because it is too large Load Diff

View File

@ -104,9 +104,10 @@ CP=./
CP=${CP}$PATHSEP$CATALINA_HOME/conf CP=${CP}$PATHSEP$CATALINA_HOME/conf
# Add mysql jar from mysql-connector-java package to CP # Add mysql jar from mysql-connector-j package to CP
# for Jenkins # for Jenkins
CP=${CP}${PATHSEP}/usr/share/java/mysql-connector-java.jar MYSQL_CONNECTOR_VERSION = '8.4.0'
CP=${CP}${PATHSEP}/usr/share/java/mysql-connector-j-${MYSQL_CONNECTOR_VERSION}.jar
for file in $CATALINA_HOME/webapps/client/WEB-INF/lib/*.jar for file in $CATALINA_HOME/webapps/client/WEB-INF/lib/*.jar
do do

View File

@ -232,7 +232,7 @@ class CsNetfilters(object):
if hook == "input" or hook == "output": if hook == "input" or hook == "output":
CsHelper.execute("nft add rule %s %s %s icmpv6 type { echo-request, echo-reply, \ CsHelper.execute("nft add rule %s %s %s icmpv6 type { echo-request, echo-reply, \
nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept" % (address_family, table, chain)) nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept" % (address_family, table, chain))
elif hook == "forward": if hook == "input" or hook == "forward":
CsHelper.execute("nft add rule %s %s %s ct state established,related accept" % (address_family, table, chain)) CsHelper.execute("nft add rule %s %s %s ct state established,related accept" % (address_family, table, chain))
def add_ip4_chain(self, address_family, table, chain, hook, action): def add_ip4_chain(self, address_family, table, chain, hook, action):

View File

@ -85,7 +85,7 @@ class TestQuarantineIPs(cloudstackTestCase):
self.services["root_admin"]["roletype"]) self.services["root_admin"]["roletype"])
""" """
Set public.ip.address.quarantine.duration to 60 minutes Set public.ip.address.quarantine.duration to 1 minute
""" """
update_configuration_cmd = updateConfiguration.updateConfigurationCmd() update_configuration_cmd = updateConfiguration.updateConfigurationCmd()
update_configuration_cmd.name = "public.ip.address.quarantine.duration" update_configuration_cmd.name = "public.ip.address.quarantine.duration"
@ -168,8 +168,7 @@ class TestQuarantineIPs(cloudstackTestCase):
zoneid=self.zone.id, zoneid=self.zone.id,
vpcid=root_vpc.id, vpcid=root_vpc.id,
ipaddress=ip_address) ipaddress=ip_address)
self.assertIn(f"Failed to allocate public IP address [{ip_address}] as it is in quarantine.", self.assertIn("errorCode: 533", exception.exception.errorMsg)
exception.exception.errorMsg)
# Owner should be able to allocate its IP in quarantine # Owner should be able to allocate its IP in quarantine
public_ip = PublicIPAddress.create(self.domain_admin_apiclient, public_ip = PublicIPAddress.create(self.domain_admin_apiclient,
@ -267,8 +266,7 @@ class TestQuarantineIPs(cloudstackTestCase):
zoneid=self.zone.id, zoneid=self.zone.id,
networkid=root_network.id, networkid=root_network.id,
ipaddress=ip_address) ipaddress=ip_address)
self.assertIn(f"Failed to allocate public IP address [{ip_address}] as it is in quarantine.", self.assertIn("errorCode: 533", exception.exception.errorMsg)
exception.exception.errorMsg)
# Owner should be able to allocate its IP in quarantine # Owner should be able to allocate its IP in quarantine
public_ip = PublicIPAddress.create(self.domain_admin_apiclient, public_ip = PublicIPAddress.create(self.domain_admin_apiclient,

View File

@ -58,7 +58,7 @@ RUN mvn -Pdeveloper -Dsimulator -DskipTests clean install
RUN find /var/lib/mysql -type f -exec touch {} \; && \ RUN find /var/lib/mysql -type f -exec touch {} \; && \
(/usr/bin/mysqld_safe &) && \ (/usr/bin/mysqld_safe &) && \
sleep 5; \ sleep 5; \
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password by ''" --connect-expired-password; \ mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password by ''" --connect-expired-password; \
mvn -Pdeveloper -pl developer -Ddeploydb; \ mvn -Pdeveloper -pl developer -Ddeploydb; \
mvn -Pdeveloper -pl developer -Ddeploydb-simulator; \ mvn -Pdeveloper -pl developer -Ddeploydb-simulator; \
MARVIN_FILE=`find /root/tools/marvin/dist/ -name "Marvin*.tar.gz"`; \ MARVIN_FILE=`find /root/tools/marvin/dist/ -name "Marvin*.tar.gz"`; \

View File

@ -46,7 +46,7 @@ setup(name="Marvin",
"marvin.sandbox.basic"], "marvin.sandbox.basic"],
license="LICENSE.txt", license="LICENSE.txt",
install_requires=[ install_requires=[
"mysql-connector-python <= 8.0.30", "mysql-connector-python <= 8.4.0",
"requests >= 2.2.1", "requests >= 2.2.1",
"paramiko >= 1.13.0", "paramiko >= 1.13.0",
"nose >= 1.3.3", "nose >= 1.3.3",

View File

@ -3077,6 +3077,7 @@
"message.action.unmanage.volume": "Please confirm that you want to unmanage the Volume.", "message.action.unmanage.volume": "Please confirm that you want to unmanage the Volume.",
"message.action.unmanage.volumes": "Please confirm that you want to unmanage the Volumes.", "message.action.unmanage.volumes": "Please confirm that you want to unmanage the Volumes.",
"message.action.vmsnapshot.delete": "Please confirm that you want to delete this Instance Snapshot. <br>Please notice that the Instance will be paused before the Snapshot deletion, and resumed after deletion, if it runs on KVM.", "message.action.vmsnapshot.delete": "Please confirm that you want to delete this Instance Snapshot. <br>Please notice that the Instance will be paused before the Snapshot deletion, and resumed after deletion, if it runs on KVM.",
"message.action.vmsnapshot.disk-only.delete": "Please confirm that you want to delete this Instance Snapshot.",
"message.activate.project": "Are you sure you want to activate this project?", "message.activate.project": "Are you sure you want to activate this project?",
"message.add.custom.action.parameters": "Parameters to be made available while running the custom action.", "message.add.custom.action.parameters": "Parameters to be made available while running the custom action.",
"message.add.egress.rule.failed": "Adding new egress rule failed.", "message.add.egress.rule.failed": "Adding new egress rule failed.",
@ -4167,6 +4168,7 @@
"message.warn.importing.instance.without.nic": "WARNING: This Instance is being imported without NICs and many Network resources will not be available. Consider creating a NIC via vCenter before importing or as soon as the Instance is imported. For KVM host, allocate a NIC to Instance after import.", "message.warn.importing.instance.without.nic": "WARNING: This Instance is being imported without NICs and many Network resources will not be available. Consider creating a NIC via vCenter before importing or as soon as the Instance is imported. For KVM host, allocate a NIC to Instance after import.",
"message.warn.select.template": "Please select a Template for Registration.", "message.warn.select.template": "Please select a Template for Registration.",
"message.warn.zone.mtu.update": "Please note that this limit won't affect pre-existing Network's MTU settings", "message.warn.zone.mtu.update": "Please note that this limit won't affect pre-existing Network's MTU settings",
"message.warn.vpc.offerings": "VPC offerings will only be shown if the selected account has at least one VPC.",
"message.webhook.deliveries.time.filter": "Webhook deliveries list can be filtered based on date-time. Select 'Custom' for specifying start and end date range.", "message.webhook.deliveries.time.filter": "Webhook deliveries list can be filtered based on date-time. Select 'Custom' for specifying start and end date range.",
"message.webhook.filter.add": "Webhook deliveries can be controlled using filters (currently by Event type). Please select the parameters to add to the applied filters list.", "message.webhook.filter.add": "Webhook deliveries can be controlled using filters (currently by Event type). Please select the parameters to add to the applied filters list.",
"message.zone.creation.complete": "Zone creation complete.", "message.zone.creation.complete": "Zone creation complete.",

View File

@ -2765,9 +2765,9 @@
"message.action.unmanage.instance": "Por favor, confirme que voc\u00ea deseja parar de gerenciar a inst\u00e2ncia.", "message.action.unmanage.instance": "Por favor, confirme que voc\u00ea deseja parar de gerenciar a inst\u00e2ncia.",
"message.action.unmanage.instances": "Por favor, confirme que voc\u00ea deseja parar de gerenciar as inst\u00e2ncias.", "message.action.unmanage.instances": "Por favor, confirme que voc\u00ea deseja parar de gerenciar as inst\u00e2ncias.",
"message.action.unmanage.virtualmachine": "Por favor, confirme que voc\u00ea deseja parar de gerenciar a VM.", "message.action.unmanage.virtualmachine": "Por favor, confirme que voc\u00ea deseja parar de gerenciar a VM.",
"message.action.vmsnapshot.delete": "Por favor, confirme que voc\u00ea deseja excluir esta snapshot de VM.",
"message.action.unmanage.volume": "Por favor, confirme que voc\u00ea deseja parar de gerenciar o Volume.", "message.action.unmanage.volume": "Por favor, confirme que voc\u00ea deseja parar de gerenciar o Volume.",
"message.action.unmanage.volumes": "Por favor, confirme que voc\u00ea deseja parar de gerenciar os Volumes.", "message.action.unmanage.volumes": "Por favor, confirme que voc\u00ea deseja parar de gerenciar os Volumes.",
"message.action.vmsnapshot.delete": "Por favor, confirme que voc\u00ea deseja excluir esta snapshot de VM. <br>Saiba que caso a instância execute em um hypervisor KVM, ela será pausada antes da deleç\u00e3o, e continuada após a deleç\u00e3o.",
"message.action.vmsnapshot.disk-only.delete": "Por favor, confirme que voc\u00ea deseja excluir esta snapshot de VM.", "message.action.vmsnapshot.disk-only.delete": "Por favor, confirme que voc\u00ea deseja excluir esta snapshot de VM.",
"message.activate.project": "Voc\u00ea tem certeza que deseja ativar este projeto?", "message.activate.project": "Voc\u00ea tem certeza que deseja ativar este projeto?",
"message.add.egress.rule.failed": "Falha ao adicionar uma nova regra de sa\u00edda", "message.add.egress.rule.failed": "Falha ao adicionar uma nova regra de sa\u00edda",

View File

@ -536,7 +536,12 @@ export default {
api: 'deleteVMSnapshot', api: 'deleteVMSnapshot',
icon: 'delete-outlined', icon: 'delete-outlined',
label: 'label.action.vmsnapshot.delete', label: 'label.action.vmsnapshot.delete',
message: 'message.action.vmsnapshot.delete', message: (record) => {
if (record.hypervisor !== 'KVM' || record.type === 'Disk') {
return 'message.action.vmsnapshot.disk-only.delete'
}
return 'message.action.vmsnapshot.delete'
},
dataView: true, dataView: true,
show: (record) => { return ['Ready', 'Expunging', 'Error'].includes(record.state) }, show: (record) => { return ['Ready', 'Expunging', 'Error'].includes(record.state) },
args: ['vmsnapshotid'], args: ['vmsnapshotid'],

View File

@ -214,7 +214,7 @@
:spinning="actionLoading" :spinning="actionLoading"
v-ctrl-enter="handleSubmit" v-ctrl-enter="handleSubmit"
> >
<span v-if="currentAction.message"> <span v-if="currentAction.messageString">
<div v-if="selectedRowKeys.length > 0"> <div v-if="selectedRowKeys.length > 0">
<a-alert <a-alert
v-if="['delete-outlined', 'DeleteOutlined', 'poweroff-outlined', 'PoweroffOutlined'].includes(currentAction.icon)" v-if="['delete-outlined', 'DeleteOutlined', 'poweroff-outlined', 'PoweroffOutlined'].includes(currentAction.icon)"
@ -226,7 +226,7 @@
style="padding-left: 5px" style="padding-left: 5px"
v-html="`<b>${selectedRowKeys.length} ` + $t('label.items.selected') + `. </b>`" v-html="`<b>${selectedRowKeys.length} ` + $t('label.items.selected') + `. </b>`"
/> />
<span v-html="currentAction.message" /> <span v-html="currentAction.messageString" />
</template> </template>
</a-alert> </a-alert>
<a-alert <a-alert
@ -238,14 +238,14 @@
v-if="selectedRowKeys.length > 0" v-if="selectedRowKeys.length > 0"
v-html="`<b>${selectedRowKeys.length} ` + $t('label.items.selected') + `. </b>`" v-html="`<b>${selectedRowKeys.length} ` + $t('label.items.selected') + `. </b>`"
/> />
<span v-html="currentAction.message" /> <span v-html="currentAction.messageString" />
</template> </template>
</a-alert> </a-alert>
</div> </div>
<div v-else> <div v-else>
<a-alert type="warning"> <a-alert type="warning">
<template #message> <template #message>
<span v-html="currentAction.message" /> <span v-html="currentAction.messageString" />
</template> </template>
</a-alert> </a-alert>
</div> </div>
@ -1384,9 +1384,11 @@ export default {
this.currentAction.paramFilters = [] this.currentAction.paramFilters = []
if ('message' in action) { if ('message' in action) {
if (typeof action.message === 'function') { if (typeof action.message === 'function') {
action.message = action.message(action.resource) action.messageString = action.message(action.resource)
} else {
action.messageString = action.message
} }
action.message = Array.isArray(action.message) ? this.$t(...action.message) : this.$t(action.message) action.messageString = Array.isArray(action.messageString) ? this.$t(...action.messageString) : this.$t(action.messageString)
} }
this.getArgs(action, isGroupAction, paramFields) this.getArgs(action, isGroupAction, paramFields)
this.getFilters(action, isGroupAction, paramFields) this.getFilters(action, isGroupAction, paramFields)

View File

@ -96,6 +96,11 @@
{{ opt.displaytext || opt.name || opt.description }} {{ opt.displaytext || opt.name || opt.description }}
</a-select-option> </a-select-option>
</a-select> </a-select>
<a-alert type="warning" v-if="!this.hasVPC">
<template #message>
<span v-html="$t('message.warn.vpc.offerings')"/>
</template>
</a-alert>
</a-form-item> </a-form-item>
<a-form-item ref="asnumber" name="asnumber" v-if="isASNumberRequired()"> <a-form-item ref="asnumber" name="asnumber" v-if="isASNumberRequired()">
<template #label> <template #label>
@ -378,7 +383,8 @@ export default {
setMTU: false, setMTU: false,
asNumberLoading: false, asNumberLoading: false,
selectedAsNumber: 0, selectedAsNumber: 0,
asNumbersZone: [] asNumbersZone: [],
hasVPC: true
} }
}, },
watch: { watch: {
@ -526,13 +532,17 @@ export default {
if (this.vpc !== null) { // from VPC section if (this.vpc !== null) { // from VPC section
this.fetchNetworkOfferingData(true) this.fetchNetworkOfferingData(true)
} else { // from guest network section } else { // from guest network section
var params = {} const params = {
account: this.owner.account,
projectid: this.owner.projectid,
domainid: this.owner.domainid
}
this.networkOfferingLoading = true this.networkOfferingLoading = true
if ('listVPCs' in this.$store.getters.apis) { if ('listVPCs' in this.$store.getters.apis) {
getAPI('listVPCs', params).then(json => { getAPI('listVPCs', params).then(json => {
const listVPCs = json.listvpcsresponse.vpc const listVPCs = json.listvpcsresponse.vpc
var vpcAvailable = this.arrayHasItems(listVPCs) this.hasVPC = this.arrayHasItems(listVPCs)
if (vpcAvailable === false) { if (!this.hasVPC) {
this.fetchNetworkOfferingData(false) this.fetchNetworkOfferingData(false)
} else { } else {
this.fetchNetworkOfferingData() this.fetchNetworkOfferingData()
@ -545,7 +555,7 @@ export default {
}, },
fetchNetworkOfferingData (forVpc) { fetchNetworkOfferingData (forVpc) {
this.networkOfferingLoading = true this.networkOfferingLoading = true
var params = { const params = {
zoneid: this.selectedZone.id, zoneid: this.selectedZone.id,
guestiptype: 'Isolated', guestiptype: 'Isolated',
state: 'Enabled' state: 'Enabled'
@ -588,7 +598,7 @@ export default {
}, },
fetchVpcData () { fetchVpcData () {
this.vpcLoading = true this.vpcLoading = true
var params = { const params = {
listAll: true, listAll: true,
details: 'min' details: 'min'
} }

View File

@ -289,7 +289,7 @@ public class UsageSanityChecker {
} }
/** /**
* usage something like: /usr/bin/java -Xmx2G -cp /usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage:/usr/share/java/mysql-connector-java.jar:/usr/share/cloudstack-common com.cloud.usage.UsageSanityChecker * usage something like: /usr/bin/java -Xmx2G -cp /usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage:/usr/share/cloudstack-common com.cloud.usage.UsageSanityChecker
* @param args none * @param args none
*/ */
public static void main(String[] args) { public static void main(String[] args) {