Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docs): add nodeadm wasm targets to call from docs #2083

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci-auto.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
- run: cd nodeadm && make build
nodeadm-build-wasm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
- run: cd nodeadm && make wasm
nodeadm-check-generate:
runs-on: ubuntu-latest
steps:
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/deploy-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ jobs:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # 5.1.0
- run: |
pushd nodeadm && make wasm && popd
mkdir -p ./site/assets/wasm && cp ./nodeadm/_bin/nodeadm.wasm ./site/assets/wasm/
mkdir -p ./site/assets/javascripts && cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" ./site/assets/javascripts/
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
- run: pip install mkdocs mkdocs-material
- run: mkdocs gh-deploy --strict --no-history --force
# use the --dirty flag so that we dont purge our custom assets
- run: mkdocs gh-deploy --dirty --no-history --force
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
.DS_Store
site/
.git-commit
*.wasm
61 changes: 61 additions & 0 deletions doc/nodeadm/doc/playground.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Playground

This an interactive playground for `nodeadm`'s config parser packaged in the
browser via WebAssembly!

You can test out the validity of your EC2 Userdata and see any of the potential
errors that might happen at runtime.

<div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.36.5/ace.min.js" integrity="sha512-NIDAOLuPuewIzUrGoK5fXxowwGDm0DFJhI5TJPyTP6MeY2hUcCSKJr54fecQTEZ8kxxEO2NBrILQSUl4qZ37FA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="/amazon-eks-ami/assets/javascripts/wasm_exec.js"></script>
<body>
<div style="display: grid; margin: auto;">
<div id="editor" style="height:50vh"></div>
<textarea readonly style="height:15vh" id="response"></textarea>
</div>
</body>
<script>
const editor = ace.edit("editor", {
useWorker: false,
theme: "ace/theme/monokai",
mode: "ace/mode/yaml",
showPrintMargin: false,
});

// a global hook established ahead of time with the target WASM binary
function wasmLoadedHook() {
editor.session.on("change", function(_) {
document.getElementById("response").textContent = nodeadmCheck(editor.session.getValue())
});
editor.session.setValue(`
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="BOUNDARY"

--BOUNDARY
Content-Type: application/node.eks.aws

---
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
cluster:
name: my-cluster
apiServerEndpoint: https://example.com
certificateAuthority: Y2VydGlmaWNhdGVBdXRob3JpdHk=
cidr: 10.100.0.0/16
kubelet:
config:
shutdownGracePeriod: 30s
featureGates:
DisableKubeletCloudCredentialProviders: true

--BOUNDARY--`.trim());
}

const go = new Go();
WebAssembly.instantiateStreaming(fetch("/amazon-eks-ami/assets/wasm/nodeadm.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
</script>
</div>
1 change: 1 addition & 0 deletions mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ nav:
- 'Concepts': nodeadm/doc/api-concepts.md
- 'Reference': nodeadm/doc/api.md
- 'Examples': nodeadm/doc/examples.md
- 'Playground': nodeadm/doc/playground.md
theme:
name: material
palette:
Expand Down
6 changes: 5 additions & 1 deletion nodeadm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,13 @@ build: ## Build binary.
go build -o $(LOCALBIN)/nodeadm cmd/nodeadm/main.go

.PHONY: run
run: build ## Run binary
run: build ## Run binary.
go run cmd/nodeadm/main.go $(args)

.PHONY: wasm
wasm: ## Build WASM binary.
GOOS=js GOARCH=wasm go build -o $(LOCALBIN)/nodeadm.wasm cmd/nodeadm-wasm/main.go

##@ Build Dependencies

## Location to install dependencies to
Expand Down
58 changes: 58 additions & 0 deletions nodeadm/cmd/nodeadm-wasm/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//go:build wasm

package main

import (
"fmt"
"syscall/js"

"github.com/awslabs/amazon-eks-ami/nodeadm/internal/api"
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/configprovider"
)

type jsWrapperFunc = func(this js.Value, args []js.Value) any

func main() {
for jsFuncName, jsFunc := range map[string]jsWrapperFunc{
"nodeadmCheck": nodeadmCheckFunc,
} {
fmt.Printf("loading %q from Go WASM module\n", jsFuncName)
js.Global().Set(jsFuncName, js.FuncOf(func(this js.Value, args []js.Value) any {
defer func() {
// Since we cannot return errors in proper convention back to
// javascript through the WebAssembly Goroutine, we'll wrap the
// panic handler instead and print the information to keep the
// execution Go-like.
if r := recover(); r != nil {
errString := fmt.Sprintf("%s", r)
fmt.Printf("encountered error: %s\n", errString)
js.Global().Call("alert", errString)
}
}()
return jsFunc(this, args)
}))
}
// search for a hook in the global namesapace and invoke it. this helps
// prevent timing issues when attemping to call WASM functions when they are
// still being loaded.
if wasmLoadedHook := js.Global().Get("wasmLoadedHook"); wasmLoadedHook.Truthy() {
wasmLoadedHook.Invoke()
}
// block function completion to keep the Go routines loaded in memory
<-make(chan struct{})
}

var nodeadmCheckFunc = func(this js.Value, args []js.Value) any {
if len(args) != 1 {
panic("incorrect number of arguments.")
}
document := args[0].String()
nodeConfig, err := configprovider.ParseMaybeMultipart([]byte(document))
if err != nil {
return js.ValueOf(err.Error())
}
if err := api.ValidateNodeConfig(nodeConfig); err != nil {
return js.ValueOf(fmt.Errorf("validating NodeConfig: %w", err).Error())
}
return js.ValueOf("Looks Good! 👍")
}
2 changes: 1 addition & 1 deletion nodeadm/internal/configprovider/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ func (fcs *fileConfigProvider) Provide() (*internalapi.NodeConfig, error) {
if err != nil {
return nil, err
}
return parseMaybeMultipart(data)
return ParseMaybeMultipart(data)
}
6 changes: 3 additions & 3 deletions nodeadm/internal/configprovider/mime.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import (
apibridge "github.com/awslabs/amazon-eks-ami/nodeadm/internal/api/bridge"
)

func parseMaybeMultipart(data []byte) (*internalapi.NodeConfig, error) {
func ParseMaybeMultipart(data []byte) (*internalapi.NodeConfig, error) {
// if the MIME data fails to parse as a multipart document, then fall back
// to parsing the entire userdata as the node config.
if multipartReader, err := getMultipartReader(data); err == nil {
config, err := parseMultipart(multipartReader)
config, err := ParseMultipart(multipartReader)
if err != nil {
return nil, err
}
Expand All @@ -31,7 +31,7 @@ func parseMaybeMultipart(data []byte) (*internalapi.NodeConfig, error) {
}
}

func parseMultipart(userDataReader *multipart.Reader) (*internalapi.NodeConfig, error) {
func ParseMultipart(userDataReader *multipart.Reader) (*internalapi.NodeConfig, error) {
var nodeConfigs []*internalapi.NodeConfig
for {
part, err := userDataReader.NextPart()
Expand Down
2 changes: 1 addition & 1 deletion nodeadm/internal/configprovider/userdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,5 @@ func (p *userDataConfigProvider) Provide() (*internalapi.NodeConfig, error) {
if err != nil {
return nil, fmt.Errorf("failed to decompress user data: %v", err)
}
return parseMaybeMultipart(userData)
return ParseMaybeMultipart(userData)
}
Loading