-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from andygeorge/andygeorge/injection-go
Rewrite in Golang
- Loading branch information
Showing
7 changed files
with
282 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
example_files/ | ||
output/ | ||
/go/build/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
variant: fcos | ||
version: 1.4.0 | ||
|
||
storage: | ||
directories: | ||
- path: /tmp/example | ||
mode: 0755 | ||
|
||
- path: /tmp/example2 | ||
|
||
- path: /tmp/example3/example4 | ||
mode: 0744 | ||
|
||
files: | ||
- path: /tmp/example/hello_world.txt | ||
contents: | ||
inline: | | ||
Hello, world! | ||
|
||
- path: /tmp/example/hello_world_gzip.txt | ||
mode: 0644 | ||
contents: | ||
inline: | | ||
This is a much larger Hello World file that will use gzip compression | ||
in the Ignition. Lorem ipsum dolor sit amet, consectetur adipisicing | ||
elit, sed do eiusmod tempor incididunt ut labore et dolore magna | ||
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco | ||
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor | ||
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla | ||
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in | ||
culpa qui officia deserunt mollit anim id est laborum. | ||
|
||
systemd: | ||
units: | ||
- name: hello-world.service | ||
enabled: true | ||
contents: | | ||
[Unit] | ||
Description=Hello world service | ||
|
||
[Service] | ||
Type=oneshot | ||
ExecStart=/usr/bin/echo "hello world" | ||
StandardOutput=journal | ||
|
||
[Install] | ||
WantedBy=multi-user.target default.target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# injection-go | ||
`injection` built in Go. | ||
|
||
```shell | ||
# generate ignition | ||
butane --strict ../example_files/example.bu > ../example_files/example.ign | ||
|
||
# build injection | ||
go mod tidy && go fmt *.go && go build -o build/ | ||
|
||
# run injection | ||
./build/injection ../example_files/example.ign | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module injection | ||
|
||
go 1.19 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
package main | ||
|
||
import ( | ||
"compress/gzip" | ||
"encoding/base64" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"net/url" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
) | ||
|
||
const ( | ||
DefaultDirectoryMode os.FileMode = 0755 | ||
DefaultFileMode os.FileMode = 0644 | ||
DefaultSystemdUnitFileMode os.FileMode = 0644 | ||
DefaultSystemdUnitPath string = "/etc/systemd/system" | ||
) | ||
|
||
type IgnitionConfig struct { | ||
Storage struct { | ||
Directories []struct { | ||
Path string `json:"path"` | ||
Mode int `json:"mode"` | ||
} `json:"directories"` | ||
Files []struct { | ||
Path string `json:"path"` | ||
Mode int `json:"mode"` | ||
Contents struct { | ||
Compression string `json:"compression"` | ||
Source string `json:"source"` | ||
} `json:"contents"` | ||
} `json:"files"` | ||
} `json:"storage"` | ||
Systemd struct { | ||
Units []struct { | ||
Name string `json:"name"` | ||
Enabled bool `json:"enabled"` | ||
Contents string `json:"contents"` | ||
} `json:"units"` | ||
} `json:"systemd"` | ||
} | ||
|
||
func main() { | ||
var filename string | ||
var ignitionConfig IgnitionConfig | ||
var err error | ||
|
||
args := os.Args[1:] | ||
|
||
if len(args) < 1 { | ||
fmt.Println("Specify a filename!") | ||
os.Exit(1) | ||
} else { | ||
filename = args[0] | ||
} | ||
|
||
readFile, err := os.ReadFile(filename) | ||
check(err) | ||
|
||
err = json.Unmarshal([]byte(string(readFile)), &ignitionConfig) | ||
check(err) | ||
|
||
err = WriteDirectories(ignitionConfig) | ||
check(err) | ||
|
||
err = WriteFiles(ignitionConfig) | ||
check(err) | ||
|
||
err = WriteUnits(ignitionConfig) | ||
check(err) | ||
} | ||
|
||
func OpenFile(path string, mode os.FileMode) (*os.File, error) { | ||
options := os.O_WRONLY | os.O_TRUNC | os.O_CREATE | ||
|
||
return os.OpenFile(path, options, mode) | ||
} | ||
|
||
func WriteDirectories(ignitionConfig IgnitionConfig) error { | ||
var err error | ||
|
||
for _, directoryConfig := range ignitionConfig.Storage.Directories { | ||
path := directoryConfig.Path | ||
mode := DefaultDirectoryMode | ||
fmt.Println(path) | ||
|
||
if directoryConfig.Mode != 0 { | ||
mode = os.FileMode(directoryConfig.Mode) | ||
} | ||
|
||
if _, err = os.Stat(path); os.IsNotExist(err) { | ||
err = os.MkdirAll(path, mode) | ||
} else { | ||
err = os.Chmod(path, mode) | ||
} | ||
} | ||
|
||
return err | ||
} | ||
|
||
func WriteFiles(ignitionConfig IgnitionConfig) error { | ||
var err error | ||
var targetFile *os.File | ||
|
||
for _, fileConfig := range ignitionConfig.Storage.Files { | ||
path := fileConfig.Path | ||
mode := DefaultFileMode | ||
compression := fileConfig.Contents.Compression | ||
source := fileConfig.Contents.Source | ||
var rawData, unescapedData string | ||
var decodedGzipData []byte | ||
fmt.Println(path) | ||
|
||
if fileConfig.Mode != 0 { | ||
mode = os.FileMode(fileConfig.Mode) | ||
} | ||
|
||
if compression == "gzip" { | ||
idx := strings.Index(source, ";base64,") | ||
rawData = source[idx+8:] | ||
|
||
gz, err := decodeBase64Data(rawData) | ||
decodedGzipData, err = decodeGzipData(string(gz)) | ||
targetFile, err = OpenFile(path, mode) | ||
if err != nil { | ||
return err | ||
} | ||
defer targetFile.Close() | ||
fmt.Fprintf(targetFile, "%s", string(decodedGzipData)) | ||
} else { | ||
idx := strings.Index(source, ",") | ||
rawData = source[idx+1:] | ||
|
||
targetFile, err = OpenFile(path, mode) | ||
if err != nil { | ||
return err | ||
} | ||
defer targetFile.Close() | ||
unescapedData, err = url.QueryUnescape(rawData) | ||
fmt.Fprintf(targetFile, "%s", unescapedData) | ||
} | ||
} | ||
|
||
return err | ||
} | ||
|
||
func WriteUnits(ignitionConfig IgnitionConfig) error { | ||
var err error | ||
var targetFile *os.File | ||
|
||
for _, unitConfig := range ignitionConfig.Systemd.Units { | ||
path := DefaultSystemdUnitPath + "/" + unitConfig.Name | ||
mode := DefaultSystemdUnitFileMode | ||
fmt.Println(path) | ||
|
||
unitEnabledString := "disable" | ||
if unitConfig.Enabled { | ||
unitEnabledString = "enable" | ||
} | ||
|
||
targetFile, err = OpenFile(path, mode) | ||
fmt.Fprintf(targetFile, "%s", unitConfig.Contents) | ||
defer targetFile.Close() | ||
check(err) | ||
|
||
cmd := exec.Command("systemctl", unitEnabledString, unitConfig.Name) | ||
err = cmd.Run() | ||
check(err) | ||
} | ||
|
||
return err | ||
} | ||
|
||
func decodeBase64Data(data string) ([]byte, error) { | ||
decodedData, err := base64.StdEncoding.DecodeString(data) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to decode base64: %q", err) | ||
} | ||
|
||
return decodedData, nil | ||
} | ||
|
||
func decodeGzipData(data string) ([]byte, error) { | ||
reader, err := gzip.NewReader(strings.NewReader(data)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer reader.Close() | ||
|
||
return io.ReadAll(reader) | ||
} | ||
|
||
func check(err error) { | ||
if err != nil { | ||
panic(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#!/usr/bin/env bash | ||
/usr/bin/butane --strict ../example_files/example.bu > ../example_files/example.ign | ||
rm -rf /tmp/example/ | ||
/usr/local/go/bin/go mod tidy && /usr/local/go/bin/go fmt *.go && /usr/local/go/bin/go build -o build/ | ||
./build/injection ../example_files/example.ign |