From b0e780a35eb226c07f0006f4c051a7fd46c8e430 Mon Sep 17 00:00:00 2001 From: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com> Date: Tue, 9 Aug 2022 01:33:03 -0300 Subject: [PATCH 1/4] Enable system VM volume migration for KVM (#6341) Release 4.16.0.0 introduced a feature for migrating system VM volumes (#4385). However, it was enabled only for VMWare. This PR intends to enable the feature for KVM too. Co-authored-by: GutoVeronezi --- .../META-INF/db/schema-41700to41710.sql | 107 +++++++++++++++++- .../main/java/com/cloud/api/ApiDBUtils.java | 13 +-- .../java/com/cloud/api/ApiResponseHelper.java | 7 +- .../query/dao/DomainRouterJoinDaoImpl.java | 2 +- .../java/com/cloud/vm/UserVmManagerImpl.java | 10 +- ui/src/config/section/infra/routers.js | 2 +- ui/src/config/section/infra/systemVms.js | 2 +- 7 files changed, 118 insertions(+), 25 deletions(-) diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41700to41710.sql b/engine/schema/src/main/resources/META-INF/db/schema-41700to41710.sql index d246a1b80cc..abbc99a53bc 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41700to41710.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41700to41710.sql @@ -20,4 +20,109 @@ --; UPDATE `cloud`.`configuration` SET `value` = 'false' WHERE `name` = 'network.disable.rpfilter' AND `value` != 'true'; -UPDATE `cloud`.`configuration` SET `value` = 'false' WHERE `name` = 'consoleproxy.disable.rpfilter' AND `value` != 'true'; \ No newline at end of file +UPDATE `cloud`.`configuration` SET `value` = 'false' WHERE `name` = 'consoleproxy.disable.rpfilter' AND `value` != 'true'; + +-- Retrieve the hypervisor_type from vm_instance +DROP VIEW IF EXISTS `cloud`.`domain_router_view`; +CREATE VIEW `cloud`.`domain_router_view` AS + select + vm_instance.id id, + vm_instance.name name, + account.id account_id, + account.uuid account_uuid, + account.account_name account_name, + account.type account_type, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + projects.id project_id, + projects.uuid project_uuid, + projects.name project_name, + vm_instance.uuid uuid, + vm_instance.created created, + vm_instance.state state, + vm_instance.removed removed, + vm_instance.pod_id pod_id, + vm_instance.instance_name instance_name, + vm_instance.hypervisor_type, + host_pod_ref.uuid pod_uuid, + data_center.id data_center_id, + data_center.uuid data_center_uuid, + data_center.name data_center_name, + data_center.networktype data_center_type, + data_center.dns1 dns1, + data_center.dns2 dns2, + data_center.ip6_dns1 ip6_dns1, + data_center.ip6_dns2 ip6_dns2, + host.id host_id, + host.uuid host_uuid, + host.name host_name, + host.cluster_id cluster_id, + vm_template.id template_id, + vm_template.uuid template_uuid, + service_offering.id service_offering_id, + service_offering.uuid service_offering_uuid, + service_offering.name service_offering_name, + nics.id nic_id, + nics.uuid nic_uuid, + nics.network_id network_id, + nics.ip4_address ip_address, + nics.ip6_address ip6_address, + nics.ip6_gateway ip6_gateway, + nics.ip6_cidr ip6_cidr, + nics.default_nic is_default_nic, + nics.gateway gateway, + nics.netmask netmask, + nics.mac_address mac_address, + nics.broadcast_uri broadcast_uri, + nics.isolation_uri isolation_uri, + vpc.id vpc_id, + vpc.uuid vpc_uuid, + vpc.name vpc_name, + networks.uuid network_uuid, + networks.name network_name, + networks.network_domain network_domain, + networks.traffic_type traffic_type, + networks.guest_type guest_type, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id, + domain_router.template_version template_version, + domain_router.scripts_version scripts_version, + domain_router.is_redundant_router is_redundant_router, + domain_router.redundant_state redundant_state, + domain_router.stop_pending stop_pending, + domain_router.role role, + domain_router.software_version software_version + from + `cloud`.`domain_router` + inner join + `cloud`.`vm_instance` ON vm_instance.id = domain_router.id + inner join + `cloud`.`account` ON vm_instance.account_id = account.id + inner join + `cloud`.`domain` ON vm_instance.domain_id = domain.id + left join + `cloud`.`host_pod_ref` ON vm_instance.pod_id = host_pod_ref.id + left join + `cloud`.`projects` ON projects.project_account_id = account.id + left join + `cloud`.`data_center` ON vm_instance.data_center_id = data_center.id + left join + `cloud`.`host` ON vm_instance.host_id = host.id + left join + `cloud`.`vm_template` ON vm_instance.vm_template_id = vm_template.id + left join + `cloud`.`service_offering` ON vm_instance.service_offering_id = service_offering.id + left join + `cloud`.`nics` ON vm_instance.id = nics.instance_id and nics.removed is null + left join + `cloud`.`networks` ON nics.network_id = networks.id + left join + `cloud`.`vpc` ON domain_router.vpc_id = vpc.id and vpc.removed is null + left join + `cloud`.`async_job` ON async_job.instance_id = vm_instance.id + and async_job.instance_type = 'DomainRouter' + and async_job.job_status = 0; diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java b/server/src/main/java/com/cloud/api/ApiDBUtils.java index c874aa19b57..fe7f39b193d 100644 --- a/server/src/main/java/com/cloud/api/ApiDBUtils.java +++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java @@ -329,7 +329,6 @@ import org.apache.cloudstack.framework.jobs.dao.AsyncJobDao; import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.commons.lang3.StringUtils; import javax.annotation.PostConstruct; import javax.inject.Inject; @@ -1795,17 +1794,7 @@ public class ApiDBUtils { /////////////////////////////////////////////////////////////////////// public static DomainRouterResponse newDomainRouterResponse(DomainRouterJoinVO vr, Account caller) { - DomainRouterResponse response = s_domainRouterJoinDao.newDomainRouterResponse(vr, caller); - if (StringUtils.isBlank(response.getHypervisor())) { - VMInstanceVO vm = ApiDBUtils.findVMInstanceById(vr.getId()); - if (vm.getLastHostId() != null) { - HostVO lastHost = ApiDBUtils.findHostById(vm.getLastHostId()); - if (lastHost != null) { - response.setHypervisor(lastHost.getHypervisorType().toString()); - } - } - } - return response; + return s_domainRouterJoinDao.newDomainRouterResponse(vr, caller); } public static DomainRouterResponse fillRouterDetails(DomainRouterResponse vrData, DomainRouterJoinVO vr) { diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index fe0b9a5c0eb..4b1963a1ae0 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -1536,18 +1536,13 @@ public class ApiResponseHelper implements ResponseGenerator { vmResponse.setTemplateName(template.getName()); } vmResponse.setCreated(vm.getCreated()); + vmResponse.setHypervisor(vm.getHypervisorType().toString()); if (vm.getHostId() != null) { Host host = ApiDBUtils.findHostById(vm.getHostId()); if (host != null) { vmResponse.setHostId(host.getUuid()); vmResponse.setHostName(host.getName()); - vmResponse.setHypervisor(host.getHypervisorType().toString()); - } - } else if (vm.getLastHostId() != null) { - Host lastHost = ApiDBUtils.findHostById(vm.getLastHostId()); - if (lastHost != null) { - vmResponse.setHypervisor(lastHost.getHypervisorType().toString()); } } diff --git a/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java index 70a20c64741..235aa78df2f 100644 --- a/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java @@ -118,6 +118,7 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase HYPERVISORS_THAT_CAN_DO_STORAGE_MIGRATION_ON_NON_USER_VMS = Arrays.asList(HypervisorType.KVM, HypervisorType.VMware); + @Override public UserVmVO getVirtualMachine(long vmId) { return _vmDao.findById(vmId); @@ -6093,8 +6095,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir throw ex; } - if (vm.getType() != VirtualMachine.Type.User && !HypervisorType.VMware.equals(vm.getHypervisorType())) { - throw new InvalidParameterValueException("cannot do storage migration on non-user vm for hypervisor: " + vm.getHypervisorType().toString() + ", only supported for VMware"); + HypervisorType hypervisorType = vm.getHypervisorType(); + if (vm.getType() != VirtualMachine.Type.User && !HYPERVISORS_THAT_CAN_DO_STORAGE_MIGRATION_ON_NON_USER_VMS.contains(hypervisorType)) { + throw new InvalidParameterValueException(String.format("Unable to migrate storage of non-user VMs for hypervisor [%s]. Operation only supported for the following" + + " hypervisors: [%s].", hypervisorType, HYPERVISORS_THAT_CAN_DO_STORAGE_MIGRATION_ON_NON_USER_VMS)); } List vols = _volsDao.findByInstance(vm.getId()); @@ -6102,7 +6106,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir // OffLineVmwareMigration: data disks are not permitted, here! if (vols.size() > 1 && // OffLineVmwareMigration: allow multiple disks for vmware - !HypervisorType.VMware.equals(vm.getHypervisorType())) { + !HypervisorType.VMware.equals(hypervisorType)) { throw new InvalidParameterValueException("Data disks attached to the vm, can not migrate. Need to detach data disks first"); } } diff --git a/ui/src/config/section/infra/routers.js b/ui/src/config/section/infra/routers.js index e7e156a930f..5c747082eaf 100644 --- a/ui/src/config/section/infra/routers.js +++ b/ui/src/config/section/infra/routers.js @@ -193,7 +193,7 @@ export default { icon: 'drag-outlined', label: 'label.action.migrate.systemvm.to.ps', dataView: true, - show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) }, + show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware', 'KVM'].includes(record.hypervisor) }, component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateVMStorage'))), popup: true }, diff --git a/ui/src/config/section/infra/systemVms.js b/ui/src/config/section/infra/systemVms.js index 294481898fe..785f51f8191 100644 --- a/ui/src/config/section/infra/systemVms.js +++ b/ui/src/config/section/infra/systemVms.js @@ -109,7 +109,7 @@ export default { icon: 'drag-outlined', label: 'label.action.migrate.systemvm.to.ps', dataView: true, - show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) }, + show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware', 'KVM'].includes(record.hypervisor) }, component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateVMStorage'))), popup: true }, From 404b579b210d75b4802c00724ad0ae252afcd9e7 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 9 Aug 2022 12:44:27 +0530 Subject: [PATCH 2/4] test,xcp-ng: fix tests for VM PV driver issue (#6549) Few of the smoke tests fail on XCP-ng8 with PV drivers not installed for the VM. This PR makes changes to use get_suitable_test_template instead of get_template to use the appropriate template for the VM deployed during the test. After volume migration VM becomes unusable for attach/detach volume action. A new template could be used in future. For workaround right now, tests are ordered in a way that migrate volume test run at the end. Signed-off-by: Abhishek Kumar --- .../smoke/test_attach_multiple_volumes.py | 18 +-- .../smoke/test_network_permissions.py | 9 +- test/integration/smoke/test_volumes.py | 124 +++++++++--------- 3 files changed, 78 insertions(+), 73 deletions(-) diff --git a/test/integration/smoke/test_attach_multiple_volumes.py b/test/integration/smoke/test_attach_multiple_volumes.py index d9b4b0aaf50..939764dc010 100644 --- a/test/integration/smoke/test_attach_multiple_volumes.py +++ b/test/integration/smoke/test_attach_multiple_volumes.py @@ -28,9 +28,9 @@ from marvin.lib.base import (ServiceOffering, DiskOffering, ) from marvin.lib.common import (get_domain, - get_zone, - get_template, - find_storage_pool_type) + get_zone, + get_suitable_test_template, + find_storage_pool_type) from marvin.codes import ( PASS, FAILED, @@ -69,13 +69,13 @@ class TestMultipleVolumeAttach(cloudstackTestCase): ) cls._cleanup.append(cls.disk_offering) - template = get_template( - cls.apiclient, - cls.zone.id, - cls.services["ostype"] - ) + template = get_suitable_test_template( + cls.apiclient, + cls.zone.id, + cls.services["ostype"], + cls.hypervisor) if template == FAILED: - assert False, "get_template() failed to return template with description %s" % cls.services["ostype"] + assert False, "get_suitable_test_template() failed to return template with description %s" % cls.services["ostype"] cls.services["domainid"] = cls.domain.id cls.services["zoneid"] = cls.zone.id diff --git a/test/integration/smoke/test_network_permissions.py b/test/integration/smoke/test_network_permissions.py index 1b4a331f260..334a5618857 100644 --- a/test/integration/smoke/test_network_permissions.py +++ b/test/integration/smoke/test_network_permissions.py @@ -44,7 +44,7 @@ from marvin.lib.base import (Account, from marvin.lib.common import (get_domain, get_zone, - get_template) + get_suitable_test_template) NETWORK_FILTER_ACCOUNT = 'account' NETWORK_FILTER_DOMAIN = 'domain' @@ -66,7 +66,12 @@ class TestNetworkPermissions(cloudstackTestCase): zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests()) cls.zone = Zone(zone.__dict__) - cls.template = get_template(cls.apiclient, cls.zone.id) + cls.hypervisor = cls.testClient.getHypervisorInfo() + cls.template = get_suitable_test_template( + cls.apiclient, + cls.zone.id, + cls.services["ostype"], + cls.hypervisor) cls._cleanup = [] cls.logger = logging.getLogger("TestNetworkPermissions") diff --git a/test/integration/smoke/test_volumes.py b/test/integration/smoke/test_volumes.py index c9b93494dc9..02125ad9540 100644 --- a/test/integration/smoke/test_volumes.py +++ b/test/integration/smoke/test_volumes.py @@ -726,67 +726,6 @@ class TestVolumes(cloudstackTestCase): time.sleep(30) return - @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") - def test_12_resize_volume_with_only_size_parameter(self): - """Test resize a volume by providing only size parameter, disk offering id is not mandatory""" - # Verify the size is the new size is what we wanted it to be. - self.debug( - "Attaching volume (ID: %s) to VM (ID: %s)" % ( - self.volume.id, - self.virtual_machine.id - )) - - self.virtual_machine.attach_volume(self.apiClient, self.volume) - self.attached = True - hosts = Host.list(self.apiClient, id=self.virtual_machine.hostid) - self.assertTrue(isinstance(hosts, list)) - self.assertTrue(len(hosts) > 0) - self.debug("Found %s host" % hosts[0].hypervisor) - - if hosts[0].hypervisor == "XenServer": - self.virtual_machine.stop(self.apiClient) - elif hosts[0].hypervisor.lower() == "hyperv": - self.skipTest("Resize Volume is unsupported on Hyper-V") - - # resize the data disk - self.debug("Resize Volume ID: %s" % self.volume.id) - - cmd = resizeVolume.resizeVolumeCmd() - cmd.id = self.volume.id - cmd.size = 20 - - self.apiClient.resizeVolume(cmd) - - count = 0 - success = False - while count < 3: - list_volume_response = Volume.list( - self.apiClient, - id=self.volume.id, - type='DATADISK' - ) - for vol in list_volume_response: - if vol.id == self.volume.id and int(vol.size) == (20 * (1024 ** 3)) and vol.state == 'Ready': - success = True - if success: - break - else: - time.sleep(10) - count += 1 - - self.assertEqual( - success, - True, - "Check if the data volume resized appropriately" - ) - - # start the vm if it is on xenserver - - if hosts[0].hypervisor == "XenServer": - self.virtual_machine.start(self.apiClient) - time.sleep(30) - return - @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="false") def test_09_delete_detached_volume(self): """Delete a Volume unattached to an VM @@ -943,6 +882,67 @@ class TestVolumes(cloudstackTestCase): return + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") + def test_12_resize_volume_with_only_size_parameter(self): + """Test resize a volume by providing only size parameter, disk offering id is not mandatory""" + # Verify the size is the new size is what we wanted it to be. + self.debug( + "Attaching volume (ID: %s) to VM (ID: %s)" % ( + self.volume.id, + self.virtual_machine.id + )) + + self.virtual_machine.attach_volume(self.apiClient, self.volume) + self.attached = True + hosts = Host.list(self.apiClient, id=self.virtual_machine.hostid) + self.assertTrue(isinstance(hosts, list)) + self.assertTrue(len(hosts) > 0) + self.debug("Found %s host" % hosts[0].hypervisor) + + if hosts[0].hypervisor == "XenServer": + self.virtual_machine.stop(self.apiClient) + elif hosts[0].hypervisor.lower() == "hyperv": + self.skipTest("Resize Volume is unsupported on Hyper-V") + + # resize the data disk + self.debug("Resize Volume ID: %s" % self.volume.id) + + cmd = resizeVolume.resizeVolumeCmd() + cmd.id = self.volume.id + cmd.size = 20 + + self.apiClient.resizeVolume(cmd) + + count = 0 + success = False + while count < 3: + list_volume_response = Volume.list( + self.apiClient, + id=self.volume.id, + type='DATADISK' + ) + for vol in list_volume_response: + if vol.id == self.volume.id and int(vol.size) == (20 * (1024 ** 3)) and vol.state == 'Ready': + success = True + if success: + break + else: + time.sleep(10) + count += 1 + + self.assertEqual( + success, + True, + "Check if the data volume resized appropriately" + ) + + # start the vm if it is on xenserver + + if hosts[0].hypervisor == "XenServer": + self.virtual_machine.start(self.apiClient) + time.sleep(30) + return + def wait_for_attributes_and_return_root_vol(self): def checkVolumeResponse(): list_volume_response = Volume.list( @@ -963,7 +963,7 @@ class TestVolumes(cloudstackTestCase): return response @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") - def test_11_migrate_volume_and_change_offering(self): + def test_13_migrate_volume_and_change_offering(self): """ Validates the following 1. Creates a new Volume with a small disk offering From bca60761c502f1fa04c1d462128ef537c0e7ce73 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 9 Aug 2022 13:29:49 +0530 Subject: [PATCH 3/4] ui: use ssh keypair uuid for listing (#6616) Addresses #6569 Use uuid to list SSH keypair wherever uuid is available. Signed-off-by: Abhishek Kumar --- ui/src/components/view/ListView.vue | 4 ++-- ui/src/main.js | 2 ++ ui/src/utils/plugins.js | 9 +++++++++ ui/src/views/AutogenView.vue | 6 ++++-- ui/tests/common/index.js | 4 +++- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue index 292460541a6..981152fe216 100644 --- a/ui/src/components/view/ListView.vue +++ b/ui/src/components/view/ListView.vue @@ -98,7 +98,7 @@ - + {{ text }} @@ -110,7 +110,7 @@ {{ $t(text.toLowerCase()) }} - {{ text }} + {{ text }} {{ text }} diff --git a/ui/src/main.js b/ui/src/main.js index bd465bcfc0a..2f1d892fbd8 100644 --- a/ui/src/main.js +++ b/ui/src/main.js @@ -34,6 +34,7 @@ import { showIconPlugin, resourceTypePlugin, fileSizeUtilPlugin, + genericUtilPlugin, localesPlugin } from './utils/plugins' import { VueAxios } from './utils/request' @@ -49,6 +50,7 @@ vueApp.use(showIconPlugin) vueApp.use(resourceTypePlugin) vueApp.use(fileSizeUtilPlugin) vueApp.use(localesPlugin) +vueApp.use(genericUtilPlugin) vueApp.use(extensions) vueApp.use(directives) diff --git a/ui/src/utils/plugins.js b/ui/src/utils/plugins.js index 63a0e609c5d..6f7954ef2db 100644 --- a/ui/src/utils/plugins.js +++ b/ui/src/utils/plugins.js @@ -464,3 +464,12 @@ export const fileSizeUtilPlugin = { } } } + +export const genericUtilPlugin = { + install (app) { + app.config.globalProperties.$isValidUuid = function (uuid) { + const regexExp = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi + return regexExp.test(uuid) + } + } +} diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index ff75a6d2697..39967fe84c4 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -851,8 +851,10 @@ export default { if (this.$route.params && this.$route.params.id) { params.id = this.$route.params.id if (['listSSHKeyPairs'].includes(this.apiName)) { - delete params.id - params.name = this.$route.params.id + if (!this.$isValidUuid(params.id)) { + delete params.id + params.name = this.$route.params.id + } } if (['listPublicIpAddresses'].includes(this.apiName)) { params.allocatedonly = false diff --git a/ui/tests/common/index.js b/ui/tests/common/index.js index 545e9915f5a..a517fc2d08d 100644 --- a/ui/tests/common/index.js +++ b/ui/tests/common/index.js @@ -30,7 +30,8 @@ import { apiMetaUtilPlugin, showIconPlugin, resourceTypePlugin, - fileSizeUtilPlugin + fileSizeUtilPlugin, + genericUtilPlugin } from '@/utils/plugins' function createMockRouter (newRoutes = []) { @@ -86,6 +87,7 @@ function createFactory (component, options) { showIconPlugin, resourceTypePlugin, fileSizeUtilPlugin, + genericUtilPlugin, StoragePlugin ], mocks From 2d0a2e388d016789bf37853ea434bf0cde956ff8 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 9 Aug 2022 12:29:19 +0200 Subject: [PATCH 4/4] .github: add codecov coverage check It seems codecov can overcome the pull_request_target limitation/issue compared to sonarcloud coverage. We've some other Apache projects who use `codecov` now and this ticket to add support with infra: https://issues.apache.org/jira/browse/INFRA-23561 Signed-off-by: Rohit Yadav --- .github/workflows/codecov.yml | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/codecov.yml diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 00000000000..b21061fb681 --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,50 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: Coverage Check + +on: [pull_request, push] + +permissions: + contents: read + +jobs: + build: + name: codecov + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK11 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '11' + cache: 'maven' + + - name: Build CloudStack with Quality Checks + run: | + git clone https://github.com/shapeblue/cloudstack-nonoss.git nonoss + cd nonoss && bash -x install-non-oss.sh && cd .. + mvn -P quality -Dsimulator -Dnoredist clean install + + - uses: codecov/codecov-action@v3 + with: + files: ./client/target/site/jacoco-aggregate/jacoco.xml + fail_ci_if_error: true + verbose: true + name: codecov