Skip to content

Commit

Permalink
feat(docs): add nodeadm wasm targets to call from docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ndbaker1 committed Dec 10, 2024
1 parent da3591e commit d1367ca
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 17 deletions.
10 changes: 9 additions & 1 deletion .github/workflows/deploy-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ jobs:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # 5.1.0
- run: |
pushd nodeadm
GOOS=js GOARCH=wasm go build -o nodeadm.wasm cmd/nodeadm-wasm/main.go
popd
mkdir -p ./site/assets/wasm && cp ./nodeadm/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
56 changes: 56 additions & 0 deletions doc/nodeadm/doc/interactive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Playground

This an interactive playground for `nodeadm`'s config parser brought 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 go = new Go();
WebAssembly.instantiateStreaming(fetch("/amazon-eks-ami/assets/wasm/nodeadm.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
const editor = ace.edit("editor", {
useWorker: false
});
editor.setTheme("ace/theme/monokai");
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());
editor.session.setMode("ace/mode/yaml");
editor.setShowPrintMargin(false);
// editor is exposed via a global created by the monaco webcomponent
const validate = () => document.getElementById("response").textContent = nodeadmCheck(editor.session.getValue())
editor.session.on('change', function(_) { validate() });
validate()
</script>
</div>
1 change: 1 addition & 0 deletions mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ nav:
- 'API':
- 'Concepts': nodeadm/doc/api-concepts.md
- 'Reference': nodeadm/doc/api.md
- 'Interactive': nodeadm/doc/interactive.md
- 'Examples': nodeadm/doc/examples.md
theme:
name: material
Expand Down
52 changes: 52 additions & 0 deletions nodeadm/cmd/nodeadm-wasm/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//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)
}))
}
// 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! 👍")
}
20 changes: 9 additions & 11 deletions nodeadm/doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

#### ClusterDetails

ClusterDetails contains the coordinates of your EKS cluster.
These details can be found using the [DescribeCluster API](https://docs.aws.amazon.com/eks/latest/APIReference/API_DescribeCluster.html).
ClusterDetails contains the coordinates of your EKS cluster. These details can be found using the [DescribeCluster API](https://docs.aws.amazon.com/eks/latest/APIReference/API_DescribeCluster.html).

_Appears in:_
- [NodeConfigSpec](#nodeconfigspec)
Expand All @@ -20,7 +19,7 @@ _Appears in:_
| --- | --- |
| `name` _string_ | Name is the name of your EKS cluster |
| `apiServerEndpoint` _string_ | APIServerEndpoint is the URL of your EKS cluster's kube-apiserver. |
| `certificateAuthority` _integer array_ | CertificateAuthority is a base64-encoded string of your cluster's certificate authority chain. |
| `certificateAuthority` _[byte](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#byte-v1-meta) array_ | CertificateAuthority is a base64-encoded string of your cluster's certificate authority chain. |
| `cidr` _string_ | CIDR is your cluster's service CIDR block. This value is used to infer your cluster's DNS address. |
| `enableOutpost` _boolean_ | EnableOutpost determines how your node is configured when running on an AWS Outpost. |
| `id` _string_ | ID is an identifier for your cluster; this is only used when your node is running on an AWS Outpost. |
Expand All @@ -34,8 +33,8 @@ _Appears in:_

| Field | Description |
| --- | --- |
| `config` _string_ | Config is an inline [`containerd` configuration TOML](https://github.com/containerd/containerd/blob/main/docs/man/containerd-config.toml.5.md)<br />that will be merged with the defaults. |
| `baseRuntimeSpec` _object (keys:string, values:[RawExtension](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#rawextension-runtime-pkg))_ | BaseRuntimeSpec is the OCI runtime specification upon which all containers will be based.<br />The provided spec will be merged with the default spec; so that a partial spec may be provided.<br />For more information, see: https://github.com/opencontainers/runtime-spec |
| `config` _string_ | Config is an inline [`containerd` configuration TOML](https://github.com/containerd/containerd/blob/main/docs/man/containerd-config.toml.5.md) that will be merged with the defaults. |
| `baseRuntimeSpec` _object (keys:string, values:RawExtension)_ | BaseRuntimeSpec is the OCI runtime specification upon which all containers will be based. The provided spec will be merged with the default spec; so that a partial spec may be provided. For more information, see: https://github.com/opencontainers/runtime-spec |

#### Feature

Expand Down Expand Up @@ -69,13 +68,12 @@ _Appears in:_

| Field | Description |
| --- | --- |
| `config` _object (keys:string, values:[RawExtension](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#rawextension-runtime-pkg))_ | Config is a [`KubeletConfiguration`](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/)<br />that will be merged with the defaults. |
| `flags` _string array_ | Flags are [command-line `kubelet` arguments](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/).<br />that will be appended to the defaults. |
| `config` _object (keys:string, values:RawExtension)_ | Config is a [`KubeletConfiguration`](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/) that will be merged with the defaults. |
| `flags` _string array_ | Flags are [command-line `kubelet` arguments](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/). that will be appended to the defaults. |

#### LocalStorageOptions

LocalStorageOptions control how [EC2 instance stores](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html)
are used when available.
LocalStorageOptions control how [EC2 instance stores](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html) are used when available.

_Appears in:_
- [InstanceOptions](#instanceoptions)
Expand Down Expand Up @@ -104,8 +102,8 @@ NodeConfig is the primary configuration object for `nodeadm`.
| --- | --- |
| `apiVersion` _string_ | `node.eks.aws/v1alpha1`
| `kind` _string_ | `NodeConfig`
| `kind` _string_ | Kind is a string value representing the REST resource this object represents.<br />Servers may infer this from the endpoint the client submits requests to.<br />Cannot be updated.<br />In CamelCase.<br />More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds |
| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.<br />Servers should convert recognized schemas to the latest internal value, and<br />may reject unrecognized values.<br />More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources |
| `kind` _string_ | Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds |
| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources |
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. |
| `spec` _[NodeConfigSpec](#nodeconfigspec)_ | |

Expand Down
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)
}

0 comments on commit d1367ca

Please sign in to comment.