205 lines
5.3 KiB
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
|
|
}
|