You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
portainer/app/kubernetes/__module.js

669 lines
17 KiB

import { EnvironmentStatus } from '@/react/portainer/environments/types';
import { updateAxiosAdapter } from '@/portainer/services/axios';
import { PortainerEndpointTypes } from 'Portainer/models/endpoint/models';
import { CACHE_REFRESH_EVENT, CACHE_DURATION } from '../portainer/services/http-request.helper';
import { cache } from '../portainer/services/axios';
import registriesModule from './registries';
import customTemplateModule from './custom-templates';
import { reactModule } from './react';
import './views/kubernetes.css';
// The angular-cache npm package didn't have exclude options, so implement a custom cache
// with an added check to only cache kubernetes requests
class ExpirationCache {
constructor() {
this.store = new Map();
this.timeout = CACHE_DURATION;
}
get(key) {
return this.store.get(key);
}
put(key, val) {
// only cache requests with 'kubernetes' in the url
if (key.includes('kubernetes')) {
this.store.set(key, val);
// remove it once it's expired
setTimeout(() => {
this.remove(key);
}, this.timeout);
}
}
remove(key) {
this.store.delete(key);
}
removeAll() {
this.store = new Map();
}
delete() {
// skip because this is standalone, not a part of $cacheFactory
}
}
angular.module('portainer.kubernetes', ['portainer.app', registriesModule, customTemplateModule, reactModule]).config([
'$stateRegistryProvider',
function ($stateRegistryProvider) {
'use strict';
const kubernetes = {
name: 'kubernetes',
url: '/kubernetes',
parent: 'endpoint',
abstract: true,
onEnter: /* @ngInject */ function onEnter(
$async,
$state,
endpoint,
KubernetesHealthService,
Notifications,
StateManager,
$http,
Authentication,
UserService,
EndpointService,
EndpointProvider
) {
return $async(async () => {
// if the user wants to use front end cache for performance, set the angular caching settings
const userDetails = Authentication.getUserDetails();
const user = await UserService.user(userDetails.ID);
updateAxiosAdapter(user.UseCache);
if (user.UseCache) {
$http.defaults.cache = new ExpirationCache();
window.addEventListener(CACHE_REFRESH_EVENT, () => {
$http.defaults.cache.removeAll();
cache.store.clear();
});
}
const kubeTypes = [
PortainerEndpointTypes.KubernetesLocalEnvironment,
PortainerEndpointTypes.AgentOnKubernetesEnvironment,
PortainerEndpointTypes.EdgeAgentOnKubernetesEnvironment,
];
if (!kubeTypes.includes(endpoint.Type)) {
$state.go('portainer.home');
return;
}
try {
const status = await checkEndpointStatus(endpoint);
if (endpoint.Type !== PortainerEndpointTypes.EdgeAgentOnKubernetesEnvironment) {
await updateEndpointStatus(endpoint, status);
}
endpoint.Status = status;
if (endpoint.Status === EnvironmentStatus.Down) {
throw new Error(
endpoint.Type === PortainerEndpointTypes.EdgeAgentOnKubernetesEnvironment
? 'Unable to contact Edge agent, please ensure that the agent is properly running on the remote environment.'
: `The environment named ${endpoint.Name} is unreachable.`
);
}
await StateManager.updateEndpointState(endpoint);
} catch (e) {
let params = {};
if (endpoint.Type == PortainerEndpointTypes.EdgeAgentOnKubernetesEnvironment) {
params = { redirect: true, environmentId: endpoint.Id, environmentName: endpoint.Name, route: 'kubernetes.dashboard' };
} else {
EndpointProvider.clean();
Notifications.error('Failed loading environment', e);
}
$state.go('portainer.home', params, { reload: true, inherit: false });
return false;
}
async function checkEndpointStatus(endpoint) {
try {
await KubernetesHealthService.ping(endpoint.Id);
return EnvironmentStatus.Up;
} catch (e) {
return EnvironmentStatus.Down;
}
}
async function updateEndpointStatus(endpoint, status) {
if (endpoint.Status === status) {
return;
}
await EndpointService.updateEndpoint(endpoint.Id, { Status: status });
}
});
},
};
const helmApplication = {
name: 'kubernetes.helm',
url: '/helm/:namespace/:name',
views: {
'content@': {
component: 'kubernetesHelmApplicationView',
},
},
data: {
docs: '/user/kubernetes/inspect-helm',
},
};
const services = {
name: 'kubernetes.services',
url: '/services',
views: {
'content@': {
component: 'kubernetesServicesView',
},
},
data: {
docs: '/user/kubernetes/networking/services',
},
};
const ingresses = {
name: 'kubernetes.ingresses',
url: '/ingresses',
views: {
'content@': {
component: 'kubernetesIngressesView',
},
},
data: {
docs: '/user/kubernetes/networking/ingresses',
},
};
const ingressesCreate = {
name: 'kubernetes.ingresses.create',
url: '/add',
views: {
'content@': {
component: 'kubernetesIngressesCreateView',
},
},
data: {
docs: '/user/kubernetes/networking/ingresses/add',
},
};
const ingressesEdit = {
name: 'kubernetes.ingresses.edit',
url: '/:namespace/:name/edit',
views: {
'content@': {
component: 'kubernetesIngressesCreateView',
},
},
};
const applications = {
name: 'kubernetes.applications',
url: '/applications',
views: {
'content@': {
component: 'kubernetesApplicationsView',
},
},
data: {
docs: '/user/kubernetes/applications',
},
};
const applicationCreation = {
name: 'kubernetes.applications.new',
url: '/new',
views: {
'content@': {
component: 'kubernetesCreateApplicationView',
},
},
data: {
docs: '/user/kubernetes/applications/add',
},
};
const application = {
name: 'kubernetes.applications.application',
url: '/:namespace/:name?resource-type&tab',
views: {
'content@': {
component: 'applicationDetailsView',
},
},
data: {
docs: '/user/kubernetes/applications/inspect',
},
};
const applicationEdit = {
name: 'kubernetes.applications.application.edit',
url: '/edit',
views: {
'content@': {
component: 'kubernetesCreateApplicationView',
},
},
data: {
docs: '/user/kubernetes/applications/edit',
},
};
const applicationConsole = {
name: 'kubernetes.applications.application.console',
url: '/:pod/:container/console',
views: {
'content@': {
component: 'kubernetesConsoleView',
},
},
};
const applicationLogs = {
name: 'kubernetes.applications.application.logs',
url: '/:pod/:container/logs',
views: {
'content@': {
component: 'kubernetesApplicationLogsView',
},
},
};
const applicationStats = {
name: 'kubernetes.applications.application.stats',
url: '/:pod/:container/stats',
views: {
'content@': {
component: 'kubernetesApplicationStatsView',
},
},
};
const stacks = {
name: 'kubernetes.stacks',
url: '/stacks',
abstract: true,
};
const stack = {
name: 'kubernetes.stacks.stack',
url: '/:namespace/:name',
abstract: true,
};
const stackLogs = {
name: 'kubernetes.stacks.stack.logs',
url: '/logs',
views: {
'content@': {
component: 'kubernetesStackLogsView',
},
},
};
const configurations = {
name: 'kubernetes.configurations',
url: '/configurations?tab',
views: {
'content@': {
component: 'kubernetesConfigMapsAndSecretsView',
},
},
params: {
tab: null,
},
data: {
docs: '/user/kubernetes/configurations',
},
};
const configmaps = {
name: 'kubernetes.configmaps',
url: '/configmaps',
abstract: true,
data: {
docs: '/user/kubernetes/configurations',
},
};
const configMapCreation = {
name: 'kubernetes.configmaps.new',
url: '/new',
views: {
'content@': {
component: 'kubernetesCreateConfigMapView',
},
},
data: {
docs: '/user/kubernetes/configurations/add-configmap',
},
};
const configMap = {
name: 'kubernetes.configmaps.configmap',
url: '/:namespace/:name',
views: {
'content@': {
component: 'kubernetesConfigMapView',
},
},
};
const secrets = {
name: 'kubernetes.secrets',
url: '/secrets',
abstract: true,
data: {
docs: '/user/kubernetes/configurations',
},
};
const secretCreation = {
name: 'kubernetes.secrets.new',
url: '/new',
views: {
'content@': {
component: 'kubernetesCreateSecretView',
},
},
data: {
docs: '/user/kubernetes/configurations/add-secret',
},
};
const secret = {
name: 'kubernetes.secrets.secret',
url: '/:namespace/:name',
views: {
'content@': {
component: 'kubernetesSecretView',
},
},
};
const cluster = {
name: 'kubernetes.cluster',
url: '/cluster',
views: {
'content@': {
component: 'kubernetesClusterView',
},
},
data: {
docs: '/user/kubernetes/cluster/details',
},
};
const node = {
name: 'kubernetes.cluster.node',
url: '/:nodeName',
views: {
'content@': {
component: 'kubernetesNodeView',
},
},
data: {
docs: '/user/kubernetes/cluster/node',
},
};
const nodeStats = {
name: 'kubernetes.cluster.node.stats',
url: '/stats',
views: {
'content@': {
component: 'kubernetesNodeStatsView',
},
},
};
const dashboard = {
name: 'kubernetes.dashboard',
url: '/dashboard',
views: {
'content@': {
component: 'kubernetesDashboardView',
},
},
data: {
docs: '/user/kubernetes/dashboard',
},
};
const deploy = {
name: 'kubernetes.deploy',
url: '/deploy?templateId&referrer&tab&buildMethod&chartName',
views: {
'content@': {
component: 'kubernetesDeployView',
},
},
data: {
docs: '/user/kubernetes/applications/manifest',
},
};
const resourcePools = {
name: 'kubernetes.resourcePools',
url: '/namespaces',
views: {
'content@': {
component: 'kubernetesNamespacesView',
},
},
data: {
docs: '/user/kubernetes/namespaces',
},
};
const namespaceCreation = {
name: 'kubernetes.resourcePools.new',
url: '/new',
views: {
'content@': {
component: 'kubernetesCreateNamespaceView',
},
},
data: {
docs: '/user/kubernetes/namespaces/add',
},
};
const resourcePool = {
name: 'kubernetes.resourcePools.resourcePool',
url: '/:id',
views: {
'content@': {
component: 'kubernetesResourcePoolView',
},
},
data: {
docs: '/user/kubernetes/namespaces/manage',
},
};
const resourcePoolAccess = {
name: 'kubernetes.resourcePools.resourcePool.access',
url: '/access',
views: {
'content@': {
component: 'kubernetesResourcePoolAccessView',
},
},
data: {
docs: '/user/kubernetes/namespaces/access',
},
};
const volumes = {
name: 'kubernetes.volumes',
url: '/volumes?tab',
views: {
'content@': {
component: 'kubernetesVolumesView',
},
},
data: {
docs: '/user/kubernetes/volumes',
},
};
const volume = {
name: 'kubernetes.volumes.volume',
url: '/:namespace/:name',
views: {
'content@': {
component: 'kubernetesVolumeView',
},
},
};
const registries = {
name: 'kubernetes.registries',
url: '/registries',
views: {
'content@': {
component: 'environmentRegistriesView',
},
},
data: {
docs: '/user/kubernetes/cluster/registries',
},
};
const registriesAccess = {
name: 'kubernetes.registries.access',
url: '/:id/access',
views: {
'content@': {
component: 'kubernetesRegistryAccessView',
},
},
};
const endpointKubernetesConfiguration = {
name: 'kubernetes.cluster.setup',
url: '/configure',
views: {
'content@': {
component: 'kubernetesConfigureView',
},
},
data: {
docs: '/user/kubernetes/cluster/setup',
},
};
const endpointKubernetesSecurityConstraint = {
name: 'kubernetes.cluster.securityConstraint',
url: '/securityConstraint',
views: {
'content@': {
templateUrl: '../kubernetes/views/security-constraint/constraint.html',
controller: 'KubernetesSecurityConstraintController',
},
},
data: {
docs: '/user/kubernetes/cluster/security',
},
};
const moreResources = {
name: 'kubernetes.moreResources',
url: '/moreResources',
abstract: true,
};
const serviceAccounts = {
name: 'kubernetes.moreResources.serviceAccounts',
url: '/serviceAccounts',
views: {
'content@': {
component: 'serviceAccountsView',
},
},
data: {
docs: '/user/kubernetes/more-resources/service-accounts',
},
};
const clusterRoles = {
name: 'kubernetes.moreResources.clusterRoles',
url: '/clusterRoles?tab',
views: {
'content@': {
component: 'clusterRolesView',
},
},
data: {
docs: '/user/kubernetes/more-resources/cluster-roles',
},
};
const roles = {
name: 'kubernetes.moreResources.roles',
url: '/roles?tab',
views: {
'content@': {
component: 'k8sRolesView',
},
},
data: {
docs: '/user/kubernetes/more-resources/namespace-roles',
},
};
$stateRegistryProvider.register(kubernetes);
$stateRegistryProvider.register(helmApplication);
$stateRegistryProvider.register(applications);
$stateRegistryProvider.register(applicationCreation);
$stateRegistryProvider.register(application);
$stateRegistryProvider.register(applicationEdit);
$stateRegistryProvider.register(applicationConsole);
$stateRegistryProvider.register(applicationLogs);
$stateRegistryProvider.register(applicationStats);
$stateRegistryProvider.register(stacks);
$stateRegistryProvider.register(stack);
$stateRegistryProvider.register(stackLogs);
$stateRegistryProvider.register(configurations);
$stateRegistryProvider.register(configmaps);
$stateRegistryProvider.register(configMapCreation);
$stateRegistryProvider.register(secrets);
$stateRegistryProvider.register(secretCreation);
$stateRegistryProvider.register(configMap);
$stateRegistryProvider.register(secret);
$stateRegistryProvider.register(cluster);
$stateRegistryProvider.register(dashboard);
$stateRegistryProvider.register(deploy);
$stateRegistryProvider.register(node);
$stateRegistryProvider.register(nodeStats);
$stateRegistryProvider.register(resourcePools);
$stateRegistryProvider.register(namespaceCreation);
$stateRegistryProvider.register(resourcePool);
$stateRegistryProvider.register(resourcePoolAccess);
$stateRegistryProvider.register(volumes);
$stateRegistryProvider.register(volume);
$stateRegistryProvider.register(registries);
$stateRegistryProvider.register(registriesAccess);
$stateRegistryProvider.register(endpointKubernetesConfiguration);
$stateRegistryProvider.register(endpointKubernetesSecurityConstraint);
$stateRegistryProvider.register(services);
$stateRegistryProvider.register(ingresses);
$stateRegistryProvider.register(ingressesCreate);
$stateRegistryProvider.register(ingressesEdit);
$stateRegistryProvider.register(moreResources);
$stateRegistryProvider.register(serviceAccounts);
$stateRegistryProvider.register(clusterRoles);
$stateRegistryProvider.register(roles);
},
]);