platform/main.go

205 lines
5.3 KiB
Go

package main
import (
"fmt"
"os"
"strconv"
"github.com/pulumi/pulumi-linode/sdk/v3/go/linode"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)
func main() {
pulumi.Run(infra)
}
func infra(ctx *pulumi.Context) error {
cfg := config.New(ctx, "")
platformConfigFile := cfg.Require("file")
p, err := newConfig(platformConfigFile)
if err != nil {
return fmt.Errorf("unable to load the platform configuration; %w", err)
}
instanceDetails, err := instance(ctx, p);
if err != nil {
return fmt.Errorf("unable to manage the instance; %w", err)
}
if err := domain(ctx, p); err != nil {
return fmt.Errorf("unable to manage the domain; %w", err)
}
if err := records(ctx, p, instanceDetails.ipv4); err != nil {
return fmt.Errorf("unable to manage the domain records; %w", err)
}
if err := firewall(ctx, p, instanceDetails.id); err != nil {
return fmt.Errorf("unable to manage the firewall; %w", err)
}
if err := volumes(ctx, p, instanceDetails.id); err != nil {
return fmt.Errorf("unable to manage the volumes; %w", err)
}
if err := readme(ctx); err != nil {
return fmt.Errorf("unable to add the README to the Stack; %w", err)
}
return nil
}
func domain(ctx *pulumi.Context, cfg *platform) error {
domainArgs := linode.DomainArgs{
Description: pulumi.String(cfg.Domain.Description),
Domain: pulumi.String(cfg.Domain.Name),
SoaEmail: pulumi.String(cfg.Domain.Email),
Status: pulumi.String("active"),
Tags: pulumi.ToStringArray(cfg.Tags),
Type: pulumi.String(cfg.Domain.Type),
}
_, err := linode.NewDomain(ctx, cfg.Domain.Name, &domainArgs, pulumi.Protect(true))
if err != nil {
return err
}
return nil
}
func records(ctx *pulumi.Context, cfg *platform, instanceIPv4 pulumi.StringInput) error {
domainName := cfg.Domain.Name
domainArgs := linode.LookupDomainArgs{
Domain: &domainName,
}
domain, err := linode.LookupDomain(ctx, &domainArgs, nil)
if err != nil {
return fmt.Errorf("unable to lookup domain %s; %w", domainName, err)
}
domainID, err := strconv.Atoi(*domain.Id)
if err != nil {
return fmt.Errorf("unable to get the Domain ID; %w", err)
}
for _, r := range cfg.Domain.Records {
args := linode.DomainRecordArgs{
DomainId: pulumi.Int(domainID),
Name: pulumi.String(r.Name),
RecordType: pulumi.String(r.Type),
Target: instanceIPv4,
TtlSec: pulumi.Int(r.TtlSec),
}
_, err := linode.NewDomainRecord(ctx, r.Label, &args, nil)
if err != nil {
return fmt.Errorf("unable to update the domain record '%s'; %w", r.Name, err)
}
}
return nil
}
func firewall(ctx *pulumi.Context, cfg *platform, instanceID pulumi.IntInput) error {
inbounds := linode.FirewallInboundArray{}
for _, a := range cfg.Firewall.Inbound.Allow {
allow := linode.FirewallInboundArgs{
Label: pulumi.String(a.Label),
Action: pulumi.String("ACCEPT"),
Protocol: pulumi.String(a.Protocol),
Ports: pulumi.String(a.Ports),
Ipv4s: pulumi.ToStringArray(a.SourceIpv4s),
Ipv6s: pulumi.ToStringArray(a.SourceIpv6s),
}
inbounds = append(inbounds, allow)
}
firewallArgs := linode.FirewallArgs{
Label: pulumi.String(cfg.Firewall.Label),
Tags: pulumi.ToStringArray(cfg.Tags),
InboundPolicy: pulumi.String("DROP"),
Inbounds: inbounds,
OutboundPolicy: pulumi.String("ACCEPT"),
Linodes: pulumi.IntArray{
instanceID,
},
}
_, err := linode.NewFirewall(ctx, cfg.Firewall.Label, &firewallArgs)
if err != nil {
return fmt.Errorf("unable to update the firewall; %w", err)
}
return nil
}
func volumes(ctx *pulumi.Context, cfg *platform, instanceID pulumi.IntInput) error {
for _, v := range cfg.Volumes {
args := linode.VolumeArgs{
Label: pulumi.String(v.Label),
LinodeId: instanceID,
Region: pulumi.String(cfg.Region),
Size: pulumi.Int(v.Size),
Tags: pulumi.ToStringArray(cfg.Tags),
}
_, err := linode.NewVolume(ctx, v.Label, &args, pulumi.Protect(true))
if err != nil {
return fmt.Errorf("unable to update volume; %w", err)
}
}
return nil
}
type instanceOutput struct {
ipv4 pulumi.StringOutput
id pulumi.IntOutput
}
func instance(ctx *pulumi.Context, cfg *platform) (instanceOutput, error) {
instanceArgs := linode.InstanceArgs{
BackupsEnabled: pulumi.Bool(cfg.Instance.BackupsEnabled),
Label: pulumi.String(cfg.Instance.Label),
PrivateIp: pulumi.Bool(cfg.Instance.PrivateIp),
Region: pulumi.String(cfg.Region),
Tags: pulumi.ToStringArray(cfg.Tags),
SwapSize: pulumi.Int(cfg.Instance.SwapSize),
Type: pulumi.String(cfg.Instance.Type),
WatchdogEnabled: pulumi.Bool(cfg.Instance.WatchdogEnabled),
}
instance, err := linode.NewInstance(ctx, cfg.Instance.Label, &instanceArgs, pulumi.Protect(true))
if err != nil {
return instanceOutput{}, fmt.Errorf("unable to update instance; %w", err)
}
instanceID := instance.ID().ToStringOutput().ApplyT(func(id string) (int, error) {
return strconv.Atoi(id)
}).(pulumi.IntOutput)
output := instanceOutput{
id: instanceID,
ipv4: instance.IpAddress,
}
return output, nil
}
func readme(ctx *pulumi.Context) error {
data, err := os.ReadFile("./README.md")
if err != nil {
return fmt.Errorf("unable to read README.md; %w", err)
}
ctx.Export("readme", pulumi.String(string(data)))
return nil
}