diff --git a/src/components/view/ListView.vue b/src/components/view/ListView.vue index 7ff0b34c9..ce8121535 100644 --- a/src/components/view/ListView.vue +++ b/src/components/view/ListView.vue @@ -224,6 +224,11 @@ + + + {{ record.autoscalingenabled ? 'Enabled' : 'Disabled' }} + +
diff --git a/src/components/view/ResourceView.vue b/src/components/view/ResourceView.vue index 2147f0bc2..3bd335ea9 100644 --- a/src/components/view/ResourceView.vue +++ b/src/components/view/ResourceView.vue @@ -113,27 +113,8 @@ export default { this.activeTab = key }, showTab (tab) { - if ('networkServiceFilter' in tab) { - if (this.resource && this.resource.virtualmachineid && !this.resource.vpcid && tab.name !== 'firewall') { - return false - } - if (this.resource && this.resource.virtualmachineid && this.resource.vpcid) { - return false - } - // dont display any option for source NAT IP of VPC - if (this.resource && this.resource.vpcid && !this.resource.issourcenat && tab.name !== 'firewall') { - return true - } - // display LB and PF options for isolated networks if static nat is disabled - if (this.resource && !this.resource.vpcid) { - if (!this.resource.isstaticnat) { - return true - } else if (tab.name === 'firewall') { - return true - } - } - return this.networkService && this.networkService.service && - tab.networkServiceFilter(this.networkService.service) + if (this.networkService && this.networkService.service && tab.networkServiceFilter) { + return tab.networkServiceFilter(this.networkService.service) } else if ('show' in tab) { return tab.show(this.resource, this.$route, this.$store.getters.userInfo) } else { diff --git a/src/config/section/compute.js b/src/config/section/compute.js index d485772e2..04a428300 100644 --- a/src/config/section/compute.js +++ b/src/config/section/compute.js @@ -405,15 +405,18 @@ export default { icon: kubernetes, docHelp: 'plugins/cloudstack-kubernetes-service.html', permission: ['listKubernetesClusters'], - columns: () => { + columns: (store) => { var fields = ['name', 'state', 'size', 'cpunumber', 'memory'] - if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) { + if (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) { fields.push('account') } + if (store.apis.scaleKubernetesCluster.params.filter(x => x.name === 'autoscalingenabled').length > 0) { + fields.splice(2, 0, 'autoscalingenabled') + } fields.push('zonename') return fields }, - details: ['name', 'description', 'zonename', 'kubernetesversionname', 'size', 'masternodes', 'cpunumber', 'memory', 'keypair', 'associatednetworkname', 'account', 'domain', 'zonename'], + details: ['name', 'description', 'zonename', 'kubernetesversionname', 'autoscalingenabled', 'minsize', 'maxsize', 'size', 'masternodes', 'cpunumber', 'memory', 'keypair', 'associatednetworkname', 'account', 'domain', 'zonename'], tabs: [{ name: 'k8s', component: () => import('@/views/compute/KubernetesServiceTab.vue') diff --git a/src/config/section/image.js b/src/config/section/image.js index cba21248d..c560bedba 100644 --- a/src/config/section/image.js +++ b/src/config/section/image.js @@ -297,7 +297,7 @@ export default { docHelp: 'plugins/cloudstack-kubernetes-service.html#kubernetes-supported-versions', permission: ['listKubernetesSupportedVersions'], columns: ['name', 'state', 'semanticversion', 'isostate', 'mincpunumber', 'minmemory', 'zonename'], - details: ['name', 'semanticversion', 'zoneid', 'zonename', 'isoid', 'isoname', 'isostate', 'mincpunumber', 'minmemory', 'supportsha', 'state'], + details: ['name', 'semanticversion', 'supportsautoscaling', 'zoneid', 'zonename', 'isoid', 'isoname', 'isostate', 'mincpunumber', 'minmemory', 'supportsha', 'state'], actions: [ { api: 'addKubernetesSupportedVersion', @@ -319,6 +319,7 @@ export default { api: 'deleteKubernetesSupportedVersion', icon: 'delete', label: 'label.kubernetes.version.delete', + message: 'message.kubernetes.version.delete', dataView: true } ] diff --git a/src/locales/en.json b/src/locales/en.json index 096355312..c1221215e 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -24,8 +24,8 @@ "error.release.dedicate.pod": "Failed to release dedicated pod", "error.release.dedicate.zone": "Failed to release dedicated zone", "error.session.expired": "Your session has expired.", -"error.unable.to.reach.management.server": "Unable to reach Management Server", "error.unable.to.proceed": "Unable to proceed. Please contact your administrator", +"error.unable.to.reach.management.server": "Unable to reach Management Server", "error.unresolved.internet.name": "Your internet name cannot be resolved.", "firewall.close": "Firewall", "force.delete.domain.warning": "Warning: Choosing this option will cause the deletion of all child domains and all associated accounts and their resources.", @@ -82,10 +82,10 @@ "label.action.copy.iso.processing": "Copying ISO....", "label.action.copy.template": "Copy Template", "label.action.copy.template.processing": "Copying Template....", +"label.action.create.snapshot.from.vmsnapshot": "Create Snapshot from VM Snapshot", "label.action.create.template.from.vm": "Create Template from VM", "label.action.create.template.from.volume": "Create Template from Volume", "label.action.create.template.processing": "Creating Template....", -"label.action.create.snapshot.from.vmsnapshot": "Create Snapshot from VM Snapshot", "label.action.create.vm": "Create VM", "label.action.create.vm.processing": "Creating VM....", "label.action.create.volume": "Create Volume", @@ -113,6 +113,7 @@ "label.action.delete.network.processing": "Deleting Network....", "label.action.delete.nexusvswitch": "Delete Nexus 1000v", "label.action.delete.nic": "Remove NIC", +"label.action.delete.node": "Delete node", "label.action.delete.physical.network": "Delete physical network", "label.action.delete.pod": "Delete Pod", "label.action.delete.pod.processing": "Deleting Pod....", @@ -450,6 +451,7 @@ "label.author.name": "Author name", "label.autoscale": "AutoScale", "label.autoscale.configuration.wizard": "AutoScale Configuration Wizard", +"label.autoscalingenabled": "Autoscaling", "label.availability": "Availability", "label.availabilityzone": "Availability Zone", "label.available": "Available", @@ -542,6 +544,9 @@ "label.cisco.nexus1000v.password": "Nexus 1000v Password", "label.cisco.nexus1000v.username": "Nexus 1000v Username", "label.ciscovnmc.resource.details": "CiscoVNMC resource details", +"label.cks.cluster.autoscalingenabled": "Enable autoscaling on this cluster", +"label.cks.cluster.maxsize": "Maximum cluster size (Worker nodes)", +"label.cks.cluster.minsize": "Minimum cluster size (Worker nodes)", "label.cks.cluster.size": "Cluster size (Worker nodes)", "label.cleanup": "Clean up", "label.clear": "Clear", @@ -1289,6 +1294,7 @@ "label.maxproject": "Max. Projects", "label.maxpublicip": "Max. Public IPs", "label.maxsecondarystorage": "Max. Secondary Storage (GiB)", +"label.maxsize": "Maximum size", "label.maxsnapshot": "Max. Snapshots", "label.maxtemplate": "Max. Templates", "label.maxuservm": "Max. User VMs", @@ -1371,6 +1377,7 @@ "label.miniops": "Min IOPS", "label.minmaxiops": "Min IOPS / Max IOPS", "label.minmemory": "Min Memory (in MB)", +"label.minsize": "Minimum size", "label.minute.past.hour": "minute(s) past the hour", "label.minutes.past.hour": "minutes(s) past the hour", "label.monday": "Monday", @@ -1842,8 +1849,8 @@ "label.save.changes": "Save changes", "label.save.new.rule": "Save new Rule", "label.saving.processing": "Saving....", -"label.scale.vm": "Scale VM", "label.scale.up.policy": "SCALE UP POLICY", +"label.scale.vm": "Scale VM", "label.scaledown.policy": "ScaleDown Policy", "label.scaleup.policy": "ScaleUp Policy", "label.schedule": "Schedule", @@ -2040,6 +2047,7 @@ "label.summary": "Summary", "label.sunday": "Sunday", "label.supportedservices": "Supported Services", +"label.supportsautoscaling": "Supports Autoscaling", "label.supportsha": "Supports HA", "label.supportspublicaccess": "Supports Public Access", "label.supportsregionlevelvpc": "Supports Region Level VPC", @@ -2366,6 +2374,7 @@ "message.action.delete.iso.for.all.zones": "The ISO is used by all zones. Please confirm that you want to delete it from all zones.", "message.action.delete.network": "Please confirm that you want to delete this network.", "message.action.delete.nexusvswitch": "Please confirm that you want to delete this nexus 1000v", +"message.action.delete.node": "Please confirm that you want to delete this node.", "message.action.delete.physical.network": "Please confirm that you want to delete this physical network", "message.action.delete.pod": "Please confirm that you want to delete this pod.", "message.action.delete.primary.storage": "Please confirm that you want to delete this primary storage.", @@ -2415,6 +2424,7 @@ "message.action.revert.snapshot": "Please confirm that you want to revert the owning volume to this snapshot.", "message.action.router.health.checks": "Health checks result will be fetched from router.", "message.action.router.health.checks.disabled.warning": "Please enable router health checks.", +"message.action.scale.kubernetes.cluster.warning": "Please do not manually scale the cluster if cluster autoscaling is enabled", "message.action.secure.host": "This will restart the host agent and libvirtd process after applying new X509 certificates, please confirm?", "message.action.settings.warning.vm.running": "Please stop the virtual machine to access settings", "message.action.settings.warning.vm.started": "Virtual machine has been started. It needs to be stopped to access settings", @@ -2629,10 +2639,10 @@ "message.creating.secondary.storage": "Creating secondary storage", "message.creating.systemvm": "Creating system VMs (this may take a while)", "message.creating.zone": "Creating zone", -"message.datacenter.description": "Name of the datacenter on vCenter", -"message.datastore.description": "Name of the datastore on vCenter", "message.data.migration": "Data Migration", "message.data.migration.progress": "Data Migration between image stores", +"message.datacenter.description": "Name of the datacenter on vCenter", +"message.datastore.description": "Name of the datastore on vCenter", "message.dedicate.zone": "Dedicating zone", "message.dedicated.zone.released": "Zone dedication released", "message.dedicating.cluster": "Dedicating Cluster...", @@ -2660,6 +2670,7 @@ "message.delete.vpn.connection": "Please confirm that you want to delete VPN connection", "message.delete.vpn.customer.gateway": "Please confirm that you want to delete this VPN Customer Gateway", "message.delete.vpn.gateway": "Please confirm that you want to delete this VPN Gateway", +"message.deleting.node": "Deleting Node", "message.deleting.vm": "Deleting VM", "message.desc.add.new.lb.sticky.rule": "Add new LB sticky rule", "message.desc.advanced.zone": "For more sophisticated network topologies. This network model provides the most flexibility in defining guest networks and providing custom network offerings such as firewall, VPN, or load balancer support.", @@ -2897,6 +2908,7 @@ "message.kubernetes.cluster.start": "Please confirm that you want to start the cluster", "message.kubernetes.cluster.stop": "Please confirm that you want to stop the cluster", "message.kubernetes.cluster.upgrade": "Please select new kubernetes version", +"message.kubernetes.version.delete": "Please confirm that you want to delete this kubernetes version", "message.launch.vm.on.private.network": "Do you wish to launch your instance on your own private dedicated network?", "message.launch.zone": "Zone is ready to launch; please proceed to the next step.", "message.launch.zone.description": "Zone is ready to launch; please proceed to the next step.", @@ -2974,8 +2986,8 @@ "message.pod.dedication.released": "Pod dedication released", "message.portable.ip.delete.confirm": "Please confirm you want to delete Portable IP Range", "message.processing.complete": "Processing complete!", -"message.protocol.description": "For XenServer, choose NFS, iSCSI, or PreSetup. For KVM, choose NFS, SharedMountPoint, RDB, CLVM or Gluster. For vSphere, choose NFS, PreSetup (VMFS or iSCSI or FiberChannel or vSAN or vVols) or DatastoreCluster. For Hyper-V, choose SMB/CIFS. For LXC, choose NFS or SharedMountPoint. For OVM, choose NFS or ocfs2.", "message.project.invite.sent": "Invite sent to user; they will be added to the project once they accept the invitation", +"message.protocol.description": "For XenServer, choose NFS, iSCSI, or PreSetup. For KVM, choose NFS, SharedMountPoint, RDB, CLVM or Gluster. For vSphere, choose NFS, PreSetup (VMFS or iSCSI or FiberChannel or vSAN or vVols) or DatastoreCluster. For Hyper-V, choose SMB/CIFS. For LXC, choose NFS or SharedMountPoint. For OVM, choose NFS or ocfs2.", "message.public.traffic.in.advanced.zone": "Public traffic is generated when VMs in the cloud access the internet. Publicly-accessible IPs must be allocated for this purpose. End users can use the CloudStack UI to acquire these IPs to implement NAT between their guest network and their public network.

Provide at least one range of IP addresses for internet traffic.", "message.public.traffic.in.basic.zone": "Public traffic is generated when VMs in the cloud access the Internet or provide services to clients over the Internet. Publicly accessible IPs must be allocated for this purpose. When a instance is created, an IP from this set of Public IPs will be allocated to the instance in addition to the guest IP address. Static 1-1 NAT will be set up automatically between the public IP and the guest IP. End users can also use the CloudStack UI to acquire additional IPs to implement static NAT between their instances and the public IP.", "message.publicip.state.allocated": "The IP address is in used.", @@ -3101,6 +3113,7 @@ "message.success.delete": "Delete success", "message.success.delete.acl.rule": "Successfully removed ACL rule", "message.success.delete.backup.schedule": "Successfully deleted Configure VM backup schedule", +"message.success.delete.node": "Successfully Deleted Node", "message.success.delete.snapshot.policy": "Successfully deleted snapshot policy", "message.success.delete.static.route": "Successfully deleted static route", "message.success.delete.tag": "Successfully deleted tag", diff --git a/src/views/AutogenView.vue b/src/views/AutogenView.vue index 3f6bf5e12..4ada8a8e0 100644 --- a/src/views/AutogenView.vue +++ b/src/views/AutogenView.vue @@ -544,7 +544,7 @@ export default { if (this.$route.meta.columns) { const columns = this.$route.meta.columns if (columns && typeof columns === 'function') { - this.columnKeys = columns() + this.columnKeys = columns(this.$store.getters) } else { this.columnKeys = columns } diff --git a/src/views/compute/CreateKubernetesCluster.vue b/src/views/compute/CreateKubernetesCluster.vue index 9759a5d90..ac56b0432 100644 --- a/src/views/compute/CreateKubernetesCluster.vue +++ b/src/views/compute/CreateKubernetesCluster.vue @@ -131,10 +131,11 @@ @@ -107,6 +107,26 @@ + @@ -141,6 +161,7 @@ export default { Status }, mixins: [mixinDevice], + inject: ['parentFetchData'], props: { resource: { type: Object, @@ -201,6 +222,13 @@ export default { } }, mounted () { + if (this.$store.getters.apis.scaleKubernetesCluster.params.filter(x => x.name === 'nodeids').length > 0) { + this.vmColumns.push({ + title: this.$t('label.action'), + dataIndex: 'action', + scopedSlots: { customRender: 'action' } + }) + } this.handleFetchData() }, watch: { @@ -332,6 +360,35 @@ export default { elem.click() document.body.removeChild(elem) } + }, + deleteNode (node) { + const params = { + id: this.resource.id, + nodeids: node.id + } + api('scaleKubernetesCluster', params).then(json => { + const jobId = json.scalekubernetesclusterresponse.jobid + console.log(jobId) + this.$store.dispatch('AddAsyncJob', { + title: this.$t('label.action.delete.node'), + jobid: jobId, + description: node.name, + status: 'progress' + }) + this.$pollJob({ + jobId, + loadingMessage: `${this.$t('message.deleting.node')} ${node.name}`, + catchMessage: this.$t('error.fetching.async.job.result'), + successMessage: `${this.$t('message.success.delete.node')} ${node.name}`, + successMethod: () => { + this.parentFetchData() + } + }) + }).catch(error => { + this.$notifyError(error) + }).finally(() => { + this.parentFetchData() + }) } } } diff --git a/src/views/compute/ScaleKubernetesCluster.vue b/src/views/compute/ScaleKubernetesCluster.vue index 8ebc1fb29..46db09ae0 100644 --- a/src/views/compute/ScaleKubernetesCluster.vue +++ b/src/views/compute/ScaleKubernetesCluster.vue @@ -19,56 +19,113 @@
- +
- + - {{ $t('label.cks.cluster.size') }} - + {{ $t('label.cks.cluster.autoscalingenabled') }} + - - - - - {{ $t('label.serviceofferingid') }} - - - - - - - {{ opt.name || opt.description }} - - + + + + + {{ $t('label.cks.cluster.minsize') }} + + + + + + + + + {{ $t('label.cks.cluster.maxsize') }} + + + + + + + + + + + {{ $t('label.serviceofferingid') }} + + + + + + + {{ opt.name || opt.description }} + + + + + + {{ $t('label.cks.cluster.size') }} + + + + + + +
{{ this.$t('label.cancel') }} @@ -96,7 +153,11 @@ export default { serviceOfferingLoading: false, minCpu: 2, minMemory: 2048, - loading: false + loading: false, + originalSize: 1, + autoscalingenabled: null, + minsize: null, + maxsize: null } }, beforeCreate () { @@ -108,7 +169,14 @@ export default { }) }, created () { - this.originalSize = !this.isObjectEmpty(this.resource) ? this.resource.size : 1 + if (!this.isObjectEmpty(this.resource)) { + this.originalSize = this.resource.size + if (this.apiParams.autoscalingenabled) { + this.autoscalingenabled = this.resource.autoscalingenabled ? true : null + this.minsize = this.resource.minsize + this.maxsize = this.resource.maxsize + } + } }, mounted () { this.fetchData() @@ -179,12 +247,21 @@ export default { const params = { id: this.resource.id } + if (this.autoscalingenabled != null) { + params.autoscalingenabled = this.autoscalingenabled + } if (this.isValidValueForKey(values, 'size') && values.size > 0) { params.size = values.size } - if (this.isValidValueForKey(values, 'serviceofferingid') && this.arrayHasItems(this.serviceOfferings)) { + if (this.isValidValueForKey(values, 'serviceofferingid') && this.arrayHasItems(this.serviceOfferings) && this.autoscalingenabled == null) { params.serviceofferingid = this.serviceOfferings[values.serviceofferingid].id } + if (this.isValidValueForKey(values, 'minsize')) { + params.minsize = values.minsize + } + if (this.isValidValueForKey(values, 'maxsize')) { + params.maxsize = values.maxsize + } api('scaleKubernetesCluster', params).then(json => { const jobId = json.scalekubernetesclusterresponse.jobid this.$store.dispatch('AddAsyncJob', { diff --git a/src/views/network/PublicIpResource.vue b/src/views/network/PublicIpResource.vue index 84c62eb4c..0096c0aaf 100644 --- a/src/views/network/PublicIpResource.vue +++ b/src/views/network/PublicIpResource.vue @@ -63,6 +63,10 @@ export default { tabs: [{ name: 'details', component: () => import('@/components/view/DetailsTab.vue') + }], + defaultTabs: [{ + name: 'details', + component: () => import('@/components/view/DetailsTab.vue') }] } }, @@ -97,39 +101,68 @@ export default { } this.loading = true - this.portFWRuleCount = await this.fetchPortFWRule() + await this.filterTabs() + await this.fetchAction() + this.loading = false + }, + async filterTabs () { + // VPC IPs with source nat have only VPN + if (this.resource && this.resource.vpcid && this.resource.issourcenat) { + this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn')) + return + } + + // VPC IPs with vpnenabled have only VPN + if (this.resource && this.resource.vpcid && this.resource.vpnenabled) { + this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn')) + return + } + + // VPC IPs with static nat have nothing + if (this.resource && this.resource.vpcid && this.resource.isstaticnat) { + return + } + + if (this.resource && this.resource.vpcid) { + // VPC IPs don't have firewall + let tabs = this.$route.meta.tabs.filter(tab => tab.name !== 'firewall') - // disable load balancing rules only if port forwarding is enabled and - // network belongs to VPC - if (this.portFWRuleCount > 0 && this.resource.vpcid) { - this.tabs = this.$route.meta.tabs.filter(tab => tab.name !== 'loadbalancing') - } else { + this.portFWRuleCount = await this.fetchPortFWRule() this.loadBalancerRuleCount = await this.fetchLoadBalancerRule() - // for isolated networks, display both LB and PF - // for VPC they are mutually exclusive + // VPC IPs with PF only have PF + if (this.portFWRuleCount > 0) { + tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'portforwarding')) + } + + // VPC IPs with LB rules only have LB if (this.loadBalancerRuleCount > 0) { - this.tabs = - this.resource.vpcid ? this.$route.meta.tabs.filter(tab => tab.name !== 'portforwarding') : this.$route.meta.tabs - this.loading = false - } else { - this.tabs = this.$route.meta.tabs + tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'loadbalancing')) } + this.tabs = tabs + return } - await this.fetchAction() - this.loading = false - }, - fetchAction () { - this.actions = [] - if (this.$route.meta.actions) { - this.actions = this.$route.meta.actions + // Regular guest networks with Source Nat have everything + if (this.resource && !this.resource.vpcid && this.resource.issourcenat) { + this.tabs = this.$route.meta.tabs + return + } + + // Regular guest networks with Static Nat only have Firewall + if (this.resource && !this.resource.vpcid && this.resource.isstaticnat) { + this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'firewall')) + return } - if (this.portFWRuleCount > 0 || this.loadBalancerRuleCount > 0) { - this.actions = this.actions.filter(action => action.api !== 'enableStaticNat') + // Regular guest networks have all tabs + if (this.resource && !this.resource.vpcid) { + this.tabs = this.$route.meta.tabs } }, + fetchAction () { + this.actions = this.$route.meta.actions || [] + }, fetchPortFWRule () { return new Promise((resolve, reject) => { api('listPortForwardingRules', {