Skip to content

Commit

Permalink
Update manage filers page (#215)
Browse files Browse the repository at this point in the history
* removed static file to call master filer list

* updates manage filers page to use new configmaps

* now adding label and annotation to requesting CM
  • Loading branch information
mathis-marcotte authored Oct 4, 2024
1 parent dd129c8 commit 8f9e427
Show file tree
Hide file tree
Showing 8 changed files with 347 additions and 5,017 deletions.
120 changes: 75 additions & 45 deletions components/centraldashboard/app/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ export const ERRORS = {
invalid_links_config: 'Cannot load dashboard menu link',
invalid_settings: 'Cannot load dashboard settings',
invalid_get_filers: 'Failed to load filers',
invalid_get_user_filers: 'Failed to load user filers',
invalid_update_filer: 'Failed to update filers'
invalid_get_existing_shares: 'Failed to load existing shares',
invalid_get_requesting_shares: 'Failed to load requesting shares',
invalid_create_requesting_shares: 'Failed to create requesting shares configmap',
invalid_update_requesting_shares: 'Failed to update requesting shares configmap',
invalid_update_existing_shares: 'Failed to update existing shares configmap',
invalid_delete_existing_shares: 'Failed to delete existing shares configmap'
};

export function apiError(a: {res: Response, error: string, code?: number}) {
Expand Down Expand Up @@ -107,71 +111,97 @@ export class Api {
})
.get(
'/filers',
async (req: Request, res: Response) => {
try{
const filePath = resolve('./filerShares.json');
const contents = await readFile(filePath, {encoding: 'utf8'});
const filers = JSON.parse(contents);
res.json(filers);
async (_: Request, res: Response) => {
const cm = await this.k8sService.getFilersListConfigMap();
let filers = [];
try {
filers=JSON.parse(cm.data["filers"]);
}catch(e){
return apiError({
res, code: 500,
error: ERRORS.invalid_get_filers,
});
res, code: 500,
error: ERRORS.invalid_get_filers,
});
}
res.json(filers);
})
.post(
'/create-filer/:namespace',
.post(
'/create-requesting-shares/:namespace',
async (req: Request, res: Response) => {
try {
const cm = await this.k8sService.createUserFilerConfigMap(req.params.namespace, req.body);
const cm = await this.k8sService.createRequestingSharesConfigMap(req.params.namespace, req.body, req.user.email);
res.json(cm.data);
}catch(e){
return apiError({
res, code: 500,
error: ERRORS.invalid_update_filer,
error: ERRORS.invalid_create_requesting_shares,
});
}
})
.get(
'/get-filer/:namespace',
async (req: Request, res: Response) => {
.get(
'/get-existing-shares/:namespace',
async (req: Request, res: Response) => {
try {
const cm = await this.k8sService.getExistingSharesConfigMap(req.params.namespace);
res.json(cm.data);
}catch(e){
return apiError({
res, code: 500,
error: ERRORS.invalid_get_existing_shares,
});
}
})
.get(
'/get-requesting-shares/:namespace',
async (req: Request, res: Response) => {
try {
const cm = await this.k8sService.getUserFilerConfigMap(req.params.namespace);
res.json(cm.data);
const cm = await this.k8sService.getRequestingSharesConfigMap(req.params.namespace);
res.json(cm.data);
}catch(e){
return apiError({
res, code: 500,
error: ERRORS.invalid_get_user_filers,
});
return apiError({
res, code: 500,
error: ERRORS.invalid_get_requesting_shares,
});
}
})
.patch(
'/update-filer/:namespace',
async (req: Request, res: Response) => {
})
.patch(
'/update-requesting-shares/:namespace',
async (req: Request, res: Response) => {
try {
const cm = await this.k8sService.updateUserFilerConfigMap(req.params.namespace, req.body);
res.json(cm.data);
const cm = await this.k8sService.updateRequestingSharesConfigMap(req.params.namespace, req.body, req.user.email);
res.json(cm.data);
}catch(e){
return apiError({
res, code: 500,
error: ERRORS.invalid_update_filer,
});
return apiError({
res, code: 500,
error: ERRORS.invalid_update_requesting_shares,
});
}
})
.patch(
'/update-existing-shares/:namespace',
async (req: Request, res: Response) => {
try {
const cm = await this.k8sService.updateExistingSharesConfigMap(req.params.namespace, req.body);
res.json(cm.data);
}catch(e){
return apiError({
res, code: 500,
error: ERRORS.invalid_update_existing_shares,
});
}
})
.delete(
'/delete-filer/:namespace',
async (req: Request, res: Response) => {
try {
await this.k8sService.deleteUserFilerConfigMap(req.params.namespace);
})
.delete(
'/delete-existing-shares/:namespace',
async (req: Request, res: Response) => {
try {
await this.k8sService.deleteExistingSharesConfigMap(req.params.namespace);
res.json({});
}catch(e){
}catch(e){
return apiError({
res, code: 500,
error: ERRORS.invalid_update_filer,
res, code: 500,
error: ERRORS.invalid_delete_existing_shares,
});
}
});
}
});
}

resolveLanguage(requested: string[], supported: string[], defaultLang: string) {
Expand Down
86 changes: 71 additions & 15 deletions components/centraldashboard/app/k8s_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ interface V1BetaApplicationList {
const APP_API_GROUP = 'app.k8s.io';
const APP_API_VERSION = 'v1beta1';
const APP_API_NAME = 'applications';
const USER_FILERS_CM_NAME = 'user-filers';
const REQUESTING_SHARES_CM_NAME = 'requesting-shares';
const EXISTING_SHARES_CM_NAME = 'existing-shares';

/** Wrap Kubernetes API calls in a simpler interface for use in routes. */
export class KubernetesService {
Expand Down Expand Up @@ -106,27 +107,59 @@ export class KubernetesService {
}
}

/** Creates the user filers configmap for the central dashboard. */
async createUserFilerConfigMap(namespace: string, data: {[key:string]:string}): Promise<k8s.V1ConfigMap> {
/** Retrieves the configmap data for the list of filers. */
async getFilersListConfigMap(): Promise<k8s.V1ConfigMap> {
try {
const { body } = await this.coreAPI.readNamespacedConfigMap("filers-list", "das");
return body;
} catch (err) {
console.error('Unable to fetch fielrs list ConfigMap:', err.response?.body || err.body || err);
return null;
}
}

/** Creates the requesting shares configmap for the central dashboard. */
async createRequestingSharesConfigMap(namespace: string, data: {[key:string]:string}, email: string): Promise<k8s.V1ConfigMap> {
try {
const config = {
metadata: {
name: USER_FILERS_CM_NAME
name: REQUESTING_SHARES_CM_NAME,
labels: {
"for-ontap": "true"
},
annotations: {
"user-email": email
}
},
data
} as k8s.V1ConfigMap;
const { body } = await this.coreAPI.createNamespacedConfigMap(namespace, config);
return body;
} catch (err) {
console.error('Unable to create ConfigMap:', err.response?.body || err.body || err);
console.error('Unable to create requesting shares ConfigMap:', err.response?.body || err.body || err);
throw err;
}
}

/** Retrieves the existing shares configmap data for the central dashboard. */
async getExistingSharesConfigMap(namespace: string): Promise<k8s.V1ConfigMap> {
try {
const { body } = await this.coreAPI.readNamespacedConfigMap(EXISTING_SHARES_CM_NAME, namespace);
return body;
} catch (err) {
if(err.statusCode === 404){
//user has no user-filers yet
return new k8s.V1ConfigMap();
}
console.error('Unable to fetch ConfigMap:', err.response?.body || err.body || err);
throw err;
}
}

/** Retrieves the user filers configmap data for the central dashboard. */
async getUserFilerConfigMap(namespace: string): Promise<k8s.V1ConfigMap> {
/** Retrieves the requesting shares configmap data for the central dashboard. */
async getRequestingSharesConfigMap(namespace: string): Promise<k8s.V1ConfigMap> {
try {
const { body } = await this.coreAPI.readNamespacedConfigMap(USER_FILERS_CM_NAME, namespace);
const { body } = await this.coreAPI.readNamespacedConfigMap(REQUESTING_SHARES_CM_NAME, namespace);
return body;
} catch (err) {
if(err.statusCode === 404){
Expand All @@ -138,27 +171,50 @@ export class KubernetesService {
}
}

/** Updates the user filers configmap for the central dashboard. */
async updateUserFilerConfigMap(namespace: string, data: {[key:string]:string}): Promise<k8s.V1ConfigMap> {
/** Updates the requesting shares configmap for the central dashboard. */
async updateRequestingSharesConfigMap(namespace: string, data: {[key:string]:string}, email: string): Promise<k8s.V1ConfigMap> {
try {
const config = {
metadata: {
name: REQUESTING_SHARES_CM_NAME,
labels: {
"for-ontap": "true"
},
annotations: {
"user-email": email
}
},
data
} as k8s.V1ConfigMap;
const { body } = await this.coreAPI.replaceNamespacedConfigMap(REQUESTING_SHARES_CM_NAME, namespace, config);
return body;
} catch (err) {
console.error('Unable to patch ConfigMap:', err.response?.body || err.body || err);
throw err;
}
}

/** Updates the existing shares configmap for the central dashboard. */
async updateExistingSharesConfigMap(namespace: string, data: {[key:string]:string}): Promise<k8s.V1ConfigMap> {
try {
const config = {
metadata: {
name: USER_FILERS_CM_NAME
name: EXISTING_SHARES_CM_NAME
},
data
} as k8s.V1ConfigMap;
const { body } = await this.coreAPI.replaceNamespacedConfigMap(USER_FILERS_CM_NAME, namespace, config);
const { body } = await this.coreAPI.replaceNamespacedConfigMap(EXISTING_SHARES_CM_NAME, namespace, config);
return body;
} catch (err) {
console.error('Unable to patch ConfigMap:', err.response?.body || err.body || err);
throw err;
}
}

/** Deletes the user filers configmap for the central dashboard. */
async deleteUserFilerConfigMap(namespace: string): Promise<k8s.V1Status> {
/** Deletes the existing shares configmap for the central dashboard. */
async deleteExistingSharesConfigMap(namespace: string): Promise<k8s.V1Status> {
try {
const { body } = await this.coreAPI.deleteNamespacedConfigMap(USER_FILERS_CM_NAME, namespace);
const { body } = await this.coreAPI.deleteNamespacedConfigMap(EXISTING_SHARES_CM_NAME, namespace);
return body;
} catch (err) {
console.error('Unable to delete ConfigMap:', err.response?.body || err.body || err);
Expand Down
Loading

0 comments on commit 8f9e427

Please sign in to comment.