Skip to content

Commit ace6b92

Browse files
committed
feat: start cloudinit package
1 parent 60a768c commit ace6b92

File tree

16 files changed

+428
-61
lines changed

16 files changed

+428
-61
lines changed

bridge.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
"strings"
7+
)
8+
9+
func SetupNetworkBridge(bridgeName string, ethInterface string, tapInterface string, originalIP string) error {
10+
if err := runCommand("ip", "link", "add", "name", bridgeName, "type", "bridge"); err != nil {
11+
return fmt.Errorf("failed to create bridge: %v", err)
12+
}
13+
14+
if err := runCommand("ip", "link", "set", "dev", bridgeName, "up"); err != nil {
15+
return cleanupBridge(bridgeName, fmt.Errorf("failed to bring bridge up: %v", err))
16+
}
17+
18+
if err := runCommand("ip", "link", "set", ethInterface, "master", bridgeName); err != nil {
19+
return cleanupBridge(bridgeName, fmt.Errorf("failed to add %s to bridge: %v", ethInterface, err))
20+
}
21+
22+
if err := runCommand("ip", "link", "set", "dev", ethInterface, "up"); err != nil {
23+
return cleanupBridge(bridgeName, fmt.Errorf("failed to bring %s up: %v", ethInterface, err))
24+
}
25+
26+
if err := runCommand("ip", "tuntap", "add", "dev", tapInterface, "mode", "tap"); err != nil {
27+
return cleanupBridge(bridgeName, fmt.Errorf("failed to create tap interface: %v", err))
28+
}
29+
30+
if err := runCommand("ip", "link", "set", tapInterface, "master", bridgeName); err != nil {
31+
return cleanupTap(tapInterface, cleanupBridge(bridgeName,
32+
fmt.Errorf("failed to add tap to bridge: %v", err)))
33+
}
34+
35+
if err := runCommand("ip", "link", "set", tapInterface, "up"); err != nil {
36+
return cleanupTap(tapInterface, cleanupBridge(bridgeName,
37+
fmt.Errorf("failed to bring tap up: %v", err)))
38+
}
39+
40+
if originalIP != "" {
41+
if err := runCommand("ip", "addr", "del", originalIP, "dev", ethInterface); err != nil {
42+
return cleanupTap(tapInterface, cleanupBridge(bridgeName,
43+
fmt.Errorf("failed to remove IP from %s: %v", ethInterface, err)))
44+
}
45+
}
46+
47+
return nil
48+
}
49+
50+
func runCommand(command string, args ...string) error {
51+
cmd := exec.Command(command, args...)
52+
if output, err := cmd.CombinedOutput(); err != nil {
53+
return fmt.Errorf("%s: %v, output: %s", strings.Join(cmd.Args, " "), err, string(output))
54+
}
55+
return nil
56+
}
57+
58+
func cleanupBridge(bridgeName string, err error) error {
59+
_ = runCommand("ip", "link", "del", bridgeName)
60+
return err
61+
}
62+
63+
func cleanupTap(tapName string, err error) error {
64+
_ = runCommand("ip", "link", "del", tapName)
65+
return err
66+
}

cloud-init.sh

Lines changed: 0 additions & 6 deletions
This file was deleted.

cloudinit/iso.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package cloudinit
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
)
7+
8+
func CreateCloudInitISO(outputFile string) error {
9+
cmd := exec.Command(
10+
"genisoimage",
11+
"-o", outputFile,
12+
"-volid", "cidata",
13+
"-joliet", "-rock",
14+
"ci-config/user-data",
15+
"ci-config/meta-data",
16+
"ci-config/network-config",
17+
)
18+
19+
output, err := cmd.CombinedOutput()
20+
if err != nil {
21+
return fmt.Errorf("error creating ISO: %v\nOutput: %s", err, string(output))
22+
}
23+
24+
return nil
25+
}

cloudinit/metadata.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package cloudinit
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
8+
"gopkg.in/yaml.v3"
9+
)
10+
11+
type MetaData struct {
12+
InstanceID string `yaml:"instance-id"`
13+
LocalHostname string `yaml:"local-hostname"`
14+
}
15+
16+
func GenerateMetaData(instanceID, localHostname string) (string, error) {
17+
config := MetaData{
18+
InstanceID: instanceID,
19+
LocalHostname: localHostname,
20+
}
21+
22+
yamlData, err := yaml.Marshal(&config)
23+
if err != nil {
24+
return "", fmt.Errorf("error marshal YAML: %w", err)
25+
}
26+
27+
tmpDir := os.TempDir()
28+
filePath := filepath.Join(tmpDir, "meta-data")
29+
30+
err = os.WriteFile(filePath, []byte(yamlData), 0644)
31+
if err != nil {
32+
return "", fmt.Errorf("error writing file: %w", err)
33+
}
34+
35+
return filePath, nil
36+
}

cloudinit/networkconfig.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package cloudinit
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
8+
"gopkg.in/yaml.v3"
9+
)
10+
11+
var DefaultNetplanConfig = NetplanConfig{
12+
Version: 2,
13+
Ethernets: map[string]Ethernet{
14+
"ens3": {
15+
DHCP4: false,
16+
Nameservers: Nameserver{
17+
Addresses: []string{"8.8.8.8", "1.1.1.1"},
18+
},
19+
},
20+
},
21+
}
22+
23+
type NetplanConfig struct {
24+
Version int `yaml:"version"`
25+
Ethernets map[string]Ethernet `yaml:"ethernets"`
26+
}
27+
28+
type Nameserver struct {
29+
Addresses []string `yaml:"addresses"`
30+
}
31+
32+
type Ethernet struct {
33+
DHCP4 bool `yaml:"dhcp4"`
34+
Addresses []string `yaml:"addresses"`
35+
Gateway4 string `yaml:"gateway4"`
36+
Nameservers Nameserver `yaml:"nameservers"`
37+
}
38+
39+
func GenerateNetplanConfig(netplanConfig *NetplanConfig) (string, error) {
40+
yamlData, err := yaml.Marshal(&netplanConfig)
41+
if err != nil {
42+
return "", fmt.Errorf("error marshal YAML: %w", err)
43+
}
44+
45+
tmpDir := os.TempDir()
46+
filePath := filepath.Join(tmpDir, "network-config")
47+
48+
err = os.WriteFile(filePath, []byte(yamlData), 0644)
49+
if err != nil {
50+
return "", fmt.Errorf("error writing file: %w", err)
51+
}
52+
53+
return filePath, nil
54+
}

cloudinit/userdata.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package cloudinit
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
8+
"gopkg.in/yaml.v3"
9+
)
10+
11+
var DefaultUserData = UserData{
12+
Hostname: "my-vm",
13+
ManageEtcHosts: true,
14+
FQDN: "my-vm",
15+
User: "user",
16+
Password: "",
17+
SSHAuthorizedKeys: []string{},
18+
Chpasswd: ChpasswdType{
19+
Expire: false,
20+
},
21+
Users: []string{
22+
"default",
23+
},
24+
}
25+
26+
type ChpasswdType struct {
27+
Expire bool `yaml:"expire"`
28+
}
29+
30+
type UserData struct {
31+
Hostname string `yaml:"hostname"`
32+
ManageEtcHosts bool `yaml:"manage_etc_hosts"`
33+
FQDN string `yaml:"fqdn"`
34+
User string `yaml:"user"`
35+
Password string `yaml:"password"`
36+
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
37+
Chpasswd ChpasswdType `yaml:"chpasswd"`
38+
Users []string `yaml:"users"`
39+
}
40+
41+
func CreateCloudInitFile(userData *UserData) (string, error) {
42+
var config UserData
43+
44+
yamlData, err := yaml.Marshal(&config)
45+
if err != nil {
46+
return "", fmt.Errorf("failed to marshal config: %v", err)
47+
}
48+
49+
yamlContent := "#cloud-config\n" + string(yamlData)
50+
51+
tmpDir := os.TempDir()
52+
filePath := filepath.Join(tmpDir, "user-data")
53+
54+
err = os.WriteFile(filePath, []byte(yamlContent), 0644)
55+
if err != nil {
56+
return "", fmt.Errorf("error writing file: %w", err)
57+
}
58+
59+
return filePath, nil
60+
}

disk.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/exec"
7+
)
8+
9+
func CreateDiskImage(baseImagePath, diskImagePath, diskSize string) error {
10+
if _, err := os.Stat(baseImagePath); os.IsNotExist(err) {
11+
return fmt.Errorf("base image %s does not exist", baseImagePath)
12+
}
13+
14+
if _, err := os.Stat(diskImagePath); err == nil {
15+
fmt.Printf("disk image %s already exists, skipping creation\n", diskImagePath)
16+
return nil
17+
}
18+
19+
cmd := exec.Command(
20+
"qemu-img",
21+
"create",
22+
"-b", baseImagePath,
23+
"-F", "qcow2",
24+
"-f", "qcow2",
25+
diskImagePath,
26+
diskSize,
27+
)
28+
29+
output, err := cmd.CombinedOutput()
30+
if err != nil {
31+
return fmt.Errorf("failed to create disk image: %v, output: %s", err, string(output))
32+
}
33+
34+
if _, err := os.Stat(diskImagePath); os.IsNotExist(err) {
35+
return fmt.Errorf("command succeeded but disk image %s was not created", diskImagePath)
36+
}
37+
38+
return nil
39+
}

docker-bake.hcl

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,39 @@
1+
variable "GO_VERSION" {
2+
default = null
3+
}
4+
5+
variable "DESTDIR" {
6+
default = "./bin"
7+
}
8+
9+
variable "IMAGE" {
10+
default = "erlnby/yadro-app"
11+
}
12+
13+
target "_common" {
14+
dockerfile = "runtime.Dockerfile"
15+
args = {
16+
GO_VERSION = GO_VERSION
17+
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
18+
}
19+
}
20+
121
group "default" {
222
targets = ["runtime", "ubuntu"]
323
}
424

525
target "runtime" {
6-
dockerfile = "runtime.Dockerfile"
26+
inherits = ["_common"]
727
tags = ["devmachines/runtime"]
828
}
929

1030
target "ubuntu" {
1131
dockerfile = "ubuntu.Dockerfile"
1232
tags = ["devmachines/ubuntu"]
1333
}
34+
35+
target "binariy" {
36+
inherits = ["_common"]
37+
target = "binary"
38+
output = ["${DESTDIR}/build"]
39+
}

get-image.sh

Lines changed: 0 additions & 2 deletions
This file was deleted.

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/utkin-tech/devmachines
22

33
go 1.24.2
4+
5+
require gopkg.in/yaml.v3 v3.0.1 // indirect

0 commit comments

Comments
 (0)