refactor(environments): remove angular dep from service [EE-2346] (#6360)

refactor(environments): parse axios error
pull/6361/head
Chaim Lev-Ari 2022-01-06 18:31:47 +02:00 committed by GitHub
parent ecd0eb6170
commit 07c6ce84c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 612 additions and 2 deletions

View File

@ -0,0 +1,174 @@
import PortainerError from '@/portainer/error';
import axios, { parseAxiosError } from '@/portainer/services/axios';
import {
Environment,
EnvironmentGroupId,
EnvironmentCreationTypes,
TagId,
} from '../types';
import { arrayToJson, buildUrl, json2formData } from './utils';
export async function createLocalEndpoint(
name = 'local',
url = '',
publicUrl = '',
groupId: EnvironmentGroupId = 1,
tagIds: TagId[] = []
) {
let endpointUrl = url;
if (endpointUrl !== '') {
if (endpointUrl.includes('//./pipe/')) {
endpointUrl = `unix://${url}`;
} else {
// Windows named pipe
endpointUrl = `npipe://${url}`;
}
}
try {
return await createEndpoint(
name,
EnvironmentCreationTypes.LocalDockerEnvironment,
{ url: endpointUrl, publicUrl, groupId, tagIds }
);
} catch (err) {
throw new PortainerError('Unable to create environment', err as Error);
}
}
export async function createLocalKubernetesEndpoint(
name = 'local',
tagIds: TagId[] = []
) {
try {
return await createEndpoint(
name,
EnvironmentCreationTypes.LocalKubernetesEnvironment,
{ tagIds, groupId: 1, tls: { skipClientVerify: true, skipVerify: true } }
);
} catch (err) {
throw new PortainerError('Unable to create environment', err as Error);
}
}
export async function createAzureEndpoint(
name: string,
applicationId: string,
tenantId: string,
authenticationKey: string,
groupId: EnvironmentGroupId,
tagIds: TagId[]
) {
try {
await createEndpoint(name, EnvironmentCreationTypes.AzureEnvironment, {
groupId,
tagIds,
azure: { applicationId, tenantId, authenticationKey },
});
} catch (err) {
throw new PortainerError('Unable to connect to Azure', err as Error);
}
}
interface TLSSettings {
skipVerify?: boolean;
skipClientVerify?: boolean;
caCertFile?: File;
certFile?: File;
keyFile?: File;
}
interface AzureSettings {
applicationId: string;
tenantId: string;
authenticationKey: string;
}
interface EndpointOptions {
url?: string;
publicUrl?: string;
groupId?: EnvironmentGroupId;
tagIds?: TagId[];
checkinInterval?: number;
azure?: AzureSettings;
tls?: TLSSettings;
}
export async function createRemoteEndpoint(
name: string,
creationType: EnvironmentCreationTypes,
options?: EndpointOptions
) {
let endpointUrl = options?.url;
if (creationType !== EnvironmentCreationTypes.EdgeAgentEnvironment) {
endpointUrl = `tcp://${endpointUrl}`;
}
try {
return await createEndpoint(name, creationType, {
...options,
url: endpointUrl,
});
} catch (err) {
throw new PortainerError('Unable to create environment', err as Error);
}
}
async function createEndpoint(
name: string,
creationType: EnvironmentCreationTypes,
options?: EndpointOptions
) {
let payload: Record<string, unknown> = {
Name: name,
EndpointCreationType: creationType,
};
if (options) {
payload = {
...payload,
URL: options.url,
PublicURL: options.publicUrl,
GroupID: options.groupId,
TagIds: arrayToJson(options.tagIds),
CheckinInterval: options.checkinInterval,
};
const { tls, azure } = options;
if (tls) {
payload = {
...payload,
TLS: true,
TLSSkipVerify: tls.skipVerify,
TLSSkipClientVerify: tls.skipClientVerify,
TLSCACertFile: tls.caCertFile,
TLSCertFile: tls.certFile,
TLSKeyFile: tls.keyFile,
};
}
if (azure) {
payload = {
...payload,
AzureApplicationID: azure.applicationId,
AzureTenantID: azure.tenantId,
AzureAuthenticationKey: azure.authenticationKey,
};
}
}
const formPayload = json2formData(payload);
try {
const { data: endpoint } = await axios.post<Environment>(
buildUrl(),
formPayload
);
return endpoint;
} catch (e) {
throw parseAxiosError(e as Error);
}
}

View File

@ -0,0 +1,224 @@
import axios, { parseAxiosError } from '@/portainer/services/axios';
import {
Environment,
EnvironmentGroupId,
EnvironmentId,
EnvironmentType,
EnvironmentSettings,
TagId,
TeamId,
UserId,
} from '../types';
import { arrayToJson, buildUrl } from './utils';
interface EndpointsQuery {
search?: string;
types?: EnvironmentType[];
tagIds?: TagId[];
endpointIds?: EnvironmentId[];
tagsPartialMatch?: boolean;
groupId?: EnvironmentGroupId;
}
export async function getEndpoints(
start: number,
limit: number,
{ types, tagIds, endpointIds, ...query }: EndpointsQuery = {}
) {
if (tagIds && tagIds.length === 0) {
return { totalCount: 0, value: <Environment[]>[] };
}
const url = buildUrl();
const params: Record<string, unknown> = { start, limit, ...query };
if (types) {
params.types = arrayToJson(types);
}
if (tagIds) {
params.tagIds = arrayToJson(tagIds);
}
if (endpointIds) {
params.endpointIds = arrayToJson(endpointIds);
}
try {
const response = await axios.get<Environment[]>(url, { params });
const totalCount = response.headers['X-Total-Count'];
return { totalCount: parseInt(totalCount, 10), value: response.data };
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function getEndpoint(id: EnvironmentId) {
try {
const { data: endpoint } = await axios.get<Environment>(buildUrl(id));
return endpoint;
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function snapshotEndpoints() {
try {
await axios.post<void>(buildUrl(undefined, 'snapshot'));
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function snapshotEndpoint(id: EnvironmentId) {
try {
await axios.post<void>(buildUrl(id, 'snapshot'));
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function endpointsByGroup(
start: number,
limit: number,
search: string,
groupId: EnvironmentGroupId
) {
return getEndpoints(start, limit, { search, groupId });
}
export async function disassociateEndpoint(id: EnvironmentId) {
try {
await axios.delete(buildUrl(id, 'association'));
} catch (e) {
throw parseAxiosError(e as Error);
}
}
interface UpdatePayload {
TLSCACert?: File;
TLSCert?: File;
TLSKey?: File;
Name: string;
PublicURL: string;
GroupID: EnvironmentGroupId;
TagIds: TagId[];
EdgeCheckinInterval: number;
TLS: boolean;
TLSSkipVerify: boolean;
TLSSkipClientVerify: boolean;
AzureApplicationID: string;
AzureTenantID: string;
AzureAuthenticationKey: string;
}
async function uploadTLSFilesForEndpoint(
id: EnvironmentId,
tlscaCert?: File,
tlsCert?: File,
tlsKey?: File
) {
await Promise.all([
uploadCert('ca', tlscaCert),
uploadCert('cert', tlsCert),
uploadCert('key', tlsKey),
]);
function uploadCert(type: 'ca' | 'cert' | 'key', cert?: File) {
if (!cert) {
return null;
}
try {
return axios.post<void>(`upload/tls/${type}`, cert, {
params: { folder: id },
});
} catch (e) {
throw parseAxiosError(e as Error);
}
}
}
export async function updateEndpoint(
id: EnvironmentId,
payload: UpdatePayload
) {
try {
await uploadTLSFilesForEndpoint(
id,
payload.TLSCACert,
payload.TLSCert,
payload.TLSKey
);
const { data: endpoint } = await axios.put<Environment>(
buildUrl(id),
payload
);
return endpoint;
} catch (e) {
throw parseAxiosError(e as Error, 'Unable to update environment');
}
}
export async function deleteEndpoint(id: EnvironmentId) {
try {
await axios.delete(buildUrl(id));
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function updatePoolAccess(
id: EnvironmentId,
resourcePool: string,
usersToAdd: UserId[],
teamsToAdd: TeamId[],
usersToRemove: UserId[],
teamsToRemove: TeamId[]
) {
try {
await axios.put<void>(`${buildUrl(id, 'pools')}/${resourcePool}/access`, {
usersToAdd,
teamsToAdd,
usersToRemove,
teamsToRemove,
});
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function forceUpdateService(
id: EnvironmentId,
serviceID: string,
pullImage: boolean
) {
try {
await axios.put(buildUrl(id, 'forceupdateservice'), {
serviceID,
pullImage,
});
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function updateSettings(
id: EnvironmentId,
settings: EnvironmentSettings
) {
try {
await axios.put(buildUrl(id, 'settings'), settings);
} catch (e) {
throw parseAxiosError(e as Error);
}
}

View File

@ -0,0 +1,70 @@
import axios, { parseAxiosError } from '@/portainer/services/axios';
import {
EnvironmentId,
TeamAccessPolicies,
UserAccessPolicies,
} from '../types';
import { buildUrl } from './utils';
export type RegistryId = number;
export interface Registry {
Id: RegistryId;
}
interface RegistryAccess {
UserAccessPolicies: UserAccessPolicies;
TeamAccessPolicies: TeamAccessPolicies;
Namespaces: string[];
}
export async function updateEnvironmentRegistryAccess(
id: EnvironmentId,
registryId: RegistryId,
access: RegistryAccess
) {
try {
await axios.put<void>(buildRegistryUrl(id, registryId), access);
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function getEnvironmentRegistries(
id: EnvironmentId,
namespace: string
) {
try {
const { data } = await axios.get<Registry[]>(buildRegistryUrl(id), {
params: { namespace },
});
return data;
} catch (e) {
throw parseAxiosError(e as Error);
}
}
export async function getEnvironmentRegistry(
endpointId: EnvironmentId,
registryId: RegistryId
) {
try {
const { data } = await axios.get<Registry>(
buildRegistryUrl(endpointId, registryId)
);
return data;
} catch (e) {
throw parseAxiosError(e as Error);
}
}
function buildRegistryUrl(id: EnvironmentId, registryId?: RegistryId) {
let url = `${buildUrl(id)}/registries`;
if (registryId) {
url += `/${registryId}`;
}
return url;
}

View File

@ -0,0 +1,36 @@
import { EnvironmentId } from '../types';
export function buildUrl(id?: EnvironmentId, action?: string) {
let baseUrl = 'endpoints';
if (id) {
baseUrl += `/${id}`;
}
if (action) {
baseUrl += `/${action}`;
}
return baseUrl;
}
export function arrayToJson<T>(arr?: Array<T>) {
if (!arr) {
return '';
}
return JSON.stringify(arr);
}
export function json2formData(json: Record<string, unknown>) {
const formData = new FormData();
Object.entries(json).forEach(([key, value]) => {
if (typeof value === 'undefined' || value === null) {
return;
}
formData.append(key, value as string);
});
return formData;
}

View File

@ -1,12 +1,118 @@
export type EnvironmentId = number;
export enum EnvironmentType {
// Docker represents an environment(endpoint) connected to a Docker environment(endpoint)
Docker = 1,
// AgentOnDocker represents an environment(endpoint) connected to a Portainer agent deployed on a Docker environment(endpoint)
AgentOnDocker,
// Azure represents an environment(endpoint) connected to an Azure environment(endpoint)
Azure,
// EdgeAgentOnDocker represents an environment(endpoint) connected to an Edge agent deployed on a Docker environment(endpoint)
EdgeAgentOnDocker,
// KubernetesLocal represents an environment(endpoint) connected to a local Kubernetes environment(endpoint)
KubernetesLocal,
// AgentOnKubernetes represents an environment(endpoint) connected to a Portainer agent deployed on a Kubernetes environment(endpoint)
AgentOnKubernetes,
// EdgeAgentOnKubernetes represents an environment(endpoint) connected to an Edge agent deployed on a Kubernetes environment(endpoint)
EdgeAgentOnKubernetes,
}
export type TagId = number;
export interface Tag {
Id: TagId;
Name: string;
}
export enum EnvironmentStatus {
Up = 1,
Down = 2,
Down,
}
export interface DockerSnapshot {
TotalCPU: number;
TotalMemory: number;
NodeCount: number;
ImageCount: number;
VolumeCount: number;
RunningContainerCount: number;
StoppedContainerCount: number;
HealthyContainerCount: number;
UnhealthyContainerCount: number;
Time: number;
StackCount: number;
ServiceCount: number;
Swarm: boolean;
DockerVersion: string;
}
export interface KubernetesSnapshot {
KubernetesVersion: string;
TotalCPU: number;
TotalMemory: number;
Time: number;
NodeCount: number;
}
export interface KubernetesSettings {
Snapshots: KubernetesSnapshot[];
}
export interface Environment {
Id: EnvironmentId;
Type: EnvironmentType;
TagIds: TagId[];
GroupName: string;
EdgeID?: string;
EdgeCheckinInterval?: number;
LastCheckInDate?: number;
Name: string;
Status: EnvironmentStatus;
PublicURL: string;
URL: string;
Snapshots: DockerSnapshot[];
Kubernetes: KubernetesSettings;
PublicURL?: string;
}
/**
* TS reference of endpoint_create.go#EndpointCreationType iota
*/
export enum EnvironmentCreationTypes {
LocalDockerEnvironment = 1,
AgentEnvironment,
AzureEnvironment,
EdgeAgentEnvironment,
LocalKubernetesEnvironment,
}
export type EnvironmentGroupId = number;
export interface EnvironmentSettings {
// Whether non-administrator should be able to use bind mounts when creating containers
allowBindMountsForRegularUsers: boolean;
// Whether non-administrator should be able to use privileged mode when creating containers
allowPrivilegedModeForRegularUsers: boolean;
// Whether non-administrator should be able to browse volumes
allowVolumeBrowserForRegularUsers: boolean;
// Whether non-administrator should be able to use the host pid
allowHostNamespaceForRegularUsers: boolean;
// Whether non-administrator should be able to use device mapping
allowDeviceMappingForRegularUsers: boolean;
// Whether non-administrator should be able to manage stacks
allowStackManagementForRegularUsers: boolean;
// Whether non-administrator should be able to use container capabilities
allowContainerCapabilitiesForRegularUsers: boolean;
// Whether non-administrator should be able to use sysctl settings
allowSysctlSettingForRegularUsers: boolean;
// Whether host management features are enabled
enableHostManagementFeatures: boolean;
}
export type UserId = number;
export type TeamId = number;
export type RoleId = number;
interface AccessPolicy {
RoleId: RoleId;
}
export type UserAccessPolicies = Record<UserId, AccessPolicy>; // map[UserID]AccessPolicy
export type TeamAccessPolicies = Record<TeamId, AccessPolicy>;