Skip to content

Commit

Permalink
Remove k8vent annotation, update k8s
Browse files Browse the repository at this point in the history
Remove the deprecated k8vent annotation.

Update k8s to support Kubernetes 1.16 and newer, replacing
extensions/v1beta1 with networking.k8s.io/v1beta1.

Prettier.

[changelog:removed]
  • Loading branch information
David Dooling committed Jun 18, 2020
1 parent 73cf7ae commit 928ee8d
Show file tree
Hide file tree
Showing 16 changed files with 596 additions and 483 deletions.
257 changes: 128 additions & 129 deletions lib/core/pack/k8s/container.ts

Large diffs are not rendered by default.

35 changes: 14 additions & 21 deletions lib/core/pack/k8s/kubernetes/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,14 @@

import * as k8s from "@kubernetes/client-node";
import { k8sErrMsg } from "../support/error";
import {
KubernetesClients,
makeApiClients,
makeNoOpApiClients,
} from "./clients";
import { KubernetesClients, makeApiClients, makeNoOpApiClients } from "./clients";
import { loadKubeConfig } from "./config";
import {
deleteAppResources,
DeleteAppResourcesArgCluster,
DeleteAppResourcesArgNamespaced,
} from "./delete";
import { deleteAppResources, DeleteAppResourcesArgCluster, DeleteAppResourcesArgNamespaced } from "./delete";
import { upsertDeployment } from "./deployment";
import { upsertIngress } from "./ingress";
import { upsertNamespace } from "./namespace";
import { upsertRbac } from "./rbac";
import {
KubernetesApplication,
KubernetesDelete,
reqString,
} from "./request";
import { KubernetesApplication, KubernetesDelete, reqString } from "./request";
import { upsertSecrets } from "./secret";
import { upsertService } from "./service";

Expand All @@ -47,7 +35,10 @@ import { upsertService } from "./service";
* @param sdmFulfiller Registered name of the SDM fulfilling the deployment goal.
* @return Array of resource specs upserted
*/
export async function upsertApplication(app: KubernetesApplication, sdmFulfiller: string): Promise<k8s.KubernetesObject[]> {
export async function upsertApplication(
app: KubernetesApplication,
sdmFulfiller: string,
): Promise<k8s.KubernetesObject[]> {
let clients: KubernetesClients;
if (app.mode === "sync") {
clients = makeNoOpApiClients();
Expand All @@ -66,7 +57,7 @@ export async function upsertApplication(app: KubernetesApplication, sdmFulfiller
try {
const k8sResources: k8s.KubernetesObject[] = [];
k8sResources.push(await upsertNamespace(req));
k8sResources.push(...Object.values<k8s.KubernetesObject>(await upsertRbac(req) as any));
k8sResources.push(...Object.values<k8s.KubernetesObject>((await upsertRbac(req)) as any));
k8sResources.push(await upsertService(req));
k8sResources.push(...(await upsertSecrets(req)));
k8sResources.push(await upsertDeployment(req));
Expand Down Expand Up @@ -100,13 +91,15 @@ export async function deleteApplication(del: KubernetesDelete): Promise<k8s.Kube

const deleted: k8s.KubernetesObject[] = [];
const errs: Error[] = [];
const resourceDeleters: Array<Omit<DeleteAppResourcesArgCluster, "req"> | Omit<DeleteAppResourcesArgNamespaced, "req">> = [
const resourceDeleters: Array<
Omit<DeleteAppResourcesArgCluster, "req"> | Omit<DeleteAppResourcesArgNamespaced, "req">
> = [
{
kind: "Ingress",
namespaced: true,
api: req.clients.ext,
lister: req.clients.ext.listNamespacedIngress,
deleter: req.clients.ext.deleteNamespacedIngress,
api: req.clients.net,
lister: req.clients.net.listNamespacedIngress,
deleter: req.clients.net.deleteNamespacedIngress,
},
{
kind: "Deployment",
Expand Down
24 changes: 12 additions & 12 deletions lib/core/pack/k8s/kubernetes/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export interface KubernetesClients {
core: k8s.CoreV1Api;
/** Kubernetes Apps client, GA in Kubernetes 1.9 */
apps: k8s.AppsV1Api;
/** Kubernetes Extension client */
ext: k8s.ExtensionsV1beta1Api;
/** Kubernetes networking client */
net: k8s.NetworkingV1beta1Api;
/** Kubernetes RBAC client, GA in Kubernetes 1.8 */
rbac: k8s.RbacAuthorizationV1Api;
}
Expand All @@ -38,16 +38,16 @@ export function makeApiClients(kc: k8s.KubeConfig): KubernetesClients {
const core = kc.makeApiClient(k8s.CoreV1Api);
const apps = kc.makeApiClient(k8s.AppsV1Api);
const rbac = kc.makeApiClient(k8s.RbacAuthorizationV1Api);
const ext = kc.makeApiClient(k8s.ExtensionsV1beta1Api);
return { core, apps, rbac, ext };
const net = kc.makeApiClient(k8s.NetworkingV1beta1Api);
return { core, apps, net, rbac };
}

/**
* Provide no-op client when only want changes persisted to the GitOps
* sync repo.
*/
export function makeNoOpApiClients(): KubernetesClients {
const noop = async () => { };
const noop = async () => {};
const core: any = {
createNamespace: noop,
deleteNamespace: noop,
Expand All @@ -72,6 +72,12 @@ export function makeNoOpApiClients(): KubernetesClients {
patchNamespacedDeployment: noop,
readNamespacedDeployment: noop,
};
const net: any = {
createNamespacedIngress: noop,
deleteNamespacedIngress: noop,
patchNamespacedIngress: noop,
readNamespacedIngress: noop,
};
const rbac: any = {
createClusterRole: noop,
deleteClusterRole: noop,
Expand All @@ -90,11 +96,5 @@ export function makeNoOpApiClients(): KubernetesClients {
patchNamespacedRoleBinding: noop,
readNamespacedRoleBinding: noop,
};
const ext: any = {
createNamespacedIngress: noop,
deleteNamespacedIngress: noop,
patchNamespacedIngress: noop,
readNamespacedIngress: noop,
};
return { core, apps, rbac, ext };
return { core, apps, net, rbac };
}
47 changes: 27 additions & 20 deletions lib/core/pack/k8s/kubernetes/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,10 @@ import { logger } from "@atomist/automation-client/lib/util/logger";
import * as k8s from "@kubernetes/client-node";
import { k8sErrMsg } from "../support/error";
import { logRetry } from "../support/retry";
import {
K8sDeleteResponse,
K8sListResponse,
K8sObjectApi,
} from "./api";
import { K8sDeleteResponse, K8sListResponse, K8sObjectApi } from "./api";
import { loadKubeConfig } from "./config";
import { labelSelector } from "./labels";
import {
appName,
KubernetesDeleteResourceRequest,
} from "./request";
import { appName, KubernetesDeleteResourceRequest } from "./request";
import { logObject } from "./resource";
import { specSlug } from "./spec";

Expand Down Expand Up @@ -122,7 +115,7 @@ export interface DeleteAppResourcesArgBase {
/** Delete request object. */
req: KubernetesDeleteResourceRequest;
/** API object to use as `this` for lister and deleter. */
api: k8s.CoreV1Api | k8s.AppsV1Api | k8s.ExtensionsV1beta1Api | k8s.RbacAuthorizationV1Api;
api: k8s.CoreV1Api | k8s.AppsV1Api | k8s.NetworkingV1beta1Api | k8s.RbacAuthorizationV1Api;
/** Resource collection deleting function. */
lister: K8sNamespacedLister | K8sClusterLister;
/** Resource collection deleting function. */
Expand Down Expand Up @@ -157,17 +150,25 @@ export async function deleteAppResources(arg: DeleteAppResourcesArg): Promise<k8
let continu: string;
do {
let listResp: K8sListResponse;
const args: [string?, boolean?, string?, string?, string?, number?] =
[undefined, undefined, continu, undefined, selector, limit];
const args: [string?, boolean?, string?, string?, string?, number?] = [
undefined,
undefined,
continu,
undefined,
selector,
limit,
];
if (arg.namespaced) {
listResp = await arg.lister.call(arg.api, arg.req.ns, ...args);
} else if (arg.namespaced === false) {
listResp = await arg.lister.apply(arg.api, args);
}
toDelete.push(...listResp.body.items.map(r => {
r.kind = r.kind || arg.kind; // list response does not include kind
return r;
}));
toDelete.push(
...listResp.body.items.map(r => {
r.kind = r.kind || arg.kind; // list response does not include kind
return r;
}),
);
continu = listResp.body.metadata._continue;
} while (!!continu);
} catch (e) {
Expand All @@ -177,12 +178,18 @@ export async function deleteAppResources(arg: DeleteAppResourcesArg): Promise<k8
const deleted: k8s.KubernetesObject[] = [];
const errs: Error[] = [];
for (const resource of toDelete) {
const resourceSlug = arg.namespaced ? `${arg.kind}/${resource.metadata.namespace}/${resource.metadata.name}` :
`${arg.kind}/${resource.metadata.name}`;
const resourceSlug = arg.namespaced
? `${arg.kind}/${resource.metadata.namespace}/${resource.metadata.name}`
: `${arg.kind}/${resource.metadata.name}`;
logger.info(`Deleting ${resourceSlug} for ${slug}`);
try {
const args: [string?, string?, number?, boolean?, string?] =
[undefined, undefined, undefined, undefined, "Background"];
const args: [string?, string?, number?, boolean?, string?] = [
undefined,
undefined,
undefined,
undefined,
"Background",
];
if (arg.namespaced) {
await arg.deleter.call(arg.api, resource.metadata.name, resource.metadata.namespace, ...args);
} else if (arg.namespaced === false) {
Expand Down
8 changes: 0 additions & 8 deletions lib/core/pack/k8s/kubernetes/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@
* limitations under the License.
*/

import { webhookBaseUrl } from "@atomist/automation-client/lib/atomistWebhook";
import { logger } from "@atomist/automation-client/lib/util/logger";
import * as k8s from "@kubernetes/client-node";
import * as stringify from "json-stringify-safe";
import * as _ from "lodash";
import { k8sErrMsg } from "../support/error";
import { logRetry } from "../support/retry";
Expand Down Expand Up @@ -74,9 +72,6 @@ export async function upsertDeployment(req: KubernetesResourceRequest): Promise<
* @return deployment resource specification
*/
export async function deploymentTemplate(req: KubernetesApplication & KubernetesSdm): Promise<k8s.V1Deployment> {
const k8ventAnnot = stringify({
webhooks: [`${webhookBaseUrl()}/atomist/kube/teams/${req.workspaceId}`],
});
const labels = applicationLabels(req);
const matchers = matchLabels(req);
const metadata = metadataTemplate({
Expand All @@ -87,9 +82,6 @@ export async function deploymentTemplate(req: KubernetesApplication & Kubernetes
const podMetadata = metadataTemplate({
name: req.name,
labels,
annotations: {
"atomist.com/k8vent": k8ventAnnot,
},
});
const selector: k8s.V1LabelSelector = {
matchLabels: matchers,
Expand Down
52 changes: 33 additions & 19 deletions lib/core/pack/k8s/kubernetes/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ import * as k8s from "@kubernetes/client-node";
import * as _ from "lodash";
import { k8sErrMsg } from "../support/error";
import { K8sObjectApi } from "./api";
import {
KubernetesClients,
makeApiClients,
} from "./clients";
import { KubernetesClients, makeApiClients } from "./clients";
import { loadKubeConfig } from "./config";
import { labelMatch } from "./labels";
import { nameMatch } from "./name";
Expand Down Expand Up @@ -96,7 +93,7 @@ export const defaultKubernetesResourceSelectorKinds: KubernetesResourceKind[] =
{ apiVersion: "apps/v1", kind: "StatefulSet" },
{ apiVersion: "autoscaling/v1", kind: "HorizontalPodAutoscaler" },
{ apiVersion: "batch/v1beta1", kind: "CronJob" },
{ apiVersion: "extensions/v1beta1", kind: "Ingress" },
{ apiVersion: "networking.k8s.io/v1beta1", kind: "Ingress" },
{ apiVersion: "networking.k8s.io/v1", kind: "NetworkPolicy" },
{ apiVersion: "policy/v1beta1", kind: "PodDisruptionBudget" },
{ apiVersion: "policy/v1beta1", kind: "PodSecurityPolicy" },
Expand Down Expand Up @@ -147,7 +144,10 @@ export const defaultKubernetesFetchOptions: KubernetesFetchOptions = {
name: /^(?:cluster-admin(?:-binding)?|cloud-provider|kubernetes-dashboard)$/,
},
{ action: "exclude", kinds: [{ apiVersion: "storage.k8s.io/v1", kind: "StorageClass" }], name: "standard" },
{ action: "exclude", filter: (r: any) => r.kind === "Secret" && r.type === "kubernetes.io/service-account-token" },
{
action: "exclude",
filter: (r: any) => r.kind === "Secret" && r.type === "kubernetes.io/service-account-token",
},
{ action: "exclude", filter: r => /^ClusterRole/.test(r.kind) && /(?:kubelet|:)/.test(r.metadata.name) },
{ action: "include", kinds: defaultKubernetesResourceSelectorKinds },
],
Expand All @@ -164,7 +164,9 @@ export const defaultKubernetesFetchOptions: KubernetesFetchOptions = {
* @param options Kubernetes fetch options
* @return Kubernetes resources matching the fetch options
*/
export async function kubernetesFetch(options: KubernetesFetchOptions = defaultKubernetesFetchOptions): Promise<k8s.KubernetesObject[]> {
export async function kubernetesFetch(
options: KubernetesFetchOptions = defaultKubernetesFetchOptions,
): Promise<k8s.KubernetesObject[]> {
let client: K8sObjectApi;
let clients: KubernetesClients;
try {
Expand Down Expand Up @@ -229,14 +231,18 @@ export async function kubernetesFetch(options: KubernetesFetchOptions = defaultK
* @param selectors Kubernetes resource selectors to ensure have default values
* @return Properly defaulted Kubernetes resource selectors
*/
export function populateResourceSelectorDefaults(selectors: KubernetesResourceSelector[]): KubernetesResourceSelector[] {
return selectors.map(s => {
const k: KubernetesResourceSelector = { action: "include", ...s };
if (!k.kinds && k.action === "include") {
k.kinds = defaultKubernetesResourceSelectorKinds;
}
return k;
}).filter(s => s.action === "include" || s.filter || s.kinds || s.labelSelector || s.name || s.namespace);
export function populateResourceSelectorDefaults(
selectors: KubernetesResourceSelector[],
): KubernetesResourceSelector[] {
return selectors
.map(s => {
const k: KubernetesResourceSelector = { action: "include", ...s };
if (!k.kinds && k.action === "include") {
k.kinds = defaultKubernetesResourceSelectorKinds;
}
return k;
})
.filter(s => s.action === "include" || s.filter || s.kinds || s.labelSelector || s.name || s.namespace);
}

/**
Expand Down Expand Up @@ -269,7 +275,10 @@ export function includedResourceKinds(selectors: KubernetesResourceSelector[]):
* @param selectors All the resource selectors
* @return A deduplicated array of Kubernetes cluster resource kinds among the inclusion rules
*/
export async function clusterResourceKinds(selectors: KubernetesResourceSelector[], client: K8sObjectApi): Promise<KubernetesResourceKind[]> {
export async function clusterResourceKinds(
selectors: KubernetesResourceSelector[],
client: K8sObjectApi,
): Promise<KubernetesResourceKind[]> {
const included = includedResourceKinds(selectors);
const apiKinds: KubernetesResourceKind[] = [];
for (const apiKind of included) {
Expand Down Expand Up @@ -298,7 +307,6 @@ export async function namespaceResourceKinds(
selectors: KubernetesResourceSelector[],
client: K8sObjectApi,
): Promise<KubernetesResourceKind[]> {

const apiKinds: KubernetesResourceKind[] = [];
for (const selector of selectors.filter(s => s.action === "include")) {
if (nameMatch(ns, selector.namespace)) {
Expand Down Expand Up @@ -381,7 +389,10 @@ export function cleanKubernetesSpec(obj: k8s.KubernetesObject, apiKind: Kubernet
* @param selectors Filtering rules
* @return Filtered array of Kubernetes resources
*/
export function selectKubernetesResources(specs: k8s.KubernetesObject[], selectors: KubernetesResourceSelector[]): k8s.KubernetesObject[] {
export function selectKubernetesResources(
specs: k8s.KubernetesObject[],
selectors: KubernetesResourceSelector[],
): k8s.KubernetesObject[] {
const uniqueSpecs = _.uniqBy(specs, kubernetesResourceIdentity);
if (!selectors || selectors.length < 1) {
return uniqueSpecs;
Expand Down Expand Up @@ -423,7 +434,10 @@ export function kubernetesResourceIdentity(obj: k8s.KubernetesObject): string {
* @param selector Selector to use for checking
* @return Selector action if there is a match, `undefined` otherwise
*/
export function selectorMatch(spec: k8s.KubernetesObject, selector: KubernetesResourceSelector): "include" | "exclude" | undefined {
export function selectorMatch(
spec: k8s.KubernetesObject,
selector: KubernetesResourceSelector,
): "include" | "exclude" | undefined {
if (!nameMatch(spec.metadata.name, selector.name)) {
return undefined;
}
Expand Down
Loading

0 comments on commit 928ee8d

Please sign in to comment.