Skip to content

Instantly share code, notes, and snippets.

@jabbrwcky
Created March 9, 2022 08:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jabbrwcky/72b23057098bdd707b2c76c46150b615 to your computer and use it in GitHub Desktop.
Save jabbrwcky/72b23057098bdd707b2c76c46150b615 to your computer and use it in GitHub Desktop.
import * as pulumi from "@pulumi/pulumi";
import * as hc from "@pulumi/hcloud";
import { randomUUID } from "crypto";
interface DynamicProviderOutputs {
name: string
configuration: {[index:string]: any};
}
class CtrlConfigurationProvider implements pulumi.dynamic.ResourceProvider {
private name: string;
constructor(name: string) {
this.name = name;
}
async create(inputs: Configuration): Promise<pulumi.dynamic.CreateResult> {
const configuration = {
apiVersion: "k0sctl.k0sproject.io/v1beta1",
kind: "Cluster",
metadata: inputs.metadata,
spec: inputs.spec
}
const outs: DynamicProviderOutputs = {
name: this.name,
configuration,
}
const id = randomUUID()
return {
id: id,
outs
}
}
async check(olds: DynamicProviderOutputs, news: Configuration):Promise<pulumi.dynamic.CheckResult> {
/**
* Any validation failures that occurred.
*/
// readonly failures?: CheckFailure[];
return {
inputs: news
}
}
async read(id: string, props: DynamicProviderOutputs): Promise<pulumi.dynamic.ReadResult> {
return {
id: "k0sconfig",
props: props
};
}
async update(id: string, current: DynamicProviderOutputs, news: Configuration) :Promise<pulumi.dynamic.UpdateResult>{
current.configuration = {
apiVersion: "k0sctl.k0sproject.io/v1beta1",
kind: "Cluster",
metadata: news.metadata,
spec: news.spec
}
return { outs: current };
}
async delete(id: string, props: DynamicProviderOutputs): Promise<void> {
}
async diff(id: string, previousOutput: DynamicProviderOutputs, news: Configuration): Promise<pulumi.dynamic.DiffResult> {
const replaces: string[] = [];
// let changes = false;
let deleteBeforeReplace = false;
return {
deleteBeforeReplace,
replaces,
changes: true,
};
}
}
export interface CtrlConfigurationInputs {
metadata?: pulumi.Inputs;
spec: pulumi.Input<SpecInputs>;
}
const provider = new CtrlConfigurationProvider("k0sctrl")
export class CtrlConfiguration extends pulumi.dynamic.Resource {
public readonly configuration: pulumi.Output<K0sCtrlConfig>;
public readonly file: pulumi.Output<string>;
constructor(name: string, args: CtrlConfigurationInputs, opts?: pulumi.CustomResourceOptions) {
super(provider, `sumcumo:k0s:k0sctrl:configuration:${name}`, {
...args,
configuration: undefined
}, opts);
this.file = pulumi.output(`k0sctl.yaml`)
}
}
export const apiVersion = "k0sctl.k0sproject.io/v1beta1"
export const kind = "Cluster"
export interface K0sCtrlConfig {
apiVersion: string
kind: string
metadata?: { [Index: string]: string };
spec: Spec;
}
/**
* Enumeration of possible cluster roles of a host
*/
export enum Role {
Single = "single",
Worker = "worker",
Controller = "controller",
ControllerAndWorker = "controller+worker",
}
export interface ConfigurationInputs {
apiVersion?: pulumi.Input<string>;
kind?: pulumi.Input<string>;
metadata?: pulumi.Inputs;
spec: pulumi.Input<SpecInputs>
}
export interface Configuration {
metadata?: { [Index: string]: string };
spec: Spec;
}
export interface SpecInputs {
hosts: pulumi.Input<pulumi.Input<HostInputs>[]>;
k0s?: pulumi.Input<K0sInputs>;
}
export interface Spec {
hosts: Host[];
k0s?: K0s;
}
export interface K0sInputs {
version?: pulumi.Input<string>;
config?: pulumi.Input<ClusterConfigurationInputs>;
}
export interface K0s {
version?: string;
config?: ClusterConfiguration;
}
export interface Host {
role: Role;
ssh: SSH;
uploadBinary?: boolean;
k0sBinaryPath?: string;
hostname?: string;
installFlags?: string[];
environment?: { [index: string]: string };
files?: Files[];
hooks?: Hooks[];
privateInterface?: string;
privateAddress?: string;
os?: string;
}
export interface HostInputs {
role: pulumi.Input<Role>;
ssh: pulumi.Input<SSHInputs>;
uploadBinary?: pulumi.Input<boolean>;
k0sBinaryPath?: pulumi.Input<string>;
hostname?: pulumi.Input<string>;
installFlags?: pulumi.Input<pulumi.Input<string>[]>;
environment?: pulumi.Input<{ [index: string]: string }>;
files?: pulumi.Input<pulumi.Input<FilesInputs>[]>;
hooks?: pulumi.Input<pulumi.Input<HooksInputs>[]>;
privateInterface?: pulumi.Input<string>;
privateAddress?: pulumi.Input<string>;
os?: pulumi.Input<string>;
}
export interface SSHInputs extends SSHHostInputs {
bastion?: SSHHostInputs
}
export interface SSHHostInputs{
address: pulumi.Input<string>
user?: pulumi.Input<string>
keyPath?: pulumi.Input<string>
}
export interface SSHHost {
address: string
user?: string
keyPath?: string
}
export interface SSH extends SSHHost{
bastion?: SSHHost
}
export interface Hooks {
apply?: Hook // Runs during k0sctl apply
backup?: Hook //Runs during k0s backup
reset?: Hook // Runs during k0sctl reset
}
export interface HooksInputs {
apply?: pulumi.Input<HookInputs> // Runs during k0sctl apply
backup?: pulumi.Input<HookInputs> //Runs during k0s backup
reset?: pulumi.Input<HookInputs> // Runs during k0sctl reset
}
export interface HookInputs {
before: pulumi.Input<string[]>;
after: pulumi.Input<string[]>;
}
export interface Hook {
before: string[];
after: string[];
}
export interface Files {
name?: string
src: string
dstDir?: string
dst?: string
perm?: string
dirPerm?: string // Directory permission mode for created directories (default: 0755)
user?: string // User name of file/directory owner, must exist on the host (optional)
group?: string// Group name of file/directory own
}
export interface FilesInputs {
name?: pulumi.Input<string>
src: pulumi.Input<string>
dstDir?: pulumi.Input<string>
dst?: pulumi.Input<string>
perm?: pulumi.Input<string>
dirPerm?: pulumi.Input<string> // Directory permission mode for created directories (default: 0755)
user?: pulumi.Input<string> // User name of file/directory owner, must exist on the host (optional)
group?: pulumi.Input<string>// Group name of file/directory own
}
export interface ClusterConfigurationInputs {
apiVersion: pulumi.Input<string>;
kind: pulumi.Input<string>;
metadata?: pulumi.Input<{ [index: string]: string }>;
spec?: pulumi.Input<ClusterSpecInputs>;
}
export interface ClusterConfiguration {
apiVersion: string
kind: string
metadata?: { [index: string]: string }
spec?: ClusterSpec
}
export interface ClusterSpecInputs {
api?: pulumi.Input<APIInputs>;
controllerManager?: pulumi.Input<ProcessInputs>;
scheduler?: pulumi.Input<ProcessInputs>;
storage?: pulumi.Input<StorageInputs>;
network?: pulumi.Input<NetworkInputs>;
podSecurityPolicy?: pulumi.Input<PodSecurityPolicyInputs>;
workerProfiles?: pulumi.Input<WorkerProfileInputs[]>;
extensions?: pulumi.Input<ExtensionsInputs>;
images?: pulumi.Input<ImagesInputs>;
konnectivity?: pulumi.Input<KonnectivityInputs>;
telemetry?: pulumi.Input<TelemetryInputs>;
}
export interface ClusterSpec {
api?: API;
controllerManager?: Process;
scheduler?: Process;
storage?: Storage;
network?: Network;
podSecurityPolicy?: PodSecurityPolicy;
workerProfiles?: WorkerProfile[];
extensions?: Extensions;
images?: Images;
konnectivity?: Konnectivity;
telemetry?: Telemetry;
}
export interface APIInputs {
externalAddress: pulumi.Input<string>;
address?: pulumi.Input<string>;
sans?: pulumi.Input<pulumi.Input<string>[]>;
extraArgs?: pulumi.Input<{ [index: string]: string }>;
}
export interface API {
externalAddress: string;
address?: string;
sans?: string[];
extraArgs?: { [index: string]: string };
}
export interface ExtensionsInputs {
helm?: pulumi.Input<HelmInputs>;
storage?: pulumi.Input<string>;
}
export interface Extensions {
helm?: Helm;
storage?: string;
}
export interface HelmInputs {
repositories: pulumi.Input<RepositoryInputs[]>;
charts: pulumi.Input<ChartInputs[]>;
}
export interface Helm {
repositories: Repository[];
charts: Chart[];
}
export interface ChartInputs {
name: pulumi.Input<string>;
chartname: pulumi.Input<string>;
version: pulumi.Input<string>;
// values?: pulumi.Inputs;
values?: pulumi.Input<string>;
namespace: pulumi.Input<string>;
}
export interface Chart {
name: string;
chartname: string;
version: string;
// values?: {[index:string]: any};
values?: pulumi.Input<string>;
namespace: string;
}
export interface RepositoryInputs {
name: pulumi.Input<string>;
url: pulumi.Input<string>;
}
export interface Repository {
name: string;
url: string;
}
export interface ImagesInputs {
konnectivity?: pulumi.Input<ImageInputs>;
metricsserver?: pulumi.Input<ImageInputs>;
kubeproxy?: pulumi.Input<ImageInputs>;
coredns?: pulumi.Input<ImageInputs>;
calico?: pulumi.Input<CalicoImagesInputs>;
repository?: pulumi.Input<string>;
}
export interface Images {
konnectivity?: Image;
metricsserver?: Image;
kubeproxy?: Image;
coredns?: Image;
calico?: CalicoImages;
repository?: string;
}
export interface CalicoImagesInputs {
cni?: pulumi.Input<ImageInputs>;
flexvolume?: pulumi.Input<ImageInputs>;
node?: pulumi.Input<ImageInputs>;
kubecontrollers?: pulumi.Input<ImageInputs>;
}
export interface CalicoImages {
cni?: Image;
flexvolume?: Image;
node?: Image;
kubecontrollers?: Image;
}
export interface ImageInputs {
image: pulumi.Input<string>;
version: pulumi.Input<string>;
}
export interface Image {
image: string;
version: string;
}
export interface ProcessInputs {
extraArgs: pulumi.Input<{ [index: string]: string }>;
}
export interface Process {
extraArgs: { [index: string]: string };
}
export interface NetworkInputs {
podCIDR?: pulumi.Input<string>;
serviceCIDR?: pulumi.Input<string>;
provider?: pulumi.Input<string>;
calico?: pulumi.Input<CalicoInputs>;
kuberouter?: pulumi.Input<KuberouterInputs>;
}
export interface Network {
podCIDR?: string;
serviceCIDR?: string;
provider?: string;
calico?: Calico;
kuberouter?: Kuberouter;
}
export interface CalicoInputs {
mode?: pulumi.Input<string>;
vxlanPort?: pulumi.Input<number>;
vxlanVNI?: pulumi.Input<number>;
mtu?: pulumi.Input<number>;
wireguard?: pulumi.Input<boolean>;
flexVolumeDriverPath?: pulumi.Input<string>;
}
export interface Calico {
mode?: string;
vxlanPort?: number;
vxlanVNI?: number;
mtu?: number;
wireguard?: boolean;
flexVolumeDriverPath?: string;
}
export interface KuberouterInputs {
autoMTU?: pulumi.Input<boolean>;
mtu?: pulumi.Input<string>;
peerRouterIPs?: pulumi.Input<string>;
peerRouterASNs?: pulumi.Input<string>;
}
export interface Kuberouter {
autoMTU?: boolean;
mtu?: string;
peerRouterIPs?: string;
peerRouterASNs?: string;
}
export interface PodSecurityPolicyInputs {
defaultPolicy: pulumi.Input<string>;
}
export interface PodSecurityPolicy {
defaultPolicy: string;
}
export interface WorkerProfileInputs {
name: pulumi.Input<string>;
values: pulumi.Inputs;
}
export interface WorkerProfile {
name: string;
values: { [index: string]: any };
}
export interface StorageInputs {
type?: pulumi.Input<string>;
etcd?: pulumi.Input<EtcdInputs>;
kine?: pulumi.Input<KineInputs>;
}
export interface Storage {
type?: string;
etcd?: Etcd;
kine?: Kine;
}
export interface EtcdInputs {
peerAddress?: pulumi.Input<string>;
}
export interface Etcd {
peerAddress?: string;
}
export interface KineInputs {
dataSource: pulumi.Input<string>;
}
export interface Kine {
dataSource: string;
}
export interface KonnectivityInputs {
agentPort?: pulumi.Input<number>;
adminPort?: pulumi.Input<number>;
}
export interface Konnectivity {
agentPort?: number;
adminPort?: number;
}
export interface TelemetryInputs {
interval?: pulumi.Input<string>;
enabled?: pulumi.Input<boolean>;
}
export interface Telemetry {
interval?: string;
enabled?: boolean;
}
export interface NodeInputs {
zone: pulumi.Input<string>;
type: pulumi.Input<string>;
placementGroupId: pulumi.Input<string>;
sshKeys: pulumi.Input<pulumi.Input<string>[]>;
role: pulumi.Input<Role>;
networkId: pulumi.Input<string>;
}
export class Node extends pulumi.ComponentResource {
public readonly role: pulumi.Output<Role>;
public readonly ip: pulumi.Output<string>;
public readonly privateIp: pulumi.Output<string>;
constructor(name: string, args: NodeInputs, opts?: pulumi.ComponentResourceOptions) {
super("k0s:node", name, args, opts);
this.role = pulumi.output(args.role);
let labels = this.role.apply((r) => {
return {
role: r.replace("+worker", "")
}
})
const n = pulumi.all([labels]).apply(([l]) => new hc.Server(`${name}-srv`, {
image: "ubuntu-20.04",
serverType: args.type,
location: args.zone,
placementGroupId: pulumi.output(args.placementGroupId).apply(Number.parseInt),
sshKeys: args.sshKeys,
labels: l,
}, { parent: this }));
let serverID = n.id.apply(Number.parseInt);
let sn = new hc.ServerNetwork(`${name}-nw`, {
serverId: serverID,
networkId: pulumi.output(args.networkId).apply(Number.parseInt),
}, { parent: this });
this.privateIp = sn.ip;
this.ip = n.ipv4Address;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment