Skip to content

Commit

Permalink
Merge pull request #85 from osstotalsoft/feature/tenant-config-updates
Browse files Browse the repository at this point in the history
Updates for SaaS platform
- Key Per File Configuration [@totalsoft/key-per-file-configuration](https://github.com/osstotalsoft/rocket-toolkit/tree/main/packages/key-per-file-configuration)
- Tenant configuration [@totalsoft/tenant-configuration](https://github.com/osstotalsoft/rocket-toolkit/tree/main/packages/tenant-configuration)
- Refactored multitenancy to use configuration instead of DB
- Removed ExternalTenantId
- Other minor fixes
  • Loading branch information
fraliv13 committed Jul 13, 2022
2 parents ac1c706 + d4f9892 commit 2a008b1
Show file tree
Hide file tree
Showing 42 changed files with 361 additions and 14,502 deletions.
3 changes: 3 additions & 0 deletions __tests__/answers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ describe('test package installers', () => {
const projectName = 'test-graphql'
const tempRoot = `../.tmp`
const gqlPort = '4000'
const dbConnectionName = 'testDatabase'
const messageBus = /^@totalsoft[/]message-bus/
const defaultAnswers = {
projectName,
gqlPort,
dataLayer: 'knex',
withMultiTenancy: false,
hasSharedDb: false,
dbConnectionName,
addSubscriptions: false,
addMessaging: false,
withRights: false,
Expand Down
3 changes: 3 additions & 0 deletions __tests__/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ describe('generator-graphql-rocket:app', () => {
const tempRoot = `../.tmp`
const projectName = 'test-graphql'
const helmChartName = 'test-helm'
const dbConnectionName = 'testDatabase'
const defaultAnswers = {
projectName,
gqlPort: '',
withMultiTenancy: true,
hasSharedDb: false,
dbConnectionName,
addSubscriptions: false,
addMessaging: false,
withRights: false,
Expand Down
6 changes: 5 additions & 1 deletion __tests__/installers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('test package installers', () => {
const projectName = 'test-graphql'
const tempRoot = `../.tmp`
const gqlPort = '4000'

const dbConnectionName = 'testDatabase'
const npm = '>= 7.16.0'
const yarn = '>= 1.22.4'

Expand All @@ -29,6 +29,8 @@ describe('test package installers', () => {
projectName,
gqlPort,
withMultiTenancy: true,
hasSharedDb: false,
dbConnectionName,
addSubscriptions: true,
addMessaging: false,
withRights: true,
Expand All @@ -53,6 +55,8 @@ describe('test package installers', () => {
projectName,
gqlPort,
withMultiTenancy: true,
hasSharedDb: false,
dbConnectionName,
addSubscriptions: true,
addMessaging: false,
withRights: true,
Expand Down
5 changes: 3 additions & 2 deletions generators/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module.exports = class extends Generator {
addMessaging,
addHelm,
withMultiTenancy,
hasSharedDb,
addTracing,
addGqlLogging,
withRights,
Expand Down Expand Up @@ -67,7 +68,7 @@ module.exports = class extends Generator {
ignoreFiles
)
if (dataLayer === 'knex' && withMultiTenancy)
ignoreFiles = concat(['**/multiTenancy/tenantManager.js', '**/startup/middleware'], ignoreFiles)
ignoreFiles = concat(['**/multiTenancy/tenantManager.js', '**/multiTenancy/index.js', '**/db/dbInstanceFactory.js', '**/startup/middleware'], ignoreFiles)
if (!addSubscriptions) ignoreFiles = concat(['**/pubSub/**'], ignoreFiles)
if (!addMessaging) ignoreFiles = append('**/messaging/**', ignoreFiles)

Expand All @@ -82,6 +83,7 @@ module.exports = class extends Generator {
],
ignoreFiles
)
if (!hasSharedDb) ignoreFiles = concat(['**/db/multiTenancy/tenancyFilter.js'], ignoreFiles)
if (!addTracing) ignoreFiles = concat(['**/tracing/**', '**/__mocks__/opentracing.js'], ignoreFiles)
if (!addGqlLogging) ignoreFiles = concat(['**/utils/logging.js'], ignoreFiles)
if (!withRights)
Expand All @@ -97,7 +99,6 @@ module.exports = class extends Generator {
'**/features/tenant/**',
'**/features/user/**',
'**/constants/identityUserRoles.js',
'**/multiTenancy/tenantDataSource.js',
'**/middleware/permissions/__tests__/**',
'**/README.md'
],
Expand Down
14 changes: 14 additions & 0 deletions generators/app/questions.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ module.exports = [
message: 'Would you like to use and implement multi-tenancy?',
default: false
},
{
type: 'confirm',
name: 'hasSharedDb',
when: prompts => prompts.withMultiTenancy,
message: 'Do you have a database that is shared by multiple tenants?',
default: false
},
{
type: 'input',
name: 'dbConnectionName',
when: prompts => prompts.withMultiTenancy,
message: 'What is your database connection name?',
default: 'myDatabase'
},
{
type: 'confirm',
name: 'addSubscriptions',
Expand Down
16 changes: 16 additions & 0 deletions generators/app/templates/infrastructure/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
**/.vscode
**/.git
**/.gitignore
**/Dockerfile*
**/node_modules
LICENSE
README.md
.dockerignore
.eslintrc.json
.husky
.prettierrc
coverage
GitVersion.yml
__mocks__
helm
.env.development
3 changes: 3 additions & 0 deletions generators/app/templates/infrastructure/.env
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,6 @@ PRISMA_DB_URL_PATTERN="sqlserver://{server}:{port};database={database};user={use
<%_}_%>
PRISMA_DEBUG=false
<%_}_%>
<%_ if(withMultiTenancy){ _%>
IS_MULTITENANT=false
<%_}_%>
8 changes: 8 additions & 0 deletions generators/app/templates/infrastructure/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<%_ if(withMultiTenancy){ _%>
MultiTenancy__Defaults__ConnectionStrings__MyDatabase__OtherParams=
MultiTenancy__Defaults__ConnectionStrings__MyDatabase__Server=
MultiTenancy__Tenants__tenant1__ConnectionStrings__MyDatabase__Database=
MultiTenancy__Tenants__tenant1__ConnectionStrings__MyDatabase__UserName=
MultiTenancy__Tenants__tenant1__ConnectionStrings__MyDatabase__Password=
MultiTenancy__Tenants__tenant1__TenantId=
<%_}_%>
8 changes: 6 additions & 2 deletions generators/app/templates/infrastructure/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
"request": "launch",
"name": "Program",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}\\src\\index.js"
"program": "${workspaceFolder}\\src\\index.js",
"env": {
"NODE_ENV": "development"
}
},
{
"type": "node",
Expand Down Expand Up @@ -44,7 +47,8 @@
"JAEGER_SAMPLER_PARAM": "1",
"JAEGER_REPORTER_FLUSH_INTERVAL": "100",
"JAEGER_DISABLED": "false",
"JAEGER_SERVICE_NAME": "eSigner.GraphQL"
"JAEGER_SERVICE_NAME": "eSigner.GraphQL",
"NODE_ENV": "development"
},
"program": "${workspaceFolder}\\src\\index.js"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
const opentracing = jest.genMockFromModule('opentracing');
const opentracing = jest.createMockFromModule('opentracing');

opentracing.globalTracer = jest.fn().mockReturnValue({
startSpan: jest.fn().mockReturnValue({
log: jest.fn(),
setTag: jest.fn(),
finish: jest.fn()
}),
finish: jest.fn()
finish: jest.fn(),
extract: jest.fn()
});

module.exports = opentracing;
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,10 @@ metadata:
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
<%_ if(addTracing){ _%>
{{- if and (eq $global.jaeger.enabled true) (eq $global.jaeger.agentAutoInject true) }}
{{- if $global.jaeger.enabled | and $global.jaeger.agentAutoInject }}
annotations:
"sidecar.jaegertracing.io/inject": "true"
{{- else }}
annotations:
"sidecar.jaegertracing.io/inject": "false"
sidecar.jaegertracing.io/inject: "true"
{{- end }}
<%_} else {_%>
annotations:
"sidecar.jaegertracing.io/inject": "false"
<%_}_%>
spec:
replicas: {{ $current.replicaCount }}
Expand Down Expand Up @@ -60,7 +54,7 @@ spec:
{{- end }}
containers:
- name: {{ $current.name }}
image: "{{ $current.image.repository }}{{ $current.image.name}}:{{ $current.image.tag }}"
image: "{{ $current.image.repository }}{{ $current.image.name}}:{{ $current.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ $current.image.pullPolicy }}
ports:
- name: http
Expand All @@ -84,7 +78,7 @@ spec:
value: {{ $global.db.password | quote }}
<%_ if(addVaultConfigs){ _%>
{{- end }}
<%_}_%>
<%_}_%>
- name: DB_INSTANCE_NAME
value: {{ $global.db.instanceName | quote }}
- name: DB_TRUST_SERVER_CERTIFICATE
Expand Down Expand Up @@ -137,8 +131,17 @@ spec:
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- if $global.runtimeConfiguration.enabled }}
volumeMounts:
- name: runtime-configs
readOnly: true
mountPath: /usr/src/app/runtime/configs
- name: runtime-secrets
readOnly: true
mountPath: /usr/src/app/runtime/secrets
{{- end }}
<%_ if(addTracing){ _%>
{{- if and (eq $global.jaeger.enabled true) (eq $global.jaeger.agentAutoInject false) }}
{{- if $global.jaeger.enabled | and (not $global.jaeger.agentAutoInject) }}
- image: jaegertracing/jaeger-agent:{{ $global.jaeger.agentImageTag }}
name: jaeger-agent{{ $current.nameSuffix}}
ports:
Expand All @@ -157,6 +160,19 @@ spec:
imagePullSecrets:
{{- toYaml $global.imagePullSecrets | trim | nindent 8 }}
{{- end }}
{{- if $global.runtimeConfiguration.enabled }}
volumes:
- name: runtime-configs
configMap:
name: {{ $global.runtimeConfiguration.configMap }}
defaultMode: 420
- name: runtime-secrets
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: {{ $global.runtimeConfiguration.csi.secretProviderClass }}
{{- end }}
{{- with $current.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ metadata:
labels:
app.kubernetes.io/name: {{ include "Gql.fullname" . }}
helm.sh/chart: {{ include "Gql.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
type: {{ $current.service.type }}
Expand All @@ -21,6 +21,5 @@ spec:
nodePort: {{ $current.service.nodePort }}
{{- end }}
selector:
app.kubernetes.io/name: {{ $current.name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{- include "Gql.selectorLabels" . | nindent 4 }}
{{- end -}}
11 changes: 10 additions & 1 deletion generators/app/templates/infrastructure/helm/gql/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ global:
key: key
<%_}_%>

runtimeConfiguration:
enabled: false
configMap: <%= helmChartName %>-runtime-config
csi:
secretProviderClass: <%= helmChartName %>-runtime-secrets

<%_ if(addTracing){ _%>
jaeger:
enabled: true
Expand Down Expand Up @@ -61,7 +67,7 @@ gql:
repository: "[ORGANIZATION].azurecr.io/"
pullPolicy: IfNotPresent
name: <%= helmChartName %>
tag: latest # overwrite from pipeline
tag: "" # overwrite from pipeline

service:
type: ClusterIP
Expand Down Expand Up @@ -90,6 +96,9 @@ gql:
IDENTITY_AUTHORITY: "[IDENTITY_AUTHORITY_URL]"
<%_ if(addGqlLogging){ _%>
APOLLO_LOGGING_LEVEL: "DEBUG"
<%_}_%>
<%_ if(withMultiTenancy){ _%>
IS_MULTITENANT: "false"
<%_}_%>
KNEX_LOGGING: "true"
PORT: "4000"
Expand Down
6 changes: 4 additions & 2 deletions generators/app/templates/infrastructure/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"<%=packageManager%>": ">= <%= packageManagerVersion %>"
},
"scripts": {
"start": "nodemon src/index.js",
"start": "cross-env NODE_ENV=development nodemon src/index.js",
"start:production": "cross-env NODE_ENV=production node src/index.js",
"test": "jest --collectCoverage --passWithNoTests",
"test:watchAll": "<%=packageManager%> run test -- --watchAll",
Expand All @@ -36,19 +36,21 @@
"lodash.set": "^4.3.2",
<%_} _%>
<%_} _%>
"@totalsoft/key-per-file-configuration": "1.0.0",
<%_ if(withMultiTenancy) {_%>
"object-path": "^0.11.8",
"koa-ignore": "^1.0.1",
<%_ if(addQuickStart) {_%>
"datasource-sql": "^2.0.1",
<%_}_%>
"@totalsoft/tenant-configuration": "1.0.0",
<%_}_%>
<%_ if(dataLayer === "knex") {_%>
"dataloader": "^2.1.0",
"knex-tiny-logger": "^2.1.0",
"mssql": "^8.1.2",
"knex": "^0.95.0",
<%_ if(withMultiTenancy) {_%>
<%_ if(withMultiTenancy && hasSharedDb) {_%>
"@totalsoft/knex-filters": "^2.4.1",
<%_} _%>
<%_}_%>
Expand Down
26 changes: 14 additions & 12 deletions generators/app/templates/infrastructure/src/db/dbConfigService.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { postProcessDbResponse<% if(withMultiTenancy){ %>, parseConnectionString <%}%>} = require("../utils/functions");
const { postProcessDbResponse, sanitizeConnectionInfo} = require("../utils/functions")
<%_ if(withMultiTenancy){ _%>
const { tenantConfiguration } = require("../multiTenancy");
const { tenantConfiguration } = require('@totalsoft/tenant-configuration')
const isMultiTenant = JSON.parse(process.env.IS_MULTITENANT || 'false')
<%_}_%>

const generateKnexConfig = ({
Expand All @@ -21,7 +22,7 @@ const generateKnexConfig = ({
database,
options: {
enableArithAbort: true,
trustServerCertificate: JSON.parse(trustServerCertificate),
trustServerCertificate: JSON.parse(trustServerCertificate?.trim().toLowerCase() || 'false'),
encrypt: true,
instanceName: instanceName || undefined
}
Expand All @@ -41,15 +42,13 @@ const generateKnexConfig = ({

const getDbConfig = <% if(withMultiTenancy){ %>async ( tenantId )<%} else { %>()<%}%> => {
<%_ if(withMultiTenancy){ _%>
const tenantDsInfo = await tenantConfiguration.getDataSourceInfo(tenantId);
let connectionInfo

if (tenantDsInfo) {
if (!tenantDsInfo.isSharedDb && !tenantDsInfo.connectionInfo)
throw new Error(`Could not find database configuration info for tenant id: ${tenantId}`)
if (isMultiTenant) {
connectionInfo = await tenantConfiguration.getConnectionInfo(tenantId, '<%= dbConnectionName %>')

const connection = parseConnectionString(tenantDsInfo.connectionInfo);
const dbConfig = generateKnexConfig(connection)
return [dbConfig, tenantDsInfo.isSharedDb]
if (!connectionInfo)
throw new Error(`Could not find database configuration info for tenant id: ${tenantId}`)
} else {
<%_}_%>
const {
Expand All @@ -62,11 +61,14 @@ const getDbConfig = <% if(withMultiTenancy){ %>async ( tenantId )<%} else { %>()
DB_TRUST_SERVER_CERTIFICATE: trustServerCertificate
} = process.env

const dbConfig = generateKnexConfig({ server, port, userId, password, database, instanceName, trustServerCertificate })
return [dbConfig, true]
connectionInfo = { server, port, userId, password, database, instanceName, trustServerCertificate }
<%_ if(withMultiTenancy){ _%>
}
<%_}_%>

connectionInfo = sanitizeConnectionInfo(connectionInfo)
const dbConfig = generateKnexConfig(connectionInfo)
return dbConfig
}

module.exports = { getDbConfig, generateKnexConfig }
Loading

0 comments on commit 2a008b1

Please sign in to comment.