diff --git a/README.md b/README.md index 2e4706e5..0301bf4f 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,10 @@ Visit The full documentation here: https://preevy.dev/ - [Notice on preview environments exposure](#notice-on-preview-environments-exposure) - [Configuration files](#configuration-files) - [Preevy-specific configuration](#preevy-specific-configuration) -- [Plugins](#plugins) + - [`driver`](#driver) + - [`drivers`](#drivers) + - [`plugins`](#plugins) +- [Plugins](#plugins-1) - [Docs and support](#docs-and-support) - [Telemetry](#telemetry) @@ -185,16 +188,54 @@ An additional option `--system-compose-file` can be used to specify paths to Com ### Preevy-specific configuration -Additional Preevy-specific configuration, if needed, can be specified by adding a `x-preevy` top-level element to the Compose file(s). Currently only the `plugins` section is supported: +Additional Preevy-specific configuration, if needed, can be specified by adding a `x-preevy` top-level element to the Compose file(s). ```yaml services: ... x-preevy: + driver: lightsail + drivers: + lightsail: + region: eu-central-1 + kube-pod: + context: dev-cluster plugins: ... ``` +The following optional properties are supported: + +### `driver` + + +Override the default [driver](https://preevy.dev/category/drivers) to use for this Compose project. +Available values: `lightsail`, `gce`, `azure`, `kube-pod`. + + +This value can be overridden per command execution using the `--driver` CLI flag. + +### `drivers` + + +Override the default the default options per driver for this Compose project. See the [specific driver documentation](https://preevy.dev/category/drivers). + + +These values can be overridden per command execution using the specific driver CLI flags, e.g, `--lightsail-bundle-id=2xlarge_2_0` + +Example: + +```yaml +x-preevy: + drivers: + lightsail: + bundle-id: large_2_0 + kube-pod: + context: dev-cluster +``` + +### `plugins` + See [Plugins](#plugins) below. diff --git a/packages/cli/src/driver-command.ts b/packages/cli/src/driver-command.ts index 5e5d529a..526e2d7b 100644 --- a/packages/cli/src/driver-command.ts +++ b/packages/cli/src/driver-command.ts @@ -1,7 +1,7 @@ import { Command, Flags, Interfaces } from '@oclif/core' import { MachineConnection, MachineDriver, isPartialMachine, profileStore } from '@preevy/core' import { pickBy } from 'lodash' -import { DriverFlags, DriverName, flagsForAllDrivers, machineDrivers, removeDriverPrefix } from './drivers' +import { DriverFlags, DriverName, FlagType, flagsForAllDrivers, machineDrivers, removeDriverPrefix } from './drivers' import ProfileCommand from './profile-command' // eslint-disable-next-line no-use-before-define @@ -25,7 +25,7 @@ abstract class DriverCommand extends ProfileCommand public async init(): Promise { await super.init() - this.#driverName = this.flags.driver ?? this.profile.driver as DriverName + this.#driverName = this.flags.driver ?? this.preevyConfig?.driver as DriverName ?? this.profile.driver as DriverName } #driverName: DriverName | undefined @@ -36,23 +36,32 @@ abstract class DriverCommand extends ProfileCommand return this.#driverName } + protected async driverFlags( + driver: Name, + type: Type + ): Promise> { + const driverFlagNames = Object.keys(machineDrivers[driver][type]) + const flagDefaults = pickBy( + { + ...await profileStore(this.store).defaultFlags(driver), + ...this.preevyConfig.drivers?.[driver] ?? {}, + }, + (_v, k) => driverFlagNames.includes(k), + ) as DriverFlags + return { + ...flagDefaults, + ...removeDriverPrefix>(driver, this.flags), + } + } + #driver: MachineDriver | undefined async driver(): Promise { if (this.#driver) { return this.#driver } const { profile, driverName } = this - const driverFlagNames = Object.keys(machineDrivers[driverName].flags) - const defaultFlags = pickBy( - await profileStore(this.store).defaultFlags(driverName), - (_v, k) => driverFlagNames.includes(k), - ) - const driverFlags = { - ...defaultFlags, - ...removeDriverPrefix>(driverName, this.flags), - } this.#driver = machineDrivers[driverName].factory({ - flags: driverFlags as never, + flags: await this.driverFlags(driverName, 'flags') as never, profile, store: this.store, log: this.logger, diff --git a/packages/cli/src/drivers.ts b/packages/cli/src/drivers.ts index 17558bbd..aabba7f6 100644 --- a/packages/cli/src/drivers.ts +++ b/packages/cli/src/drivers.ts @@ -18,7 +18,7 @@ type MachineDrivers = typeof machineDrivers export type DriverName = keyof MachineDrivers -type FlagType = 'flags' | 'machineCreationFlags' +export type FlagType = 'flags' | 'machineCreationFlags' export type DriverFlagName< Name extends DriverName, diff --git a/packages/cli/src/machine-creation-driver-command.ts b/packages/cli/src/machine-creation-driver-command.ts index 614ac614..a5a5d3c1 100644 --- a/packages/cli/src/machine-creation-driver-command.ts +++ b/packages/cli/src/machine-creation-driver-command.ts @@ -1,8 +1,8 @@ import { Command, Flags, Interfaces } from '@oclif/core' -import { MachineCreationDriver, profileStore } from '@preevy/core' +import { MachineCreationDriver } from '@preevy/core' import { BaseCommand } from '@preevy/cli-common' import DriverCommand from './driver-command' -import { DriverFlags, DriverName, machineCreationflagsForAllDrivers, machineDrivers, removeDriverPrefix } from './drivers' +import { machineCreationflagsForAllDrivers, machineDrivers } from './drivers' // eslint-disable-next-line no-use-before-define export type Flags = Interfaces.InferredFlags @@ -24,11 +24,8 @@ abstract class MachineCreationDriverCommand extends Dr return this.#machineCreationDriver } const { profile, driverName } = this - const defaultFlags = await profileStore(this.store).defaultFlags(driverName) - const specifiedFlags = removeDriverPrefix>(this.driverName, this.flags) - const driverFlags = { ...defaultFlags, ...specifiedFlags } this.#machineCreationDriver = machineDrivers[driverName].machineCreationFactory({ - flags: driverFlags as never, + flags: await this.driverFlags(driverName, 'machineCreationFlags') as never, profile, store: this.store, log: this.logger, diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index d89578ba..b7675bef 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -6,4 +6,6 @@ export type PreevyPluginConfig = { export type PreevyConfig = { plugins?: PreevyPluginConfig[] + driver?: string + drivers?: Record> } diff --git a/packages/driver-azure/src/driver/index.ts b/packages/driver-azure/src/driver/index.ts index df6818a3..0fa1a3e3 100644 --- a/packages/driver-azure/src/driver/index.ts +++ b/packages/driver-azure/src/driver/index.ts @@ -179,26 +179,17 @@ const DEFAULT_VM_SIZE = 'Standard_B2s' const machineCreationFlags = { ...flags, - region: Flags.string({ - description: 'Microsoft Azure region in which resources will be provisioned', - required: true, - }), 'vm-size': Flags.string({ description: 'Machine type to be provisioned', default: DEFAULT_VM_SIZE, required: false, }), - 'resource-group-name': Flags.string({ - description: 'Microsoft Azure resource group name', - required: true, - }), } as const type MachineCreationFlagTypes = Omit, 'json'> type MachineCreationContext = DriverContext & { vmSize?: string - resourceGroupId: string metadata: MachineCreationFlagTypes } @@ -273,10 +264,9 @@ const factory: MachineDriverFactory< const machineCreationContextFromFlags = ( f: MachineCreationFlagTypes, -): ReturnType & { vmSize: string; resourceGroupId: string } => ({ +): ReturnType & { vmSize: string } => ({ ...contextFromFlags(f), vmSize: f['vm-size'], - resourceGroupId: f['resource-group-name'], }) const machineCreationFactory: MachineCreationDriverFactory< diff --git a/packages/driver-kube-pod/src/driver/client/index.ts b/packages/driver-kube-pod/src/driver/client/index.ts index 68ebe432..1ed8ca6a 100644 --- a/packages/driver-kube-pod/src/driver/client/index.ts +++ b/packages/driver-kube-pod/src/driver/client/index.ts @@ -29,7 +29,7 @@ import { import { Package } from './common' import { logError } from './log-error' -export const loadKubeConfig = (kubeconfig?: string, context?:string) => { +export const loadKubeConfig = (kubeconfig?: string, context?: string) => { const kc = new k8s.KubeConfig() if (kubeconfig) { kc.loadFromFile(kubeconfig) diff --git a/site/docs/drivers/aws-lightsail.md b/site/docs/drivers/aws-lightsail.md index d5403b68..abe9b5a5 100644 --- a/site/docs/drivers/aws-lightsail.md +++ b/site/docs/drivers/aws-lightsail.md @@ -5,13 +5,41 @@ title: AWS Lightsail Driver # AWS Lightsail Driver -Preevy can provision virtual machines on AWS Lightsail using the `aws-lightsail` driver. +Preevy can provision virtual machines on AWS Lightsail using the `lightsail` driver. [AWS lightsail](https://aws.amazon.com/lightsail) is Amazon's cost-effective solution for VMs in the cloud. AWS lightsail provisioning time for a VM is usually around 2 minutes, and its cost can be as low as $3.50 per month making them suitable for preview environments at scale. -### Supported flags -- `--aws-region` - The AWS region to use. +### Supported options + +| option | flag | description | required | default | +| ------ | ---- | ----------- | -------- | ------- | +| `region` | `--lightsail-region` | AWS region in which resources will be provisioned | required | (none) | +| `bundle-id` | `--lightsail-bundle-id` | Lightsail bundle ID (size of instance) to provision | optional | `medium_2_0` | +| `availability-zone` | `--lightsail-availability-zone` | AWS zone to provision resources in region | optional | (first AZ in zone) | + +### Overriding options + +Similar to other drivers, options are saved in the Preevy profile to be used as default values for all operations. + +Options can be overridden for a specific compose file by adding them to the `x-preevy` section: + +```yaml +services: + ... +x-preevy: + driver: lightsail + drivers: + lightsail: + # use a larger instance for this project + bundle-id: xlarge_2_0 +``` + +Options can also be overridden using a CLI flag per command execution: + +```bash +preevy up ---lightsail-bundle-id=xlarge_2_0 +``` ### Credentials Configuration Preevy uses the AWS JS SDK which supports multiple ways of configuring credentials, according to the [credentials provider chain](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html). diff --git a/site/docs/drivers/azure.md b/site/docs/drivers/azure.md index ad6df177..85d36566 100644 --- a/site/docs/drivers/azure.md +++ b/site/docs/drivers/azure.md @@ -8,11 +8,35 @@ title: Microsoft Azure Driver Preevy can provision virtual machines on Microsoft Azure using the `azure` driver. Microsoft Azure also offers free 12 months for new users which is suited for trying out preevy. -### Supported flags -- `--azure-region` - Microsoft Azure region in which resources will be provisioned -- `--azure-resource-group-name` - Microsoft Azure resource group name -- `--azure-subscription-id` - Microsoft Azure subscription id -- `--azure-vm-size` - Machine type to be provisioned, defaults to `Standard_B2s` +### Supported options + +| option | flag | description | required | default | +| ------ | ---- | ----------- | -------- | ------- | +| `region` | `--azure-region` | Microsoft Azure region in which resources will be provisioned | required | (none) | +| `subscription-id` | `--azure-subscription-id` | Microsoft Azure subsription ID | required | (none) | +| `vm-size` | `--azure-vm-size` | Machine type to be provisioned | optional | `Standard_B2s` | + +### Overriding options + +Similar to other drivers, options are saved in the Preevy profile to be used as default values for all operations. + +Options can be overridden for a specific compose file by adding them to the `x-preevy` section: + +```yaml +services: + ... +x-preevy: + driver: azure + drivers: + azure: + vm-size: DS3_v2 +``` + +Options can also be overridden using a CLI flag per command execution: + +```bash +preevy up --azure-vm-size=DS3_v2 +``` ### Credentials Configuration Preevy uses the Microsoft Azure SDK which can obtain the application [default credentials](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#defaultazurecredential). diff --git a/site/docs/drivers/gcp-gce.md b/site/docs/drivers/gcp-gce.md index 32004d44..cf70e293 100644 --- a/site/docs/drivers/gcp-gce.md +++ b/site/docs/drivers/gcp-gce.md @@ -9,10 +9,35 @@ Preevy can provision virtual machines on GCP using the `gce` driver. Google compute engine provisioning time for a VM is usually less than a minute, the default machine size in use is e2-small (2GB, 2vCpu) which costs around $12 per month. Google compute also offer $300 free credit for new users which is suited for trying out preevy. -### Supported flags -- `--gce-machine-type` - Machine type to be provisioned. -- `--gce-profile-id` - Google Cloud project ID. -- `--gce-zone` - Google Cloud zone in which resources will be provisioned. +### Supported options + +| option | flag | description | required | default | +| ------ | ---- | ----------- | -------- | ------- | +| `project-id` | `--gce-project-id` | Google Cloud project ID | required | (none) | +| `zone` | `--gce-zone` | Google Cloud zone in which resources will be provisioned | required | (none) | +| `machine-type` | `--gce-machine-type` | Machine type to be provisioned | optional | `e2-small` | + +### Overriding options + +Similar to other drivers, options are saved in the Preevy profile to be used as default values for all operations. + +Options can be overridden for a specific compose file by adding them to the `x-preevy` section: + +```yaml +services: + ... +x-preevy: + driver: gce + drivers: + gce: + machine-type: e2-medium +``` + +Options can also be overridden using a CLI flag per command execution: + +```bash +preevy up --gce-machine-type=e2-medium +``` ### Credentials Configuration Preevy uses the Google SDK which uses application default credentials (https://cloud.google.com/docs/authentication/application-default-credentials). diff --git a/site/docs/drivers/kube-pod.md b/site/docs/drivers/kube-pod.md index c9dd565d..568dee26 100644 --- a/site/docs/drivers/kube-pod.md +++ b/site/docs/drivers/kube-pod.md @@ -31,16 +31,36 @@ Your services are still exposed using the Preevy Tunnel Service - there's no nee - The [`kubectl`](https://kubernetes.io/docs/tasks/tools/#kubectl) tool needs to be installed and available in the PATH. - By default, the driver runs a Pod with [`privileged: true` security context](https://kubernetes.io/docs/concepts/security/pod-security-standards/#privileged). In some cases, this requirement may be lifted by customizing the deployment template, see [below](#configuring-rootless-unprivileged-docker-in-docker). -## Supported flags +## Supported options -|flag|default|env var|description| -|---|--------|-------|-----------| -|`--kube-pod-namespace`|`default`| |Kubernetes namespace to provision resources in| -|`--kube-pod-kubeconfig`|`$HOME/.kube`| `KUBECONFIG` | path to a [`kubeconfig`](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) file| -|`--kube-pod-template`|[default template](https://github.com/livecycle/preevy/blob/main/packages/driver-kube-pod/static/default-template.yaml.njk)| |path to a [nunjacks template](https://mozilla.github.io/nunjucks/templating.html) used to provision Kubernetes resources per environment. See [below](#customizing-the-provisioned-kubernetes-resources) for details| -|`--no-kube-pod-server-side-apply`| | | provision resources using client-side apply (CREATE/PATCH) instead of [server-side apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/). Applies to `preevy up` only| +| option | flag | default | env var | description | +| ---- | --- | -------- | ------- | ----------- | +|`namespace`|`--kube-pod-namespace`|`default`| |Kubernetes namespace to provision resources in| +|`kubeconfig`|`--kube-pod-kubeconfig`|`$HOME/.kube`| `KUBECONFIG` | path to a [`kubeconfig`](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) file| +|`pod-template`|`--kube-pod-template`|[default template](https://github.com/livecycle/preevy/blob/main/packages/driver-kube-pod/static/default-template.yaml.njk)| |path to a [nunjacks template](https://mozilla.github.io/nunjucks/templating.html) used to provision Kubernetes resources per environment. See [below](#customizing-the-provisioned-kubernetes-resources) for details| +|`server-side-apply`|`--[no-]kube-pod-server-side-apply`| true | | if true, provision resources using [server-side apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/), else using client-side apply (CREATE/PATCH). Applies to `preevy up` only| -Similar to other drivers, flags are saved in the Preevy profile to be used as default values for all operations. They can be specified per command if the defaults need to be changed. For example, if a specific environment needs to be provisioned in a different Kubernetes namespace, specify `--kube-pod-namespace=other-namespace` when running the `preevy up` command. +### Overriding options + +Similar to other drivers, options are saved in the Preevy profile to be used as default values for all operations. + +Options can be overridden for a specific compose file by adding them to the `x-preevy` section: + +```yaml +services: + ... +x-preevy: + driver: kube-pod + drivers: + kube-pod: + namespace: other-namespace +``` + +Options can also be overridden using a CLI flag per command execution: + +```bash +preevy up --kube-pod-namespace=other-namespace +``` ## Customizing the provisioned Kubernetes resources