Skip to content

Commit

Permalink
Merge pull request #364 from richard-cox/fix-make-ns-agnostic
Browse files Browse the repository at this point in the history
Make UI agnostic of epinio's namespace and other improvements
  • Loading branch information
richard-cox authored Nov 27, 2023
2 parents a478b7a + e114983 commit af846fe
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 31 deletions.
2 changes: 2 additions & 0 deletions dashboard/pkg/epinio/l10n/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ epinio:
label: Redeploy
goToEpinio:
label: Epinio App
viewDeployment:
label: View In Kube Cluster
wm:
containerName: 'Instance: {label}'
noData: There are no log entries to show.
Expand Down
70 changes: 63 additions & 7 deletions dashboard/pkg/epinio/models/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
import { createEpinioRoute } from '../utils/custom-routing';
import EpinioNamespacedResource, { bulkRemove } from './epinio-namespaced-resource';
import { AppUtils } from '../utils/application';
import { WORKLOAD_TYPES } from '@shell/config/types';
import { NAME as EXPLORER } from '@shell/config/product/explorer';

// See https://github.com/epinio/epinio/blob/00684bc36780a37ab90091498e5c700337015a96/pkg/api/core/v1/models/app.go#L11
const STATES = {
Expand Down Expand Up @@ -106,7 +108,7 @@ export default class EpinioApplicationModel extends EpinioNamespacedResource {
res.push({
action: 'showAppShell',
label: this.t('epinio.applications.actions.shell.label'),
icon: 'icon icon-fw icon-chevron-right',
icon: 'icon icon-fw icon-terminal',
enabled: showAppShell,
});
}
Expand All @@ -125,10 +127,6 @@ export default class EpinioApplicationModel extends EpinioNamespacedResource {
},
);

if (showAppShell || showAppLog || showStagingLog) {
res.push({ divider: true });
}

res.push( {
action: 'restage',
label: this.t('epinio.applications.actions.restage.label'),
Expand All @@ -141,16 +139,28 @@ export default class EpinioApplicationModel extends EpinioNamespacedResource {
icon: 'icon icon-fw icon-refresh',
enabled: isRunning
},
{ divider: true },
{
action: 'exportApp',
label: this.t('epinio.applications.export.label'),
icon: 'icon icon-fw icon-download',
enabled: isRunning
},
{ divider: true },
);

...super._availableActions);
if (this.canViewDeployment) {
res.push({
action: 'viewDeployment',
label: this.t('epinio.applications.actions.viewDeployment.label'),
icon: 'icon icon-fw icon-chevron-right',
},
{ divider: true },
);
}

res.push(
...super._availableActions
);

return res;
}
Expand Down Expand Up @@ -448,6 +458,52 @@ export default class EpinioApplicationModel extends EpinioNamespacedResource {
return 'export';
}

get canViewDeployment() {
return !this.$rootGetters['isSingleProduct'] && !!this.$getters[`schemaFor`](WORKLOAD_TYPES.DEPLOYMENT);
}

/**
* Attempt to view the deployment for this namespace in Rancher's UI
*
* If we can't find the deployment, just go to the deployment list with the name in the filter
*/
viewDeployment() {
const clusterId = this.$rootGetters['clusterId'];
const namespace = this.metadata.namespace;
const appName = this.metadata.name;
const url = `/k8s/clusters/${ clusterId }/v1/apps.deployments/${ namespace }?labelSelector=app.kubernetes.io/component%3Dapplication,app.kubernetes.io/name%3D${ appName }`;

const deploymentList = {
name: `c-cluster-product-resource`,
params: {
product: EXPLORER,
cluster: clusterId,
resource: WORKLOAD_TYPES.DEPLOYMENT,
},
query: { q: this.metadata.name }
};

this.$dispatch(`cluster/request`, { url }, { root: true })
.then((deployments) => {
if (deployments?.data?.length === 1) {
const deployment = deployments.data[0];

this.currentRouter().push({
name: `c-cluster-product-resource-namespace-id`,
params: {
...deploymentList.params,
namespace: deployment.metadata.namespace,
id: deployment.metadata.name,
}
});
} else {
this.currentRouter().push(deploymentList);
}
}).catch(() => {
this.currentRouter().push(deploymentList);
});
}

// ------------------------------------------------------------------
// Change/handle changes of the app

Expand Down
3 changes: 3 additions & 0 deletions dashboard/pkg/epinio/models/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default class EpinioCluster extends Resource {

id: string;
name: string;
namespace: string;
state?: string;
metadata?: { state: { transitioning: boolean, error: boolean, message: string }};
loggedIn: boolean;
Expand All @@ -20,13 +21,15 @@ export default class EpinioCluster extends Resource {
constructor(data: {
id: string,
name: string,
namespace: string,
loggedIn: boolean,
api: string,
mgmtCluster: any,
}, ctx: any) {
super(data, ctx);
this.id = data.id;
this.name = data.name;
this.namespace = data.namespace;
this.api = data.api;
this.loggedIn = data.loggedIn;
this.mgmtCluster = data.mgmtCluster;
Expand Down
21 changes: 11 additions & 10 deletions dashboard/pkg/epinio/pages/c/_cluster/dashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,6 @@ export default Vue.extend<any, any, any, any>({
this.sectionContent[2].isLoaded = true;
this.sectionContent[2].isEnable = true;
}
},
openMetricsDetails() {
this.$router.replace({
name: 'c-cluster-explorer',
params: { cluster: this.$store.getters['clusterId'] }
});
}
},
computed: {
Expand Down Expand Up @@ -206,6 +200,12 @@ export default Vue.extend<any, any, any, any>({
return { totalNamespaces: allNamespaces.length, latestNamespaces: sortBy(allNamespaces, 'metadata.createdAt').reverse().slice(0, 2) };
},
metricsDetails() {
return {
name: 'c-cluster-explorer',
params: { cluster: this.$store.getters['clusterId'] }
};
}
},
});
</script>
Expand Down Expand Up @@ -254,10 +254,11 @@ export default Vue.extend<any, any, any, any>({
<span>
{{ t('epinio.intro.metrics.availability', { availableCpu, availableMemory }) }}
</span>
<a
class="cluster-link"
@click="openMetricsDetails"
>{{ t('epinio.intro.metrics.link.label') }}</a>
<n-link
:to="metricsDetails"
>
{{ t('epinio.intro.metrics.link.label') }}
</n-link>
</Banner>

<div class="get-started">
Expand Down
20 changes: 13 additions & 7 deletions dashboard/pkg/epinio/store/epinio-store/actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { METRIC, SCHEMA } from '@shell/config/types';
import { METRIC, SCHEMA, WORKLOAD_TYPES } from '@shell/config/types';
import { handleSpoofedRequest } from '@shell/plugins/dashboard-store/actions';
import { classify } from '@shell/plugins/dashboard-store/classify';
import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
Expand All @@ -12,6 +12,7 @@ import {
} from '../../types';
import EpinioCluster from '../../models/cluster';
import { RedirectToError } from '@shell/utils/error';
import { allHashSettled } from '@shell/utils/promise';

const createId = (schema: any, resource: any) => {
const name = resource.meta?.name || resource.name;
Expand Down Expand Up @@ -243,13 +244,18 @@ export default {

if (!isSingleProduct) {
try {
const nodeMetricsSchema = await dispatch(`cluster/request`, { url: `/k8s/clusters/${ clusterId }/v1/schemas/${ METRIC.NODE }` }, { root: true });

if (nodeMetricsSchema) {
data.push(nodeMetricsSchema);
}
const schemas = await allHashSettled({
nodeMetrics: dispatch(`cluster/request`, { url: `/k8s/clusters/${ clusterId }/v1/schemas/${ METRIC.NODE }` }, { root: true }),
deployments: dispatch(`cluster/request`, { url: `/k8s/clusters/${ clusterId }/v1/schemas/${ WORKLOAD_TYPES.DEPLOYMENT }` }, { root: true })
});

Object.values(schemas).forEach((res: any ) => {
if (res.value) {
data.push(res.value);
}
});
} catch (e) {
console.warn(`Unable to fetch Node metrics schema for epinio cluster: ${ clusterId }`);// eslint-disable-line no-console
console.debug(`Unable to fetch schema/s for epinio cluster: ${ clusterId }`, e);// eslint-disable-line no-console
}
}

Expand Down
39 changes: 32 additions & 7 deletions dashboard/pkg/epinio/utils/epinio-discovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ import epinioAuth, { EpinioAuthTypes } from '../utils/auth';
import EpinioCluster from '../models/cluster';
import { dashboardUrl } from './embedded-helpers';

export default {
ingressUrl(clusterId: string) {
return `/k8s/clusters/${ clusterId }/v1/networking.k8s.io.ingresses/epinio/epinio`;
},
class EpinioDiscovery {
ingressUrl(clusterId: string, namespace: string) {
return `/k8s/clusters/${ clusterId }/v1/networking.k8s.io.ingresses/${ namespace }/epinio`;
}

async discover(store: any) {
const allClusters = await store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }, { root: true });
const epinioClusters = [];

for (const c of allClusters.filter((c: any) => c.isReady)) {
try {
// Try to discover the namespace epinio is installed to
const namespace = await this.findNamespace(store, c.id);

// Get the url first, if it has this it's highly likely it's an epinio cluster
const epinioIngress = await store.dispatch(`cluster/request`, { url: this.ingressUrl(c.id) }, { root: true });
const epinioIngress = await store.dispatch(`cluster/request`, { url: this.ingressUrl(c.id, namespace) }, { root: true });
const url = ingressFullPath(epinioIngress, epinioIngress.spec.rules?.[0]);

const loggedIn = await epinioAuth.isLoggedIn({
type: EpinioAuthTypes.AGNOSTIC,
epinioUrl: url,
Expand All @@ -30,15 +34,36 @@ export default {
epinioClusters.push(new EpinioCluster({
id: c.id,
name: c.spec.displayName,
namespace,
api: url,
loggedIn: !!loggedIn,
mgmtCluster: c
}, { rootGetters: store.getters }));
} catch (err) {
console.info(`Skipping epinio discovery for ${ c.spec.displayName }`, err); // eslint-disable-line no-console
console.debug(`Skipping epinio discovery for ${ c.spec.displayName }:`, err); // eslint-disable-line no-console
}
}

return epinioClusters;
}
};

private async findNamespace(store: any, clusterId: string): Promise<string> {
// Attempt to find the `epinio-server` deployment. This assumes the user had read rights to resources in the target namespace
const url = `/k8s/clusters/${ clusterId }/v1/apps.deployments?labelSelector=app.kubernetes.io/component%3Depinio,app.kubernetes.io/name%3Depinio-server`;
const deployments = await store.dispatch(`cluster/request`, { url }, { root: true });

if (!deployments?.data?.length) {
return Promise.reject(new Error('Could not find epinio-server deployment'));
}

if (deployments?.data.length > 1) {
return Promise.reject(new Error('Found too many epinio-server deployments'));
}

return deployments.data[0].metadata.namespace;
}
}

const epinioDiscovery = new EpinioDiscovery();

export default epinioDiscovery;

0 comments on commit af846fe

Please sign in to comment.