From 2370799066c0a3483b0e2a0301df2bae01cd33be Mon Sep 17 00:00:00 2001 From: MathieuAA Date: Tue, 11 May 2021 07:10:44 +0200 Subject: [PATCH 1/7] Removed unused deployment option --- jdl/jhipster/deployment-options.js | 1 - 1 file changed, 1 deletion(-) diff --git a/jdl/jhipster/deployment-options.js b/jdl/jhipster/deployment-options.js index b73eb74515c..ea01ff12f7a 100644 --- a/jdl/jhipster/deployment-options.js +++ b/jdl/jhipster/deployment-options.js @@ -28,7 +28,6 @@ const DeploymentTypes = { const Options = { deploymentType: { dockerCompose: DeploymentTypes.DOCKERCOMPOSE, - rancherCompose: DeploymentTypes.RANCHERCOMPOSE, kubernetes: DeploymentTypes.KUBERNETES, openshift: DeploymentTypes.OPENSHIFT, }, From e7e089fed8f3d4b04b389f63825c0cd70c1e361d Mon Sep 17 00:00:00 2001 From: MathieuAA Date: Tue, 11 May 2021 07:54:01 +0200 Subject: [PATCH 2/7] Added missing jdl deployment options fixes #14817 --- jdl/jhipster/deployment-options.js | 39 ++++++++++++++++++------- test/jdl/jdl-importer.spec.js | 47 ++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/jdl/jhipster/deployment-options.js b/jdl/jhipster/deployment-options.js index ea01ff12f7a..4ec3c416109 100644 --- a/jdl/jhipster/deployment-options.js +++ b/jdl/jhipster/deployment-options.js @@ -25,6 +25,29 @@ const DeploymentTypes = { exists: deploymentType => !!deploymentType && !!DeploymentTypes[deploymentType.toUpperCase().replace('-', '')], }; +const kubernetesRelatedOptions = { + kubernetesNamespace: 'default', + kubernetesServiceType: { + loadBalancer: 'LoadBalancer', + nodePort: 'NodePort', + ingress: 'Ingress', + }, + kubernetesStorageClassName: '', + kubernetesUseDynamicStorage: { + false: false, + true: true, + }, + ingressDomain: '', + ingressType: { + nginx: 'nginx', + gke: 'gke', + }, + istio: { + false: false, + true: true, + }, +}; + const Options = { deploymentType: { dockerCompose: DeploymentTypes.DOCKERCOMPOSE, @@ -50,17 +73,7 @@ const Options = { dockerRepositoryName: '', dockerPushCommand: 'docker push', // Kubernetes specific - kubernetesNamespace: 'default', - kubernetesServiceType: { - loadBalancer: 'LoadBalancer', - nodePort: 'NodePort', - ingress: 'Ingress', - }, - ingressDomain: '', - istio: { - false: false, - true: true, - }, + ...kubernetesRelatedOptions, // openshift specific openshiftNamespace: 'default', storageType: { @@ -84,7 +97,11 @@ Options.defaults = (deploymentType = Options.deploymentType.dockerCompose) => dockerPushCommand: Options.dockerPushCommand, kubernetesNamespace: deploymentType === Options.deploymentType.kubernetes ? Options.kubernetesNamespace : undefined, kubernetesServiceType: deploymentType === Options.deploymentType.kubernetes ? Options.kubernetesServiceType.loadBalancer : undefined, + kubernetesStorageClassName: deploymentType === Options.deploymentType.kubernetes ? Options.kubernetesStorageClassName : '', + kubernetesUseDynamicStorage: + deploymentType === Options.deploymentType.kubernetes ? deploymentType === Options.deploymentType.kubernetes : false, ingressDomain: deploymentType === Options.deploymentType.kubernetes ? Options.ingressDomain : undefined, + ingressType: deploymentType === Options.deploymentType.kubernetes ? Options.ingressType.nginx : undefined, istio: deploymentType === Options.deploymentType.kubernetes ? Options.istio.false : undefined, openshiftNamespace: deploymentType === Options.deploymentType.openshift ? Options.openshiftNamespace : undefined, storageType: deploymentType === Options.deploymentType.openshift ? Options.storageType.ephemeral : undefined, diff --git a/test/jdl/jdl-importer.spec.js b/test/jdl/jdl-importer.spec.js index 83cc10032b4..8f2e22613cb 100644 --- a/test/jdl/jdl-importer.spec.js +++ b/test/jdl/jdl-importer.spec.js @@ -619,6 +619,53 @@ relationship OneToOne { }); }); }); + context('when parsing two JDL applications with and without entities ', () => { + let returned; + const APPLICATION_NAMES = ['app1', 'app2']; + + before(() => { + const importer = createImporterFromFiles([path.join(__dirname, 'test-files', 'applications_with_and_without_entities.jdl')]); + returned = importer.import(); + }); + + after(() => { + APPLICATION_NAMES.forEach(applicationName => { + fse.removeSync(applicationName); + }); + }); + + it('should return the import state', () => { + expect(returned.exportedEntities).to.have.lengthOf(1); + expect(returned.exportedApplications).to.have.lengthOf(2); + expect(Object.keys(returned.exportedApplicationsWithEntities).length).to.equal(2); + expect(returned.exportedDeployments).to.have.lengthOf(0); + }); + it('should create the folders and the .yo-rc.json files', () => { + APPLICATION_NAMES.forEach(applicationName => { + expect(fse.statSync(path.join(applicationName, '.yo-rc.json')).isFile()).to.be.true; + expect(fse.statSync(applicationName).isDirectory()).to.be.true; + }); + }); + it('should create the entity folder in only one app folder', () => { + expect(fse.existsSync(path.join(APPLICATION_NAMES[0], '.jhipster'))).to.be.false; + expect(fse.statSync(path.join(APPLICATION_NAMES[1], '.jhipster')).isDirectory()).to.be.true; + expect(fse.statSync(path.join(APPLICATION_NAMES[1], '.jhipster', 'BankAccount.json')).isFile()).to.be.true; + }); + it('should export the application contents', () => { + expect(returned.exportedApplicationsWithEntities[APPLICATION_NAMES[0]].entities).to.have.lengthOf(0); + expect(returned.exportedApplicationsWithEntities[APPLICATION_NAMES[1]].entities).to.have.lengthOf(1); + }); + it('should return the corresponding exportedApplicationsWithEntities', () => { + returned.exportedApplications.forEach(application => { + const applicationConfig = application['generator-jhipster']; + const entityNames = application.entities || []; + const applicationWithEntities = returned.exportedApplicationsWithEntities[applicationConfig.baseName]; + expect(applicationConfig).to.be.eql(applicationWithEntities.config); + expect(applicationWithEntities.entities.map(entity => entity.name)).to.be.eql(entityNames); + expect(returned.exportedEntities.filter(entity => entityNames.includes(entity.name))).to.be.eql(applicationWithEntities.entities); + }); + }); + }); context('when parsing one JDL application and entities passed as string', () => { let returned; From e514705f08beab6723bdbab89302f387d390b3ef Mon Sep 17 00:00:00 2001 From: MathieuAA Date: Tue, 11 May 2021 07:54:01 +0200 Subject: [PATCH 3/7] Added missing jdl deployment options fixes #14817 --- jdl/jhipster/deployment-options.js | 98 +++++++++++++------ ...parsed-jdl-to-jdl-object-converter.spec.js | 1 - .../jhipster-deployment-exporter.spec.js | 3 +- test/jdl/jdl-importer.spec.js | 9 +- test/jdl/jhipster/deployment-options.spec.js | 15 +-- test/jdl/models/jdl-deployment.spec.js | 6 +- 6 files changed, 78 insertions(+), 54 deletions(-) diff --git a/jdl/jhipster/deployment-options.js b/jdl/jhipster/deployment-options.js index ea01ff12f7a..e556011cd8a 100644 --- a/jdl/jhipster/deployment-options.js +++ b/jdl/jhipster/deployment-options.js @@ -16,8 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -const _ = require('lodash'); - const DeploymentTypes = { DOCKERCOMPOSE: 'docker-compose', KUBERNETES: 'kubernetes', @@ -25,6 +23,29 @@ const DeploymentTypes = { exists: deploymentType => !!deploymentType && !!DeploymentTypes[deploymentType.toUpperCase().replace('-', '')], }; +const kubernetesRelatedOptions = { + kubernetesNamespace: 'default', + kubernetesServiceType: { + loadBalancer: 'LoadBalancer', + nodePort: 'NodePort', + ingress: 'Ingress', + }, + kubernetesStorageClassName: '', + kubernetesUseDynamicStorage: { + false: false, + true: true, + }, + ingressDomain: '', + ingressType: { + nginx: 'nginx', + gke: 'gke', + }, + istio: { + false: false, + true: true, + }, +}; + const Options = { deploymentType: { dockerCompose: DeploymentTypes.DOCKERCOMPOSE, @@ -40,7 +61,7 @@ const Options = { }, directoryPath: '../', appsFolders: [], - clusteredDbApps: [], + clusteredDbApps: {}, // adminPassword: 'admin', serviceDiscoveryType: { eureka: 'eureka', @@ -50,47 +71,60 @@ const Options = { dockerRepositoryName: '', dockerPushCommand: 'docker push', // Kubernetes specific - kubernetesNamespace: 'default', - kubernetesServiceType: { - loadBalancer: 'LoadBalancer', - nodePort: 'NodePort', - ingress: 'Ingress', - }, - ingressDomain: '', - istio: { - false: false, - true: true, - }, + ...kubernetesRelatedOptions, // openshift specific openshiftNamespace: 'default', + registryReplicas: { + two: 2, + }, storageType: { ephemeral: 'ephemeral', persistent: 'persistent', }, }; -Options.defaults = (deploymentType = Options.deploymentType.dockerCompose) => - _.omitBy( - { - deploymentType, - gatewayType: Options.gatewayType.springCloudGateway, - monitoring: Options.monitoring.no, - directoryPath: Options.directoryPath, +Options.defaults = (deploymentType = Options.deploymentType.dockerCompose) => { + if (deploymentType === Options.deploymentType.kubernetes) { + return { appsFolders: new Set(), - clusteredDbApps: new Set(), - adminPassword: Options.adminPassword, + directoryPath: Options.directoryPath, + clusteredDbApps: new Map(), serviceDiscoveryType: Options.serviceDiscoveryType.eureka, dockerRepositoryName: Options.dockerRepositoryName, dockerPushCommand: Options.dockerPushCommand, - kubernetesNamespace: deploymentType === Options.deploymentType.kubernetes ? Options.kubernetesNamespace : undefined, - kubernetesServiceType: deploymentType === Options.deploymentType.kubernetes ? Options.kubernetesServiceType.loadBalancer : undefined, - ingressDomain: deploymentType === Options.deploymentType.kubernetes ? Options.ingressDomain : undefined, - istio: deploymentType === Options.deploymentType.kubernetes ? Options.istio.false : undefined, - openshiftNamespace: deploymentType === Options.deploymentType.openshift ? Options.openshiftNamespace : undefined, - storageType: deploymentType === Options.deploymentType.openshift ? Options.storageType.ephemeral : undefined, - }, - _.isUndefined - ); + kubernetesNamespace: Options.kubernetesNamespace, + kubernetesServiceType: Options.kubernetesServiceType.loadBalancer, + kubernetesUseDynamicStorage: Options.kubernetesUseDynamicStorage.false, + ingressDomain: Options.ingressDomain, + monitoring: Options.monitoring.no, + istio: Options.istio.false, + }; + } + + if (deploymentType === Options.deploymentType.dockerCompose) { + return { + appsFolders: new Set(), + directoryPath: Options.directoryPath, + gatewayType: Options.gatewayType.springCloudGateway, + clusteredDbApps: new Map(), + monitoring: Options.monitoring.no, + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }; + } + + return { + appsFolders: new Set(), + directoryPath: Options.directoryPath, + clusteredDbApps: new Map(), + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + monitoring: Options.monitoring.no, + dockerRepositoryName: Options.dockerRepositoryName, + dockerPushCommand: Options.dockerPushCommand, + openshiftNamespace: Options.openshiftNamespace, + storageType: Options.storageType.ephemeral, + registryReplicas: Options.registryReplicas.two, + }; +}; module.exports = { Options, diff --git a/test/jdl/converters/parsedJDLToJDLObject/parsed-jdl-to-jdl-object-converter.spec.js b/test/jdl/converters/parsedJDLToJDLObject/parsed-jdl-to-jdl-object-converter.spec.js index 48b3b12f32a..b91b7ffc070 100644 --- a/test/jdl/converters/parsedJDLToJDLObject/parsed-jdl-to-jdl-object-converter.spec.js +++ b/test/jdl/converters/parsedJDLToJDLObject/parsed-jdl-to-jdl-object-converter.spec.js @@ -544,7 +544,6 @@ describe('ParsedJDLToJDLObjectConverter', () => { expect(deployment).to.deep.equal({ deploymentType: 'docker-compose', directoryPath: '../', - dockerPushCommand: 'docker push', dockerRepositoryName: 'test', gatewayType: 'SpringCloudGateway', monitoring: 'no', diff --git a/test/jdl/exporters/jhipster-deployment-exporter.spec.js b/test/jdl/exporters/jhipster-deployment-exporter.spec.js index cda04591a25..1de22768845 100644 --- a/test/jdl/exporters/jhipster-deployment-exporter.spec.js +++ b/test/jdl/exporters/jhipster-deployment-exporter.spec.js @@ -88,7 +88,6 @@ describe('JHipsterDeploymentExporter', () => { appsFolders: ['tata', 'titi'], clusteredDbApps: [], directoryPath: '../', - dockerPushCommand: 'docker push', dockerRepositoryName: 'test', gatewayType: 'SpringCloudGateway', monitoring: 'no', @@ -128,12 +127,12 @@ describe('JHipsterDeploymentExporter', () => { directoryPath: '../', dockerPushCommand: 'docker push', dockerRepositoryName: 'test', - gatewayType: 'SpringCloudGateway', ingressDomain: '', istio: false, kubernetesNamespace: 'default', kubernetesServiceType: 'LoadBalancer', monitoring: 'no', + kubernetesUseDynamicStorage: false, serviceDiscoveryType: 'eureka', }); }); diff --git a/test/jdl/jdl-importer.spec.js b/test/jdl/jdl-importer.spec.js index 83cc10032b4..6850249474e 100644 --- a/test/jdl/jdl-importer.spec.js +++ b/test/jdl/jdl-importer.spec.js @@ -1361,7 +1361,6 @@ relationship OneToOne { clusteredDbApps: [], deploymentType: 'docker-compose', serviceDiscoveryType: 'eureka', - dockerPushCommand: 'docker push', dockerRepositoryName: 'test', monitoring: 'no', }, @@ -1410,7 +1409,6 @@ relationship OneToOne { clusteredDbApps: [], deploymentType: 'docker-compose', serviceDiscoveryType: 'eureka', - dockerPushCommand: 'docker push', dockerRepositoryName: 'test', monitoring: 'no', }, @@ -1423,8 +1421,8 @@ relationship OneToOne { deploymentType: 'kubernetes', dockerPushCommand: 'docker push', dockerRepositoryName: 'test', - gatewayType: 'SpringCloudGateway', ingressDomain: '', + kubernetesUseDynamicStorage: false, istio: false, kubernetesNamespace: 'default', kubernetesServiceType: 'LoadBalancer', @@ -1440,8 +1438,8 @@ relationship OneToOne { deploymentType: 'openshift', dockerPushCommand: 'docker push', dockerRepositoryName: 'test', - gatewayType: 'SpringCloudGateway', monitoring: 'no', + registryReplicas: 2, openshiftNamespace: 'default', serviceDiscoveryType: 'eureka', storageType: 'ephemeral', @@ -1620,13 +1618,11 @@ relationship OneToOne { clusteredDbApps: [], serviceDiscoveryType: false, dockerRepositoryName: 'deepu105', - dockerPushCommand: 'docker push', }, }, { 'generator-jhipster': { deploymentType: 'kubernetes', - gatewayType: 'SpringCloudGateway', monitoring: 'no', directoryPath: '../', appsFolders: ['store', 'invoice', 'notification', 'product'], @@ -1638,6 +1634,7 @@ relationship OneToOne { kubernetesServiceType: 'LoadBalancer', ingressDomain: '', istio: false, + kubernetesUseDynamicStorage: false, }, }, ]; diff --git a/test/jdl/jhipster/deployment-options.spec.js b/test/jdl/jhipster/deployment-options.spec.js index 718a09259d8..bd6c752773a 100644 --- a/test/jdl/jhipster/deployment-options.spec.js +++ b/test/jdl/jhipster/deployment-options.spec.js @@ -50,12 +50,9 @@ describe('DeploymentOptions', () => { context('when passing no args', () => { it('should return docker deployment config', () => { expect(Options.defaults()).to.eql({ - deploymentType: 'docker-compose', appsFolders: new Set(), - clusteredDbApps: new Set(), + clusteredDbApps: new Map(), directoryPath: '../', - dockerPushCommand: 'docker push', - dockerRepositoryName: '', gatewayType: 'SpringCloudGateway', monitoring: 'no', serviceDiscoveryType: 'eureka', @@ -65,13 +62,12 @@ describe('DeploymentOptions', () => { context('when passing kubernetes as arg', () => { it('should return kubernetes deployment config', () => { expect(Options.defaults('kubernetes')).to.eql({ - deploymentType: 'kubernetes', appsFolders: new Set(), - clusteredDbApps: new Set(), + clusteredDbApps: new Map(), directoryPath: '../', dockerPushCommand: 'docker push', dockerRepositoryName: '', - gatewayType: 'SpringCloudGateway', + kubernetesUseDynamicStorage: false, monitoring: 'no', serviceDiscoveryType: 'eureka', ingressDomain: '', @@ -84,17 +80,16 @@ describe('DeploymentOptions', () => { context('when passing openshift as arg', () => { it('should return openshift deployment config', () => { expect(Options.defaults('openshift')).to.eql({ - deploymentType: 'openshift', appsFolders: new Set(), - clusteredDbApps: new Set(), + clusteredDbApps: new Map(), directoryPath: '../', dockerPushCommand: 'docker push', dockerRepositoryName: '', - gatewayType: 'SpringCloudGateway', monitoring: 'no', serviceDiscoveryType: 'eureka', openshiftNamespace: 'default', storageType: 'ephemeral', + registryReplicas: 2, }); }); }); diff --git a/test/jdl/models/jdl-deployment.spec.js b/test/jdl/models/jdl-deployment.spec.js index 14b14a1df44..ce5ec313411 100644 --- a/test/jdl/models/jdl-deployment.spec.js +++ b/test/jdl/models/jdl-deployment.spec.js @@ -75,8 +75,8 @@ describe('JDLDeployment', () => { it('should stringify its content without default values', () => { expect(deployment.toString()).to.eql(`deployment { - deploymentType ${args.deploymentType} appsFolders [${args.appsFolders.join(', ').replace(/'/g, '')}] + deploymentType ${args.deploymentType} dockerRepositoryName ${args.dockerRepositoryName} }`); }); @@ -98,9 +98,9 @@ describe('JDLDeployment', () => { it('should stringify it', () => { expect(deployment.toString()).to.eql(`deployment { - deploymentType ${args.deploymentType} - directoryPath ${args.directoryPath} appsFolders [${args.appsFolders.join(', ').replace(/'/g, '')}] + directoryPath ${args.directoryPath} + deploymentType ${args.deploymentType} dockerRepositoryName ${args.dockerRepositoryName} }`); }); From 34109fca55d1b85d036112140a70fab711a1e4f8 Mon Sep 17 00:00:00 2001 From: MathieuAA Date: Fri, 14 May 2021 22:01:18 +0200 Subject: [PATCH 4/7] Added validations for docker-compose-related deployments --- jdl/jhipster/deployment-options.js | 8 +- jdl/validators/deployment-validator.js | 19 +++-- test/jdl/jhipster/deployment-options.spec.js | 6 +- .../validators/deployment-validator.spec.js | 85 ++++++++++++++++--- 4 files changed, 92 insertions(+), 26 deletions(-) diff --git a/jdl/jhipster/deployment-options.js b/jdl/jhipster/deployment-options.js index ea07a47f9a6..3ec8b97dadd 100644 --- a/jdl/jhipster/deployment-options.js +++ b/jdl/jhipster/deployment-options.js @@ -65,7 +65,7 @@ const dockerComposeRelatedOptions = { const baseOptions = { appsFolders: [], - clusteredDbApps: {}, + clusteredDbApps: [], directoryPath: '../', monitoring: { no: 'no', @@ -97,7 +97,7 @@ Options.defaults = (deploymentType = Options.deploymentType.dockerCompose) => { return { appsFolders: new Set(), directoryPath: Options.directoryPath, - clusteredDbApps: new Map(), + clusteredDbApps: new Set(), serviceDiscoveryType: Options.serviceDiscoveryType.eureka, dockerRepositoryName: Options.dockerRepositoryName, dockerPushCommand: Options.dockerPushCommand, @@ -115,7 +115,7 @@ Options.defaults = (deploymentType = Options.deploymentType.dockerCompose) => { appsFolders: new Set(), directoryPath: Options.directoryPath, gatewayType: Options.gatewayType.springCloudGateway, - clusteredDbApps: new Map(), + clusteredDbApps: new Set(), monitoring: Options.monitoring.no, serviceDiscoveryType: Options.serviceDiscoveryType.eureka, }; @@ -124,7 +124,7 @@ Options.defaults = (deploymentType = Options.deploymentType.dockerCompose) => { return { appsFolders: new Set(), directoryPath: Options.directoryPath, - clusteredDbApps: new Map(), + clusteredDbApps: new Set(), serviceDiscoveryType: Options.serviceDiscoveryType.eureka, monitoring: Options.monitoring.no, dockerRepositoryName: Options.dockerRepositoryName, diff --git a/jdl/validators/deployment-validator.js b/jdl/validators/deployment-validator.js index 7997b38cdb6..d8722b183fc 100644 --- a/jdl/validators/deployment-validator.js +++ b/jdl/validators/deployment-validator.js @@ -17,16 +17,25 @@ * limitations under the License. */ +const { MICROSERVICE } = require('../jhipster/application-types'); +const { Options } = require('../jhipster/deployment-options'); const Validator = require('./validator'); -class DeploymentValidator extends Validator { +module.exports = class DeploymentValidator extends Validator { constructor() { - super('deployment', ['deploymentType', 'appsFolders', 'dockerRepositoryName']); + super('deployment', ['deploymentType', 'appsFolders', 'directoryPath']); } - validate(jdlDeployment) { + validate(jdlDeployment, options = {}) { super.validate(jdlDeployment); + if (jdlDeployment.deploymentType === Options.deploymentType.dockerCompose) { + validateDockerComposeRelatedDeployment(jdlDeployment, options); + } } -} +}; -module.exports = DeploymentValidator; +function validateDockerComposeRelatedDeployment(jdlDeployment, options = {}) { + if (jdlDeployment.gatewayType !== Options.gatewayType.springCloudGateway && options.applicationType === MICROSERVICE) { + throw new Error('A gateway type must be provided when dealing with microservices and the deployment type is docker-compose.'); + } +} diff --git a/test/jdl/jhipster/deployment-options.spec.js b/test/jdl/jhipster/deployment-options.spec.js index bd6c752773a..f9f39b0ba0c 100644 --- a/test/jdl/jhipster/deployment-options.spec.js +++ b/test/jdl/jhipster/deployment-options.spec.js @@ -51,7 +51,7 @@ describe('DeploymentOptions', () => { it('should return docker deployment config', () => { expect(Options.defaults()).to.eql({ appsFolders: new Set(), - clusteredDbApps: new Map(), + clusteredDbApps: new Set(), directoryPath: '../', gatewayType: 'SpringCloudGateway', monitoring: 'no', @@ -63,7 +63,7 @@ describe('DeploymentOptions', () => { it('should return kubernetes deployment config', () => { expect(Options.defaults('kubernetes')).to.eql({ appsFolders: new Set(), - clusteredDbApps: new Map(), + clusteredDbApps: new Set(), directoryPath: '../', dockerPushCommand: 'docker push', dockerRepositoryName: '', @@ -81,7 +81,7 @@ describe('DeploymentOptions', () => { it('should return openshift deployment config', () => { expect(Options.defaults('openshift')).to.eql({ appsFolders: new Set(), - clusteredDbApps: new Map(), + clusteredDbApps: new Set(), directoryPath: '../', dockerPushCommand: 'docker push', dockerRepositoryName: '', diff --git a/test/jdl/validators/deployment-validator.spec.js b/test/jdl/validators/deployment-validator.spec.js index 3113a73fb57..31c93a22439 100644 --- a/test/jdl/validators/deployment-validator.spec.js +++ b/test/jdl/validators/deployment-validator.spec.js @@ -18,6 +18,8 @@ */ const { expect } = require('chai'); +const { Options } = require('../../../jdl/jhipster/deployment-options'); +const { MICROSERVICE } = require('../../../jdl/jhipster/application-types'); const DeploymentValidator = require('../../../jdl/validators/deployment-validator'); describe('DeploymentValidator', () => { @@ -34,22 +36,77 @@ describe('DeploymentValidator', () => { }); }); context('when a deployment is passed', () => { - context('when not missing any attribute', () => { - it('should not fail', () => { - expect(() => { - validator.validate({ - deploymentType: 'kubernetes', - appsFolders: ['invoices'], - dockerRepositoryName: 'test', + context('when having a docker-compose-related deployment', () => { + context('without appFolders', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.dockerCompose, + directoryPath: '../', + gatewayType: Options.gatewayType.springCloudGateway, + monitoring: 'no', + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }) + ).to.throw(/^The deployment attribute appsFolders was not found.$/); + }); + }); + context('without directoryPath', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.dockerCompose, + appsFolders: ['beers', 'burgers'], + gatewayType: Options.gatewayType.springCloudGateway, + monitoring: 'no', + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }) + ).to.throw(/^The deployment attribute directoryPath was not found.$/); + }); + }); + context('without monitoring', () => { + it('should not fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.dockerCompose, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + gatewayType: Options.gatewayType.springCloudGateway, + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }) + ).not.to.throw(); + }); + }); + context('with microservices', () => { + context('without gatewayType', () => { + it('should fail', () => { + expect(() => + validator.validate( + { + deploymentType: Options.deploymentType.dockerCompose, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + monitoring: 'no', + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }, + { + applicationType: MICROSERVICE, + } + ) + ).to.throw(/^A gateway type must be provided when dealing with microservices and the deployment type is docker-compose.$/); }); - }).not.to.throw(); + }); }); - }); - context('when missing attributes', () => { - it('should fail', () => { - expect(() => validator.validate({})).to.throw( - /^The deployment attributes deploymentType, appsFolders, dockerRepositoryName were not found.$/ - ); + context('without serviceDiscoveryType', () => { + it('should not fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.dockerCompose, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + monitoring: 'no', + }) + ).not.to.throw(); + }); }); }); }); From deb9a7bf367681dc555c535a3b42db904c23bcaf Mon Sep 17 00:00:00 2001 From: MathieuAA Date: Fri, 14 May 2021 22:44:58 +0200 Subject: [PATCH 5/7] Added validations for kubernetes-related deployments --- jdl/validators/deployment-validator.js | 29 ++++- .../validators/deployment-validator.spec.js | 102 ++++++++++++++++++ 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/jdl/validators/deployment-validator.js b/jdl/validators/deployment-validator.js index d8722b183fc..cbee8aadfe3 100644 --- a/jdl/validators/deployment-validator.js +++ b/jdl/validators/deployment-validator.js @@ -28,8 +28,19 @@ module.exports = class DeploymentValidator extends Validator { validate(jdlDeployment, options = {}) { super.validate(jdlDeployment); - if (jdlDeployment.deploymentType === Options.deploymentType.dockerCompose) { - validateDockerComposeRelatedDeployment(jdlDeployment, options); + + switch (jdlDeployment.deploymentType) { + case Options.deploymentType.dockerCompose: + validateDockerComposeRelatedDeployment(jdlDeployment, options); + break; + case Options.deploymentType.kubernetes: + validateKubernetesRelatedDeployment(jdlDeployment); + break; + case Options.deploymentType.openshift: + // TODO + break; + default: + throw new Error(`The deployment type ${jdlDeployment.deploymentType} isn't supported.`); } } }; @@ -39,3 +50,17 @@ function validateDockerComposeRelatedDeployment(jdlDeployment, options = {}) { throw new Error('A gateway type must be provided when dealing with microservices and the deployment type is docker-compose.'); } } + +function validateKubernetesRelatedDeployment(jdlDeployment) { + if (!jdlDeployment.kubernetesServiceType) { + throw new Error('A kubernetes service type must be provided when dealing with kubernetes-related deployments.'); + } + if (jdlDeployment.istio && !jdlDeployment.ingressDomain) { + throw new Error( + 'An ingress domain must be provided when dealing with kubernetes-related deployments, with istio and when the service type is ingress.' + ); + } + if (jdlDeployment.kubernetesServiceType === Options.kubernetesServiceType.ingress && !jdlDeployment.ingressType) { + throw new Error('An ingress type is required when dealing with kubernetes-related deployments and when the service type is ingress.'); + } +} diff --git a/test/jdl/validators/deployment-validator.spec.js b/test/jdl/validators/deployment-validator.spec.js index 31c93a22439..d814f8213be 100644 --- a/test/jdl/validators/deployment-validator.spec.js +++ b/test/jdl/validators/deployment-validator.spec.js @@ -109,6 +109,108 @@ describe('DeploymentValidator', () => { }); }); }); + context('when having a kubernetes-related deployment', () => { + context('without appFolders', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.kubernetes, + directoryPath: '../', + kubernetesServiceType: Options.kubernetesServiceType.loadBalancer, + monitoring: 'no', + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }) + ).to.throw(/^The deployment attribute appsFolders was not found.$/); + }); + }); + context('without directoryPath', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.kubernetes, + appsFolders: ['beers', 'burgers'], + kubernetesServiceType: Options.kubernetesServiceType.loadBalancer, + monitoring: 'no', + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }) + ).to.throw(/^The deployment attribute directoryPath was not found.$/); + }); + }); + context( + 'without monitoring, dockerPushCommand, dockerRepositoryName, kubernetesNamespace, kubernetesUseDynamicStorage, kubernetesStorageClassName or istio and an ingressDomain', + () => { + it('should not fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.kubernetes, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + kubernetesServiceType: Options.kubernetesServiceType.loadBalancer, + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }) + ).not.to.throw(); + }); + } + ); + context('without kubernetesServiceType', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.kubernetes, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }) + ).to.throw(/^A kubernetes service type must be provided when dealing with kubernetes-related deployments.$/); + }); + }); + context('with istio', () => { + context('without an ingressDomain', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.kubernetes, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + kubernetesServiceType: Options.kubernetesServiceType.loadBalancer, + istio: true, + }) + ).to.throw( + /^An ingress domain must be provided when dealing with kubernetes-related deployments, with istio and when the service type is ingress.$/ + ); + }); + }); + }); + context('with the kubernetesServiceType being Ingress', () => { + context('without an ingressType', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.kubernetes, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + kubernetesServiceType: Options.kubernetesServiceType.ingress, + serviceDiscoveryType: Options.serviceDiscoveryType.eureka, + }) + ).to.throw( + /^An ingress type is required when dealing with kubernetes-related deployments and when the service type is ingress.$/ + ); + }); + }); + }); + }); + }); + context('when passing an unknown deployment type', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: 'whatever', + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + }) + ).to.throw(/^The deployment type whatever isn't supported.$/); + }); }); }); }); From ebbae42fbc52fe58d1297c0355d30e3988b81377 Mon Sep 17 00:00:00 2001 From: MathieuAA Date: Tue, 1 Jun 2021 20:54:05 +0200 Subject: [PATCH 6/7] Added validations for openshift-related deployments --- jdl/validators/deployment-validator.js | 20 +++- .../validators/deployment-validator.spec.js | 108 ++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/jdl/validators/deployment-validator.js b/jdl/validators/deployment-validator.js index cbee8aadfe3..4d9e4bdb8b8 100644 --- a/jdl/validators/deployment-validator.js +++ b/jdl/validators/deployment-validator.js @@ -18,6 +18,8 @@ */ const { MICROSERVICE } = require('../jhipster/application-types'); +const { NO } = require('../jhipster/database-types'); +const { ELASTICSEARCH } = require('../jhipster/search-engine-types'); const { Options } = require('../jhipster/deployment-options'); const Validator = require('./validator'); @@ -37,7 +39,7 @@ module.exports = class DeploymentValidator extends Validator { validateKubernetesRelatedDeployment(jdlDeployment); break; case Options.deploymentType.openshift: - // TODO + validateOpenshiftRelatedDeployment(jdlDeployment, options); break; default: throw new Error(`The deployment type ${jdlDeployment.deploymentType} isn't supported.`); @@ -64,3 +66,19 @@ function validateKubernetesRelatedDeployment(jdlDeployment) { throw new Error('An ingress type is required when dealing with kubernetes-related deployments and when the service type is ingress.'); } } + +function validateOpenshiftRelatedDeployment(jdlDeployment, options) { + if (jdlDeployment.storageType) { + if (options.prodDatabaseType === NO) { + throw new Error("Can't have the storageType option set when there is no prodDatabaseType."); + } + + if (options.searchEngine === ELASTICSEARCH) { + throw new Error("Can't have the storageType option set when elasticsearch is the search engine."); + } + + if (jdlDeployment.monitoring === Options.monitoring.prometheus) { + throw new Error("Can't have the storageType option set when the monitoring is done with prometheus."); + } + } +} diff --git a/test/jdl/validators/deployment-validator.spec.js b/test/jdl/validators/deployment-validator.spec.js index d814f8213be..910d7103515 100644 --- a/test/jdl/validators/deployment-validator.spec.js +++ b/test/jdl/validators/deployment-validator.spec.js @@ -20,6 +20,8 @@ const { expect } = require('chai'); const { Options } = require('../../../jdl/jhipster/deployment-options'); const { MICROSERVICE } = require('../../../jdl/jhipster/application-types'); +const { MONGODB, NO } = require('../../../jdl/jhipster/database-types'); +const SearchEngineTypes = require('../../../jdl/jhipster/search-engine-types'); const DeploymentValidator = require('../../../jdl/validators/deployment-validator'); describe('DeploymentValidator', () => { @@ -200,6 +202,112 @@ describe('DeploymentValidator', () => { }); }); }); + context('when having an openshift-related deployment', () => { + context('without appFolders', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.openshift, + directoryPath: '../', + gatewayType: Options.gatewayType.springCloudGateway, + openshiftNamespace: 'default', + }) + ).to.throw(/^The deployment attribute appsFolders was not found.$/); + }); + }); + context('without directoryPath', () => { + it('should fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.openshift, + appsFolders: ['beers', 'burgers'], + monitoring: 'no', + openshiftNamespace: 'default', + }) + ).to.throw(/^The deployment attribute directoryPath was not found.$/); + }); + }); + context('without monitoring', () => { + it('should not fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.openshift, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + openshiftNamespace: 'default', + }) + ).not.to.throw(); + }); + }); + context('without openshiftNamespace', () => { + it('should not fail', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.openshift, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + }) + ).not.to.throw(); + }); + }); + context('when there is no prodDatabaseType', () => { + it('should fail if there is a storageType', () => { + expect(() => + validator.validate( + { + deploymentType: Options.deploymentType.openshift, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + storageType: Options.storageType.ephemeral, + }, + { prodDatabaseType: NO } + ) + ).to.throw(/^Can't have the storageType option set when there is no prodDatabaseType.$/); + }); + }); + context('when the search engine is elasticsearch', () => { + it('should fail if there is a storageType', () => { + expect(() => + validator.validate( + { + deploymentType: Options.deploymentType.openshift, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + storageType: Options.storageType.ephemeral, + }, + { searchEngine: SearchEngineTypes.ELASTICSEARCH } + ) + ).to.throw(/^Can't have the storageType option set when elasticsearch is the search engine.$/); + }); + }); + context('when the monitoring is done with prometheus', () => { + it('should fail if there is a storageType', () => { + expect(() => + validator.validate({ + deploymentType: Options.deploymentType.openshift, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + storageType: Options.storageType.ephemeral, + monitoring: Options.monitoring.prometheus, + }) + ).to.throw(/^Can't have the storageType option set when the monitoring is done with prometheus.$/); + }); + }); + context('when the prodDatabaseType is set and the storageType is not set', () => { + it('should not fail', () => { + expect(() => + validator.validate( + { + deploymentType: Options.deploymentType.openshift, + appsFolders: ['beers', 'burgers'], + directoryPath: '../', + }, + { prodDatabaseType: MONGODB } + ) + ).not.to.throw(); + }); + }); + }); }); context('when passing an unknown deployment type', () => { it('should fail', () => { From 3e4a230cb54423eb32eff039badfccda70ce8a6b Mon Sep 17 00:00:00 2001 From: MathieuAA Date: Tue, 8 Jun 2021 20:23:08 +0200 Subject: [PATCH 7/7] Fixed the kubernetesStorageClassName option --- jdl/jhipster/deployment-options.js | 1 + jdl/parsing/validator.js | 5 ++- .../jhipster-deployment-exporter.spec.js | 1 + test/jdl/grammar/grammar.spec.js | 42 +++++++++++++++++++ test/jdl/jdl-importer.spec.js | 2 + test/jdl/jhipster/deployment-options.spec.js | 1 + test/jdl/test-files/deployments.jdl | 1 + 7 files changed, 51 insertions(+), 2 deletions(-) diff --git a/jdl/jhipster/deployment-options.js b/jdl/jhipster/deployment-options.js index 3ec8b97dadd..67f680547bf 100644 --- a/jdl/jhipster/deployment-options.js +++ b/jdl/jhipster/deployment-options.js @@ -104,6 +104,7 @@ Options.defaults = (deploymentType = Options.deploymentType.dockerCompose) => { kubernetesNamespace: Options.kubernetesNamespace, kubernetesServiceType: Options.kubernetesServiceType.loadBalancer, kubernetesUseDynamicStorage: Options.kubernetesUseDynamicStorage.false, + kubernetesStorageClassName: Options.kubernetesStorageClassName, ingressDomain: Options.ingressDomain, monitoring: Options.monitoring.no, istio: Options.istio.false, diff --git a/jdl/parsing/validator.js b/jdl/parsing/validator.js index 93abb807369..5472f476bab 100644 --- a/jdl/parsing/validator.js +++ b/jdl/parsing/validator.js @@ -44,6 +44,7 @@ const LANGUAGE_PATTERN = /^[a-z]+(-[A-Za-z0-9]+)*$/; const PATH_PATTERN = /^"([^\/]+).*"$/; // const PASSWORD_PATTERN = /^(.+)$/; const REPONAME_PATTERN = /^"((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:\/?#[\]@!$&'()*+,;=]+|[a-zA-Z0-9]+)"$/; +const KUBERNETES_STORAGE_CLASS_NAME = /^"[A-Za-z]*"$/; const JWT_SECRET_KEY_PATTERN = /^\S+$/; const REMEMBER_ME_KEY_PATTERN = /^\S+$/; const NUMERIC = /^\d$/; @@ -276,8 +277,8 @@ const deploymentConfigPropsValidations = { msg: 'kubernetesServiceType property', }, KUBERNETES_STORAGE_CLASS_NAME: { - type: 'NAME', - pattern: ALPHABETIC, + type: 'STRING', + pattern: KUBERNETES_STORAGE_CLASS_NAME, msg: 'kubernetesStorageClassName property', }, KUBERNETES_USE_DYNAMIC_STORAGE: { type: 'BOOLEAN' }, diff --git a/test/jdl/exporters/jhipster-deployment-exporter.spec.js b/test/jdl/exporters/jhipster-deployment-exporter.spec.js index 1de22768845..4f38e427b7e 100644 --- a/test/jdl/exporters/jhipster-deployment-exporter.spec.js +++ b/test/jdl/exporters/jhipster-deployment-exporter.spec.js @@ -133,6 +133,7 @@ describe('JHipsterDeploymentExporter', () => { kubernetesServiceType: 'LoadBalancer', monitoring: 'no', kubernetesUseDynamicStorage: false, + kubernetesStorageClassName: '', serviceDiscoveryType: 'eureka', }); }); diff --git a/test/jdl/grammar/grammar.spec.js b/test/jdl/grammar/grammar.spec.js index d9c2b42c941..15d0d5088ee 100644 --- a/test/jdl/grammar/grammar.spec.js +++ b/test/jdl/grammar/grammar.spec.js @@ -1721,4 +1721,46 @@ entity A { }); }); }); + context('when parsing deployments', () => { + context('with kubernetesStorageClassName', () => { + context('being empty', () => { + let parsedDeployment; + + before(() => { + const content = parseFromContent( + `deployment { + kubernetesStorageClassName "" +} +` + ); + parsedDeployment = content.deployments[0]; + }); + + it('should parse it', () => { + expect(parsedDeployment).to.deep.equal({ + kubernetesStorageClassName: '', + }); + }); + }); + context('being set', () => { + let parsedDeployment; + + before(() => { + const content = parseFromContent( + `deployment { + kubernetesStorageClassName "SetValue" +} +` + ); + parsedDeployment = content.deployments[0]; + }); + + it('should parse it', () => { + expect(parsedDeployment).to.deep.equal({ + kubernetesStorageClassName: 'SetValue', + }); + }); + }); + }); + }); }); diff --git a/test/jdl/jdl-importer.spec.js b/test/jdl/jdl-importer.spec.js index 6850249474e..b389066e5d8 100644 --- a/test/jdl/jdl-importer.spec.js +++ b/test/jdl/jdl-importer.spec.js @@ -1423,6 +1423,7 @@ relationship OneToOne { dockerRepositoryName: 'test', ingressDomain: '', kubernetesUseDynamicStorage: false, + kubernetesStorageClassName: 'KubernetesStorageClassName', istio: false, kubernetesNamespace: 'default', kubernetesServiceType: 'LoadBalancer', @@ -1632,6 +1633,7 @@ relationship OneToOne { dockerPushCommand: 'docker push', kubernetesNamespace: 'default', kubernetesServiceType: 'LoadBalancer', + kubernetesStorageClassName: '', ingressDomain: '', istio: false, kubernetesUseDynamicStorage: false, diff --git a/test/jdl/jhipster/deployment-options.spec.js b/test/jdl/jhipster/deployment-options.spec.js index f9f39b0ba0c..8c1cd333864 100644 --- a/test/jdl/jhipster/deployment-options.spec.js +++ b/test/jdl/jhipster/deployment-options.spec.js @@ -68,6 +68,7 @@ describe('DeploymentOptions', () => { dockerPushCommand: 'docker push', dockerRepositoryName: '', kubernetesUseDynamicStorage: false, + kubernetesStorageClassName: '', monitoring: 'no', serviceDiscoveryType: 'eureka', ingressDomain: '', diff --git a/test/jdl/test-files/deployments.jdl b/test/jdl/test-files/deployments.jdl index b5ba8e97a9f..37bb9401b5e 100644 --- a/test/jdl/test-files/deployments.jdl +++ b/test/jdl/test-files/deployments.jdl @@ -7,6 +7,7 @@ deployment { deploymentType kubernetes, appsFolders [tata, titi], dockerRepositoryName "test" + kubernetesStorageClassName "KubernetesStorageClassName" } deployment { deploymentType openshift,