Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions packages/db/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Context, getInternalEndpoint } from '@osaas/client-core';
import { getApacheCouchdbInstance } from '@osaas/client-services';
import { setupDatabase } from '.';

jest.mock('@osaas/client-core', () => {
return {
getInternalEndpoint: jest.fn(),
getPortsForInstance: jest.fn(),
Context: jest.fn().mockImplementation(() => {
return {
getServiceAccessToken: jest.fn().mockResolvedValue('token')
};
})
};
});

jest.mock('@osaas/client-services', () => {
return {
getApacheCouchdbInstance: jest.fn(),
createApacheCouchdbInstance: jest.fn()
};
});

describe('setupDatabase couchdb', () => {
afterEach(() => {
jest.clearAllMocks();
});

it('returns an http:// URL for a private (publicAccess: false) instance', async () => {
(getApacheCouchdbInstance as jest.Mock).mockResolvedValue({
name: 'myinstance',
url: 'https://myinstance.apache-couchdb.auto.dev.osaas.io',
AdminPassword: 'secret'
});
(getInternalEndpoint as jest.Mock).mockResolvedValue({
serviceDns: 'myinstance.apache-couchdb.svc.cluster.local',
ports: [{ name: 'couchdb', port: 5984, protocol: 'TCP' }],
publicAccess: false
});

const ctx = new Context();
const url = await setupDatabase(ctx, 'couchdb', 'myinstance', {
rootPassword: 'secret',
publicAccess: false
});

expect(url).toMatch(/^http:\/\//);
expect(url).toBe(
'http://admin:secret@myinstance.apache-couchdb.svc.cluster.local:5984'
);
});

it('returns an https:// URL for a public instance', async () => {
(getApacheCouchdbInstance as jest.Mock).mockResolvedValue({
name: 'myinstance',
url: 'https://myinstance.apache-couchdb.auto.dev.osaas.io',
AdminPassword: 'secret'
});

const ctx = new Context();
const url = await setupDatabase(ctx, 'couchdb', 'myinstance', {
rootPassword: 'secret'
});

expect(url).toMatch(/^https:\/\//);
expect(getInternalEndpoint).not.toHaveBeenCalled();
});
});
18 changes: 17 additions & 1 deletion packages/db/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ export const DatabaseTypeToProtocol: Record<DatabaseType, string> = {
couchdb: 'https'
};

/**
* Protocol to use when connecting to the *internal* (cluster-local) endpoint
* of a database, as opposed to its public ingress URL.
*
* This only needs an entry for database types whose `DatabaseTypeToProtocol`
* value is not valid for the raw container port. CouchDB's public URL is
* HTTPS (TLS terminated at the ingress on port 443), but its internal
* container port (5984) speaks plaintext HTTP - there is no in-cluster TLS
* termination on that port. Other database types use non-HTTP schemes
* (postgres://, mysql://, redis://, clickhouse://) for both paths and are
* unaffected.
*/
const DatabaseTypeToInternalProtocol: Partial<Record<DatabaseType, string>> = {
couchdb: 'http'
};

export interface DatabaseOpts {
username?: string;
password?: string;
Expand Down Expand Up @@ -259,7 +275,7 @@ export async function setupDatabase(
(p) => p.port === DatabaseTypeToPort['couchdb']
);
if (port) {
return `${DatabaseTypeToProtocol['couchdb']}://admin:${
return `${DatabaseTypeToInternalProtocol['couchdb']}://admin:${
(instance as any).AdminPassword
}@${endpointInfo.serviceDns}:${port.port}`;
}
Expand Down
Loading