Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: force option on npx pepr deploy #480

Merged
merged 6 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/cli/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export default function (program: RootCmd) {
.description("Deploy a Pepr Module")
.option("-i, --image [image]", "Override the image tag")
.option("--confirm", "Skip confirmation prompt")
.option("--force", "Force deploy the module, override manager field")
.action(async opts => {
if (!opts.confirm) {
// Prompt the user to confirm
Expand Down Expand Up @@ -46,7 +47,7 @@ export default function (program: RootCmd) {
}

try {
await webhook.deploy();
await webhook.deploy(opts.force);
// Wait for the pepr-system resources to be fully up
await namespaceDeploymentsReady();
console.info(`✅ Module deployed successfully`);
Expand Down
4 changes: 2 additions & 2 deletions src/cli/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ export default function (program: RootCmd) {
const runFork = async () => {
console.info(`Running module ${path}`);

// Deploy the webhook with a 30 second timeout for debugging
await webhook.deploy(30);
// Deploy the webhook with a 30 second timeout for debugging, don't force
await webhook.deploy(false, 30);

program = fork(path, {
env: {
Expand Down
44 changes: 22 additions & 22 deletions src/lib/assets/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { peprStoreCRD } from "./store";
import { webhookConfig } from "./webhooks";
import { CapabilityExport } from "../types";

export async function deploy(assets: Assets, webhookTimeout?: number) {
export async function deploy(assets: Assets, force: boolean, webhookTimeout?: number) {
Log.info("Establishing connection to Kubernetes");

const { name, host, path } = assets;
Expand All @@ -26,7 +26,7 @@ export async function deploy(assets: Assets, webhookTimeout?: number) {
const mutateWebhook = await webhookConfig(assets, "mutate", webhookTimeout);
if (mutateWebhook) {
Log.info("Applying mutating webhook");
await K8s(kind.MutatingWebhookConfiguration).Apply(mutateWebhook);
await K8s(kind.MutatingWebhookConfiguration).Apply(mutateWebhook, { force });
} else {
Log.info("Mutating webhook not needed, removing if it exists");
await K8s(kind.MutatingWebhookConfiguration).Delete(name);
Expand All @@ -36,14 +36,14 @@ export async function deploy(assets: Assets, webhookTimeout?: number) {
const validateWebhook = await webhookConfig(assets, "validate", webhookTimeout);
if (validateWebhook) {
Log.info("Applying validating webhook");
await K8s(kind.ValidatingWebhookConfiguration).Apply(validateWebhook);
await K8s(kind.ValidatingWebhookConfiguration).Apply(validateWebhook, { force });
} else {
Log.info("Validating webhook not needed, removing if it exists");
await K8s(kind.ValidatingWebhookConfiguration).Delete(name);
}

Log.info("Applying the Pepr Store CRD if it doesn't exist");
await K8s(kind.CustomResourceDefinition).Apply(peprStoreCRD);
await K8s(kind.CustomResourceDefinition).Apply(peprStoreCRD, { force });

// If a host is specified, we don't need to deploy the rest of the resources
if (host) {
Expand All @@ -57,66 +57,66 @@ export async function deploy(assets: Assets, webhookTimeout?: number) {
throw new Error("No code provided");
}

await setupRBAC(name, assets.capabilities);
await setupController(assets, code, hash);
await setupWatcher(assets, hash);
await setupRBAC(name, assets.capabilities, force);
await setupController(assets, code, hash, force);
await setupWatcher(assets, hash, force);
}

async function setupRBAC(name: string, capabilities: CapabilityExport[]) {
async function setupRBAC(name: string, capabilities: CapabilityExport[], force: boolean) {
Log.info("Applying cluster role binding");
const crb = clusterRoleBinding(name);
await K8s(kind.ClusterRoleBinding).Apply(crb);
await K8s(kind.ClusterRoleBinding).Apply(crb, { force });

Log.info("Applying cluster role");
const cr = clusterRole(name, capabilities);
await K8s(kind.ClusterRole).Apply(cr);
await K8s(kind.ClusterRole).Apply(cr, { force });

Log.info("Applying service account");
const sa = serviceAccount(name);
await K8s(kind.ServiceAccount).Apply(sa);
await K8s(kind.ServiceAccount).Apply(sa, { force });

Log.info("Applying store role");
const role = storeRole(name);
await K8s(kind.Role).Apply(role);
await K8s(kind.Role).Apply(role, { force });

Log.info("Applying store role binding");
const roleBinding = storeRoleBinding(name);
await K8s(kind.RoleBinding).Apply(roleBinding);
await K8s(kind.RoleBinding).Apply(roleBinding, { force });
}

async function setupController(assets: Assets, code: Buffer, hash: string) {
async function setupController(assets: Assets, code: Buffer, hash: string, force: boolean) {
const { name } = assets;

Log.info("Applying module secret");
const mod = moduleSecret(name, code, hash);
await K8s(kind.Secret).Apply(mod);
await K8s(kind.Secret).Apply(mod, { force });

Log.info("Applying controller service");
const svc = service(name);
await K8s(kind.Service).Apply(svc);
await K8s(kind.Service).Apply(svc, { force });

Log.info("Applying TLS secret");
const tls = tlsSecret(name, assets.tls);
await K8s(kind.Secret).Apply(tls);
await K8s(kind.Secret).Apply(tls, { force });

Log.info("Applying API token secret");
const apiToken = apiTokenSecret(name, assets.apiToken);
await K8s(kind.Secret).Apply(apiToken);
await K8s(kind.Secret).Apply(apiToken, { force });

Log.info("Applying deployment");
const dep = deployment(assets, hash);
await K8s(kind.Deployment).Apply(dep);
await K8s(kind.Deployment).Apply(dep, { force });
}

async function setupWatcher(assets: Assets, hash: string) {
async function setupWatcher(assets: Assets, hash: string, force: boolean) {
// If the module has a watcher, deploy it
const watchDeployment = watcher(assets, hash);
if (watchDeployment) {
Log.info("Applying watcher deployment");
await K8s(kind.Deployment).Apply(watchDeployment);
await K8s(kind.Deployment).Apply(watchDeployment, { force });

Log.info("Applying watcher service");
const watchSvc = watcherService(assets.name);
await K8s(kind.Service).Apply(watchSvc);
await K8s(kind.Service).Apply(watchSvc, { force });
}
}
4 changes: 2 additions & 2 deletions src/lib/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ export class Assets {
this.apiToken = crypto.randomBytes(32).toString("hex");
}

deploy = async (webhookTimeout?: number) => {
deploy = async (force: boolean, webhookTimeout?: number) => {
this.capabilities = await loadCapabilities(this.path);
await deploy(this, webhookTimeout);
await deploy(this, force, webhookTimeout);
};

zarfYaml = (path: string) => zarfYaml(this, path);
Expand Down