From 03cd6bdfbd473dba3f3dc50a1b15e389aac5bc70 Mon Sep 17 00:00:00 2001 From: Leonardo Bishop Date: Wed, 7 Jan 2026 23:39:53 +0000 Subject: Initial commit --- pkg/deployer/instance.go | 163 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 pkg/deployer/instance.go (limited to 'pkg/deployer/instance.go') diff --git a/pkg/deployer/instance.go b/pkg/deployer/instance.go new file mode 100644 index 0000000..99171f4 --- /dev/null +++ b/pkg/deployer/instance.go @@ -0,0 +1,163 @@ +package deployer + +import ( + "context" + "fmt" + "log/slog" + "strconv" + "time" + + "github.com/moby/moby/client" +) + +type Instance struct { + ChallengeName string + DeployKey string + Address string + AddressFormat string + ExpiresAt time.Time +} + +func (d *DockerDeployer) GetTeamInstances(ctx context.Context, team string) ([]Instance, error) { + filters := client.Filters{} + filters.Add("label", ContainerLabelForTeam+"="+team) + + containers, err := d.client.ContainerList(ctx, client.ContainerListOptions{ + All: true, + Filters: filters, + }) + if err != nil { + return []Instance{}, err + } + + var instances []Instance + for _, c := range containers.Items { + expiresAt, err := strconv.Atoi(c.Labels[ContainerLabelExpiresAt]) + if err != nil { + slog.Error("container has invalid expiry", "container", c.ID, "expiry", c.Labels[ContainerLabelExpiresAt]) + continue + } + instances = append(instances, Instance{ + ChallengeName: c.Labels[ContainerLabelChallenge], + DeployKey: c.Labels[ContainerLabelDeployKey], + Address: c.Labels[ContainerLabelAddress], + AddressFormat: c.Labels[ContainerLabelAddressFormat], + ExpiresAt: time.Unix(int64(expiresAt), 0), + }) + } + return instances, nil +} + +func (d *DockerDeployer) StopInstance(ctx context.Context, deployKey, team string) error { + if deployKey == "" || team == "" { + return fmt.Errorf("deploy key/team is invalid") + } + + filters := client.Filters{} + filters.Add("label", ContainerLabelForTeam+"="+team) + filters.Add("label", ContainerLabelDeployKey+"="+deployKey) + + containers, err := d.client.ContainerList(ctx, client.ContainerListOptions{ + All: true, + Filters: filters, + }) + if err != nil { + return fmt.Errorf("docker error") + } + + if len(containers.Items) == 0 { + return fmt.Errorf("no such instance") + } + + for _, c := range containers.Items { + _, err := d.client.ContainerRemove(ctx, c.ID, client.ContainerRemoveOptions{ + Force: true, + }) + if err != nil { + return fmt.Errorf("docker error") + } + slog.Info("container removed early", "container", c.ID) + } + + networks, err := d.client.NetworkList(ctx, client.NetworkListOptions{}) + if err != nil { + return fmt.Errorf("docker error") + } + for _, n := range networks.Items { + if err = d.forceRemoveNetwork(ctx, n.ID); err != nil { + slog.Warn("failed to remove network", "network", n.ID) + continue + } + slog.Info("network removed early", "network", n.ID) + } + + return nil +} + +func (d *DockerDeployer) RemoveExpiredResources(ctx context.Context) error { + filters := client.Filters{} + filters.Add("label", ContainerLabelManaged+"=yes") + + containers, err := d.client.ContainerList(ctx, client.ContainerListOptions{ + All: true, + Filters: filters, + }) + if err != nil { + return err + } + for _, c := range containers.Items { + expiry, err := strconv.ParseInt(c.Labels[ContainerLabelExpiresAt], 10, 64) + if err != nil { + slog.Warn("invalid timestamp on container label", "container", c.ID, "timestamp", c.Labels[ContainerLabelExpiresAt]) + continue + } + if expiry > time.Now().Unix() { + continue + } + + _, err = d.client.ContainerRemove(ctx, c.ID, client.ContainerRemoveOptions{ + Force: true, + }) + if err != nil { + return err + } + slog.Info("expired container removed", "container", c.ID) + } + + networks, err := d.client.NetworkList(ctx, client.NetworkListOptions{ + Filters: filters, + }) + if err != nil { + return err + } + for _, n := range networks.Items { + expiry, err := strconv.ParseInt(n.Labels[ContainerLabelExpiresAt], 10, 64) + if err != nil { + slog.Warn("invalid timestamp on network label", "network", n.ID, "timestamp", n.Labels[ContainerLabelExpiresAt]) + continue + } + if expiry > time.Now().Unix() { + continue + } + + if err = d.forceRemoveNetwork(ctx, n.ID); err != nil { + return err + } + slog.Info("expired network removed", "network", n.ID) + } + + return nil +} + +func (d *DockerDeployer) forceRemoveNetwork(ctx context.Context, networkID string) error { + _, _ = d.client.NetworkDisconnect(ctx, networkID, client.NetworkDisconnectOptions{ + Container: d.proxyContainerName, + Force: true, + }) + + _, err := d.client.NetworkRemove(ctx, networkID, client.NetworkRemoveOptions{}) + if err != nil { + return err + } + return nil +} -- cgit v1.2.3-70-g09d2