MinIO support for Admin UI (#2248)

Add support for MinIO creation form and list
This commit is contained in:
Carlos Alcaide Corvo authored and GitHub committed 2024-04-16 14:17:23 -07:00
1 parent 98c16ad422
commit 0870a8f623
26 files changed
+1332 -597

No files matched your search

@@ -73,6 +73,12 @@ export default class GeneratedStorageBucketModel extends BaseModel {
})
region;
@attr('string', {
isNestedAttribute: true,
description: 'The MinIO location server.',
})
endpoint_url;
//this field is not used in the UI, but this is kept here to replicate the API
@attr('string', {
readOnly: true,
+10
View File
@@ -9,8 +9,10 @@ export const TYPE_STORAGE_BUCKET_PLUGIN = 'plugin';
export const TYPES_STORAGE_BUCKET = Object.freeze([TYPE_STORAGE_BUCKET_PLUGIN]);
export const TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3 = 'aws';
export const TYPE_STORAGE_BUCKET_PLUGIN_MINIO = 'minio';
export const TYPES_STORAGE_BUCKET_PLUGIN = Object.freeze([
TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
TYPE_STORAGE_BUCKET_PLUGIN_MINIO,
]);
export const TYPE_CREDENTIAL_STATIC = 'static';
@@ -75,6 +77,14 @@ export default class StorageBucketModel extends GeneratedStorageBucketModel {
return this.compositeType === TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3;
}
/**
* True if the storage bucket plugin type is MinIO
* @type {boolean}
*/
get isMinIO() {
return this.compositeType === TYPE_STORAGE_BUCKET_PLUGIN_MINIO;
}
/**
* If the storage bucket is a plugin return `plugin.name`,
* otherwise return the storage bucket type.
+37 -6
View File
@@ -4,7 +4,10 @@
*/
import ApplicationSerializer from './application';
import { TYPE_CREDENTIAL_DYNAMIC } from '../models/storage-bucket';
import {
TYPE_CREDENTIAL_DYNAMIC,
TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
} from '../models/storage-bucket';
const fieldsByCredentialType = {
static: [
@@ -12,27 +15,55 @@ const fieldsByCredentialType = {
'secret_access_key',
'region',
'disable_credential_rotation',
'endpoint_url',
],
dynamic: [
'role_arn',
'role_external_id',
'role_session_name',
'role_tags',
'disable_credential_rotation',
'region',
'disable_credential_rotation',
'endpoint_url',
],
};
export default class StorageBucketSerializer extends ApplicationSerializer {
/**
* Serializes storage-bucket. ATM just AWS needs specific serialization,
* for the other plugin types use default.
* @param {object} snapshot
* @returns
*/
serialize(snapshot) {
const serialized = super.serialize(...arguments);
const { credentialType } = snapshot.record;
const pluginType = snapshot.record.plugin?.name;
const serialized = super.serialize(...arguments);
// Common for all pluginTypes
if (!snapshot.record.isNew) {
delete serialized.bucket_name;
delete serialized.bucket_prefix;
}
if (credentialType === TYPE_CREDENTIAL_DYNAMIC) {
serialized.attributes.disable_credential_rotation = true;
if (pluginType === TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3) {
return this.serializeAws(serialized, credentialType);
}
return serialized;
}
/**
* Returns a storage bucket serialized object specific for aws
* @param {object} serialized
* @param {string} credentialType
* @returns
*/
serializeAws(serialized, credentialType) {
if (serialized.attributes) {
if (credentialType === TYPE_CREDENTIAL_DYNAMIC) {
serialized.attributes.disable_credential_rotation = true;
}
delete serialized.attributes.endpoint_url;
}
return serialized;
}
@@ -45,7 +76,7 @@ export default class StorageBucketSerializer extends ApplicationSerializer {
if (options.isNestedAttribute && json.attributes) {
// The key must be included in the fieldsByType list above
if (!fieldsByCredentialType[credentialType].includes(key))
//API requires these fields to be null
// API requires these fields to be null
json.attributes[key] = null;
}
@@ -11,6 +11,7 @@ import {
TYPES_STORAGE_BUCKET as types,
TYPES_STORAGE_BUCKET_PLUGIN,
TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
TYPE_STORAGE_BUCKET_PLUGIN_MINIO,
} from 'api/models/storage-bucket';
// Represents known plugin types, except "foobar" which models the possibility
@@ -50,6 +51,10 @@ export default factory.extend({
)}`,
disable_credential_rotation: faker.datatype.boolean(),
};
case TYPE_STORAGE_BUCKET_PLUGIN_MINIO:
return {
endpoint_url: faker.internet.url(),
};
}
},
});
@@ -7,6 +7,7 @@ import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import {
TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
TYPE_STORAGE_BUCKET_PLUGIN_MINIO,
TYPE_STORAGE_BUCKET_PLUGIN,
TYPE_CREDENTIAL_STATIC,
TYPE_CREDENTIAL_DYNAMIC,
@@ -15,15 +16,6 @@ import {
module('Unit | Serializer | storage bucket', function (hooks) {
setupTest(hooks);
test('it serializes records', function (assert) {
let store = this.owner.lookup('service:store');
let record = store.createRecord('storage-bucket', {});
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});
test('it serializes a new static aws plugin as expected', async function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('storage-bucket', {
@@ -70,6 +62,47 @@ module('Unit | Serializer | storage bucket', function (hooks) {
assert.deepEqual(record.serialize(), expectedResult);
});
test('it serializes a new minio (static by default) plugin as expected', async function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('storage-bucket', {
compositeType: TYPE_STORAGE_BUCKET_PLUGIN_MINIO,
credentialType: TYPE_CREDENTIAL_STATIC,
name: 'minio',
description: 'this has a minio plugin',
bucket_name: 'bucketname',
bucket_prefix: 'bucketprefix',
worker_filter: 'workerfilter',
endpoint_url: 'http://hashicorp.com',
region: 'eu-west-1',
access_key_id: 'foobars',
secret_access_key: 'testing',
disable_credential_rotation: true,
});
const expectedResult = {
name: 'minio',
description: 'this has a minio plugin',
type: TYPE_STORAGE_BUCKET_PLUGIN,
bucket_name: 'bucketname',
bucket_prefix: 'bucketprefix',
worker_filter: 'workerfilter',
attributes: {
region: 'eu-west-1',
disable_credential_rotation: true,
endpoint_url: 'http://hashicorp.com',
role_arn: null,
role_external_id: null,
role_session_name: null,
role_tags: null,
secrets_hmac: null,
},
secrets: {
access_key_id: 'foobars',
secret_access_key: 'testing',
},
};
assert.deepEqual(record.serialize(), expectedResult);
});
test('it serializes a new aws plugin with dynamic credentials as expected', async function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('storage-bucket', {
@@ -126,6 +159,7 @@ module('Unit | Serializer | storage bucket', function (hooks) {
bucket_name: 'bucketname',
bucket_prefix: 'bucketprefix',
worker_filter: 'workerfilter',
plugin: { name: 'aws' },
region: 'eu-west-1',
access_key_id: 'foobars',
secret_access_key: 'testing',
@@ -183,6 +217,7 @@ module('Unit | Serializer | storage bucket', function (hooks) {
bucket_name: 'bucketname',
bucket_prefix: 'bucketprefix',
worker_filter: 'workerfilter',
plugin: { name: 'aws' },
region: 'eu-west-1',
disable_credential_rotation: true,
access_key_id: 'test',
@@ -222,6 +257,61 @@ module('Unit | Serializer | storage bucket', function (hooks) {
assert.deepEqual(serializedRecord, expectedResult);
});
test('it serializes when updating a MinIO (static credential by default) storage bucket correctly', async function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('storage-bucket');
store.push({
data: {
id: '3',
type: 'storage-bucket',
attributes: {
type: TYPE_STORAGE_BUCKET_PLUGIN,
plugin: { name: 'minio' },
name: 'minio',
description: 'this has a minio plugin',
bucket_name: 'bucketname',
bucket_prefix: 'bucketprefix',
worker_filter: 'workerfilter',
endpoint_url: 'http://hashicorp.com',
region: 'eu-west-1',
disable_credential_rotation: true,
access_key_id: 'test',
secret_access_key: 'test',
version: 1,
},
},
});
const record = store.peekRecord('storage-bucket', '3');
record.description = 'This is new description';
record.name = 'This is the new name';
record.endpoint_url = 'http://developer.hashicorp.com';
const snapshot = record._createSnapshot();
const serializedRecord = serializer.serialize(snapshot);
const expectedResult = {
name: 'This is the new name',
description: 'This is new description',
type: TYPE_STORAGE_BUCKET_PLUGIN,
worker_filter: 'workerfilter',
attributes: {
region: 'eu-west-1',
disable_credential_rotation: true,
endpoint_url: 'http://developer.hashicorp.com',
role_arn: null,
role_external_id: null,
role_session_name: null,
role_tags: null,
secrets_hmac: null,
},
secrets: {
access_key_id: 'test',
secret_access_key: 'test',
},
version: 1,
};
assert.deepEqual(serializedRecord, expectedResult);
});
test('it normalizes correctly', function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('storage-bucket');