diff --git a/app/models/cloudcredential.js b/app/models/cloudcredential.js index 0a308ba52..91d3d849d 100644 --- a/app/models/cloudcredential.js +++ b/app/models/cloudcredential.js @@ -20,15 +20,18 @@ const cloudCredential = Resource.extend({ isDo: notEmpty('digitaloceancredentialConfig'), isLinode: notEmpty('linodecredentialConfig'), isOCI: notEmpty('ocicredentialConfig'), + isPNAP: notEmpty('pnapcredentialConfig'), isVMware: notEmpty('vmwarevspherecredentialConfig'), - displayType: computed('amazonec2credentialConfig', 'azurecredentialConfig', 'digitaloceancredentialConfig', 'linodecredentialConfig', 'ocicredentialConfig', 'vmwarevspherecredentialConfig', function() { + + displayType: computed('amazonec2credentialConfig', 'azurecredentialConfig', 'digitaloceancredentialConfig', 'linodecredentialConfig', 'ocicredentialConfig', 'pnapcredentialConfig', 'vmwarevspherecredentialConfig', function() { const { isAmazon, isAzure, isDo, isLinode, isOCI, + isPNAP, isVMware } = this; @@ -42,6 +45,8 @@ const cloudCredential = Resource.extend({ return 'Linode'; } else if (isOCI) { return 'OCI'; + } else if (isPNAP) { + return 'phoenixNAP'; } else if (isVMware) { return 'VMware vSphere'; } diff --git a/app/models/nodedriver.js b/app/models/nodedriver.js index 33408d32d..ea85c7544 100644 --- a/app/models/nodedriver.js +++ b/app/models/nodedriver.js @@ -4,7 +4,7 @@ import Resource from '@rancher/ember-api-store/models/resource'; import C from 'ui/utils/constants'; import { parseExternalId } from 'ui/utils/parse-externalid'; -export const BUILT_IN_UI = ['amazonec2', 'digitalocean', 'azure', 'exoscale', 'packet', 'rackspace', 'vmwarevsphere', 'aliyunecs', 'oci']; +export const BUILT_IN_UI = ['amazonec2', 'digitalocean', 'azure', 'exoscale', 'packet', 'pnap', 'rackspace', 'vmwarevsphere', 'aliyunecs', 'oci']; export const BUILT_IN_ICON_ONLY = ['openstack', 'otc']; function displayUrl(url) { diff --git a/app/styles/abstracts/_mixins.scss b/app/styles/abstracts/_mixins.scss index 2c0afe223..7539d770f 100755 --- a/app/styles/abstracts/_mixins.scss +++ b/app/styles/abstracts/_mixins.scss @@ -103,6 +103,10 @@ background-image: url('images/providers/packet.svg'); } +@mixin pnap { + background-image: url('images/providers/pnap.svg'); +} + @mixin rackspace { background-image: url('images/providers/rackspace.svg'); } diff --git a/app/styles/components/_catalog-box.scss b/app/styles/components/_catalog-box.scss index a6e2b2fc7..d77302460 100644 --- a/app/styles/components/_catalog-box.scss +++ b/app/styles/components/_catalog-box.scss @@ -199,6 +199,7 @@ $badge-partner: $warning; &.openstack { @include openstack; } &.other { @include other; } &.packet { @include packet; } + &.pnap { @include pnap; } &.rackspace { @include rackspace; } &.rancherdo { @include rancherdo;} &.vmwarevsphere { @include vmwarevsphere; } diff --git a/app/styles/pages/_host.scss b/app/styles/pages/_host.scss index a12ad5e28..641776974 100644 --- a/app/styles/pages/_host.scss +++ b/app/styles/pages/_host.scss @@ -56,6 +56,7 @@ &.oci { @include oci; } &.openstack { @include openstack; } &.packet { @include packet; } + &.pnap { @include pnap; } &.rackspace { @include rackspace; } &.vmwarevsphere { @include vmwarevsphere; } &.other { @include other; } diff --git a/lib/global-admin/addon/components/cru-cloud-credential/component.js b/lib/global-admin/addon/components/cru-cloud-credential/component.js index c83f7d262..2b725393a 100644 --- a/lib/global-admin/addon/components/cru-cloud-credential/component.js +++ b/lib/global-admin/addon/components/cru-cloud-credential/component.js @@ -33,6 +33,12 @@ const CRED_CONFIG_CHOICES = [ driver: 'oci', configField: 'ocicredentialConfig', }, + { + name: 'pnap', + displayName: 'phoenixNAP', + driver: 'pnap', + configField: 'pnapcredentialConfig', + }, { name: 'linode', displayName: 'Linode', @@ -110,7 +116,7 @@ export default Component.extend(ViewNewEdit, { }, }, - config: computed('cloudCredentialType', 'model.{amazonec2credentialConfig,azurecredentialConfig,digitaloceancredentialConfig,linodecredentialConfig,ocicredentialConfig,vmwarevspherecredentialConfig}', function() { + config: computed('cloudCredentialType', 'model.{amazonec2credentialConfig,azurecredentialConfig,digitaloceancredentialConfig,linodecredentialConfig,ocicredentialConfig,pnapcredentialConfig,vmwarevspherecredentialConfig}', function() { const { model } = this; const configField = this.getConfigField(); @@ -145,6 +151,7 @@ export default Component.extend(ViewNewEdit, { case 'linode': return 'modalAddCloudKey.saving.validating'; case 'oci': + case 'pnap': case 'azure': case 'vmware': default: diff --git a/lib/global-admin/addon/components/cru-cloud-credential/template.hbs b/lib/global-admin/addon/components/cru-cloud-credential/template.hbs index 0921846ed..1d3a41b25 100644 --- a/lib/global-admin/addon/components/cru-cloud-credential/template.hbs +++ b/lib/global-admin/addon/components/cru-cloud-credential/template.hbs @@ -258,6 +258,37 @@ + {{else if (eq cloudCredentialType "pnap")}} +
+
+ + {{input + type="text" + value=config.clientIdentifier + classNames="form-control" + id="pnap-client-identifier" + placeholder=(t "modalAddCloudKey.pnap.clientIdentifier.placeholder") + }} +
+
+ + {{input + type="password" + value=config.clientSecret + classNames="form-control" + id="pnap-client-secret" + placeholder=(t "modalAddCloudKey.pnap.clientSecret.placeholder") + }} +

+ {{t "modalAddCloudKey.pnap.clientSecret.help" htmlSafe=true}} +

+
+
+ {{else if (eq cloudCredentialType "vmware")}}
diff --git a/lib/nodes/addon/components/driver-pnap/component.js b/lib/nodes/addon/components/driver-pnap/component.js new file mode 100644 index 000000000..721731da4 --- /dev/null +++ b/lib/nodes/addon/components/driver-pnap/component.js @@ -0,0 +1,86 @@ +import { alias } from '@ember/object/computed'; +import { get, set } from '@ember/object'; +import Component from '@ember/component'; +import NodeDriver from 'shared/mixins/node-driver'; +import layout from './template'; +import { inject as service } from '@ember/service'; + + +const DRIVER = 'pnap'; +const CONFIG = 'pnapConfig'; + +const LOCATION_CHOICES = [ + { value: 'PHX' }, + { value: 'ASH' } +]; + +const OS_CHOICES = [ + { value: 'ubuntu/bionic' }, + { value: 'centos/centos7' } +]; + + +const TYPE_CHOICES = [ + { value: 's1.c1.small' }, + { value: 's1.c1.medium' }, + { value: 's1.c2.medium' }, + { value: 's1.c2.large' }, + { value: 'd1.c1.small' }, + { value: 'd1.c1.medium' }, + { value: 'd1.c1.large' }, + { value: 'd1.m1.medium' } +]; + +export default Component.extend(NodeDriver, { + intl: service(), + + layout, + driverName: DRIVER, + locationChoices: LOCATION_CHOICES, + osChoices: OS_CHOICES, + typeChoices: TYPE_CHOICES, + + model: null, + config: alias(`model.${ CONFIG }`), + + actions: { + finishAndSelectCloudCredential(credential) { + set(this, 'model.cloudCredentialId', get(credential, 'id')) + } + }, + + bootstrap() { + let config = get(this, 'globalStore').createRecord({ + type: CONFIG, + serverLocation: 'PHX', + serverType: 's1.c1.medium', + serverOs: 'ubuntu/bionic', + serverHostname: 'host' + }); + + set(this, `model.${ CONFIG }`, config); + }, + + validate() { + this._super(); + let errors = get(this, 'errors') || []; + + if ( !get(this, 'model.name') ) { + errors.push(this.intl.t('nodeDriver.nameError')); + } + + if (!this.validateCloudCredentials()) { + errors.push(this.intl.t('nodeDriver.cloudCredentialError')) + } + + + if (errors.length) { + set(this, 'errors', errors.uniq()); + + return false; + } + + return true; + }, + +}); diff --git a/lib/nodes/addon/components/driver-pnap/template.hbs b/lib/nodes/addon/components/driver-pnap/template.hbs new file mode 100644 index 000000000..b846874df --- /dev/null +++ b/lib/nodes/addon/components/driver-pnap/template.hbs @@ -0,0 +1,112 @@ +{{#accordion-list showExpandAll=false as | al expandFn |}} +
+ + {{driverOptionsTitle}} + +
+ + {{#accordion-list-item + title=(t "nodeDriver.pnap.access.title") + detail=(t "nodeDriver.pnap.access.detail") + expandAll=expandAll + expand=(action expandFn) + expandOnInit=true + }} + {{form-auth-cloud-credential + driverName=driverName + parseAndCollectErrors=(action "errorHandler") + primaryResource=primaryResource + cloudCredentials=cloudCredentials + finishAndSelectCloudCredential=(action "finishAndSelectCloudCredential") + progressStep=(action "finishAndSelectCloudCredential") + cancel=(action "cancel") + hideSave=true + }} + + {{/accordion-list-item}} + + {{#accordion-list-item + title=(t "nodeDriver.pnap.serverDetails.title") + detail=(t "nodeDriver.pnap.serverDetails.detail") + expandAll=expandAll + expand=(action expandFn) + expandOnInit=true + }} +
+
+ + {{new-select + classNames="form-control" + content=locationChoices + optionLabelPath="value" + value=config.serverLocation + }} +
+
+ + {{new-select + classNames="form-control" + content=typeChoices + optionLabelPath="value" + value=config.serverType + }} +
+
+ +
+
+ + {{new-select + classNames="form-control" + content=osChoices + optionLabelPath="value" + value=config.serverOs + }} +
+
+ {{/accordion-list-item}} + +
+ + {{templateOptionsTitle}} + +
+ + {{form-name-description + model=model + nameRequired=true + rowClass="row mb-10" + }} + + {{form-user-labels + initialLabels=labelResource.labels + setLabels=(action "setLabels") + expand=(action expandFn) + }} + + {{form-node-taints + model=model + expand=(action expandFn) + }} + + {{form-engine-opts + machine=model + showEngineUrl=showEngineUrl + }} + + {{top-errors + errors=errors + }} + + {{save-cancel + save=(action "save") + cancel=(action "cancel") + editing=editing + }} +{{/accordion-list}} diff --git a/lib/nodes/app/components/driver-pnap/component.js b/lib/nodes/app/components/driver-pnap/component.js new file mode 100644 index 000000000..0e2e6e146 --- /dev/null +++ b/lib/nodes/app/components/driver-pnap/component.js @@ -0,0 +1 @@ +export { default } from 'nodes/components/driver-pnap/component'; diff --git a/lib/shared/addon/mixins/node-driver.js b/lib/shared/addon/mixins/node-driver.js index 0f7e58b8a..be20a2121 100644 --- a/lib/shared/addon/mixins/node-driver.js +++ b/lib/shared/addon/mixins/node-driver.js @@ -79,6 +79,10 @@ function _initBuiltInSizes() { driver: 'packet', keyOrKeysToWatch: 'config.plan', }, + { + driver: 'pnap', + keyOrKeysToWatch: 'config.serverType', + }, { driver: 'rackspace', keyOrKeysToWatch: 'config.flavorId', @@ -135,6 +139,10 @@ function _initBuiltInLocations() { driver: 'packet', keyOrKeysToWatch: 'config.facilityCode', }, + { + driver: 'pnap', + keyOrKeysToWatch: 'config.serverLocation', + }, { driver: 'rackspace', keyOrKeysToWatch: 'config.region', @@ -270,6 +278,11 @@ export default Mixin.create(NewOrEdit, ManageLabels, { return cc; } break; + case 'pnap': + if (get(cc, 'isPNAP')) { + return cc; + } + break; case 'vmwarevsphere': if (get(cc, 'isVMware')) { return cc; @@ -336,7 +349,7 @@ export default Mixin.create(NewOrEdit, ManageLabels, { }, validateCloudCredentials() { - const driversToValidate = ['amazonec2', 'azure', 'digitalocean', 'linode', 'vmwarevsphere']; + const driversToValidate = ['amazonec2', 'azure', 'digitalocean', 'linode', 'pnap', 'vmwarevsphere']; let { driverName } = this; let { cloudCredentialId } = this.model; let valid = false; diff --git a/public/assets/images/providers/pnap.svg b/public/assets/images/providers/pnap.svg new file mode 100644 index 000000000..5cd5ac233 --- /dev/null +++ b/public/assets/images/providers/pnap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/translations/en-us.yaml b/translations/en-us.yaml index 84e0c2903..c9e8ac609 100644 --- a/translations/en-us.yaml +++ b/translations/en-us.yaml @@ -8036,7 +8036,15 @@ modalAddCloudKey: authRegion: label: Region help: Any region your tenancy is subscribed to authenticate your credentials. - + pnap: + clientIdentifier: + label: Client ID + placeholder: Your Client ID + clientSecret: + label: Client Secret + placeholder: Your Client Secret + help: + From phoenixNAP BMC Portal Application Credentials vmwarevsphere: password: @@ -8642,6 +8650,7 @@ nodeDriver: otccce: Open Telekom Cloud CCE packet: Packet pinganyunecs: Pinganyun ECS + pnap: phoenixNAP rackspace: RackSpace rancherkubernetesengine: RKE softlayer: SoftLayer @@ -9338,7 +9347,29 @@ nodeDriver: region: label: Region placeholder: 'select cloud credential to populate options...' - + pnap: + access: + title: Account Access + detail: API Credentials will be used to launch phoenixNAP servers. + serverDetails: + title: Server Details + detail: Select details of the instances that will be created by this template. + location: + label: Location + placeholder: 'Please select server location.' + os: + label: OS + placeholder: 'Please select Operating System.' + type: + label: Type + placeholder: 'Please select type of server to provision.' + errors: + typeRequired: Server type is required. + osRequired: Operating System is required. + locationRequired: Location is required. + hostnameRequired: Hostname is required. + clientIDRequired: Client ID is required. + clientSecretRequired: Client Secret is required. zstack: access: title: 1. Account Access