diff --git a/cmd/minikube/cmd/config/addons_list_test.go b/cmd/minikube/cmd/config/addons_list_test.go index 52afb8e37f..fc4ca0f91a 100644 --- a/cmd/minikube/cmd/config/addons_list_test.go +++ b/cmd/minikube/cmd/config/addons_list_test.go @@ -66,7 +66,7 @@ func TestAddonsList(t *testing.T) { Ambassador *interface{} `json:"ambassador"` } - b := make([]byte, 544) + b := make([]byte, 557) r, w, err := os.Pipe() if err != nil { t.Fatalf("failed to create pipe: %v", err) diff --git a/deploy/addons/assets.go b/deploy/addons/assets.go index 8a30f5d9f3..84b6b644d5 100644 --- a/deploy/addons/assets.go +++ b/deploy/addons/assets.go @@ -143,4 +143,8 @@ var ( // AliyunMirror assets for aliyun_mirror.json //go:embed aliyun_mirror.json AliyunMirror embed.FS + + // InAccelAssets assets for inaccel addon + //go:embed inaccel/fpga-operator.yaml.tmpl + InAccelAssets embed.FS ) diff --git a/deploy/addons/inaccel/README.md b/deploy/addons/inaccel/README.md new file mode 100644 index 0000000000..a8e24b3f9e --- /dev/null +++ b/deploy/addons/inaccel/README.md @@ -0,0 +1,7 @@ +### Documentation + +For detailed usage instructions visit: [docs.inaccel.com](https://docs.inaccel.com) + +### Support + +For more product information contact: info@inaccel.com diff --git a/deploy/addons/inaccel/fpga-operator.yaml.tmpl b/deploy/addons/inaccel/fpga-operator.yaml.tmpl new file mode 100644 index 0000000000..a20bbc7747 --- /dev/null +++ b/deploy/addons/inaccel/fpga-operator.yaml.tmpl @@ -0,0 +1,56 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + addonmanager.kubernetes.io/mode: Reconcile + kubernetes.io/minikube-addons: inaccel + name: inaccel-addon + namespace: kube-system +data: + disable.sh: | + #!/bin/sh -e + exec >/proc/1/fd/1 + echo "Disabling InAccel FPGA Operator" + helm uninstall inaccel --namespace kube-system + echo "InAccel is disabled" + enable.sh: | + #!/bin/sh -e + exec >/proc/1/fd/1 + echo "Enabling InAccel FPGA Operator" + helm install inaccel fpga-operator --namespace kube-system --repo https://setup.inaccel.com/helm + echo "InAccel is enabled" +--- +apiVersion: v1 +kind: Pod +metadata: + labels: + addonmanager.kubernetes.io/mode: Reconcile + kubernetes.io/minikube-addons: inaccel + name: inaccel-addon + namespace: kube-system +spec: + containers: + - command: + - sleep + - infinity + image: {{ .CustomRegistries.Helm3 | default .ImageRepository | default .Registries.Helm3 }}{{ .Images.Helm3 }} + lifecycle: + postStart: + exec: + command: + - /inaccel/enable.sh + preStop: + exec: + command: + - /inaccel/disable.sh + name: helm3 + volumeMounts: + - mountPath: /inaccel + name: inaccel-addon + readOnly: true + volumes: + - configMap: + defaultMode: 0777 + name: inaccel-addon + name: inaccel-addon diff --git a/pkg/addons/config.go b/pkg/addons/config.go index f464df25a4..81db657897 100644 --- a/pkg/addons/config.go +++ b/pkg/addons/config.go @@ -197,4 +197,9 @@ var Addons = []*Addon{ set: SetBool, callbacks: []setFn{EnableOrDisableAddon}, }, + { + name: "inaccel", + set: SetBool, + callbacks: []setFn{EnableOrDisableAddon}, + }, } diff --git a/pkg/minikube/assets/addons.go b/pkg/minikube/assets/addons.go index 8fbeb0b662..dbd4239a39 100755 --- a/pkg/minikube/assets/addons.go +++ b/pkg/minikube/assets/addons.go @@ -688,6 +688,17 @@ var Addons = map[string]*Addon{ }, false, "portainer", "portainer.io", map[string]string{ "Portainer": "portainer/portainer-ce:latest@sha256:4f126c5114b63e9d1bceb4b368944d14323329a9a0d4e7bb7eb53c9b7435d498", }, nil), + "inaccel": NewAddon([]*BinAsset{ + MustBinAsset(addons.InAccelAssets, + "inaccel/fpga-operator.yaml.tmpl", + vmpath.GuestAddonsDir, + "fpga-operator.yaml", + "0640"), + }, false, "inaccel", "InAccel ", map[string]string{ + "Helm3": "alpine/helm:3.9.0@sha256:9f4bf4d24241f983910550b1fe8688571cd684046500abe58cef14308f9cb19e", + }, map[string]string{ + "Helm3": "docker.io", + }), } // parseMapString creates a map based on `str` which is encoded as =,=,... diff --git a/pkg/minikube/detect/detect.go b/pkg/minikube/detect/detect.go index c5910efc59..23ebc31613 100644 --- a/pkg/minikube/detect/detect.go +++ b/pkg/minikube/detect/detect.go @@ -17,6 +17,7 @@ limitations under the License. package detect import ( + "io" "net/http" "os" "os/exec" @@ -67,6 +68,27 @@ func IsOnGCE() bool { return resp.Header.Get("Metadata-Flavor") == "Google" } +// IsOnAmazonEC2 determines whether minikube is currently running on Amazon EC2 +// and, if yes, on which instance type. +func IsOnAmazonEC2() (bool, string) { + resp, err := http.Get("http://instance-data.ec2.internal/latest/meta-data/instance-type") + if err != nil { + return false, "" + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return true, "" + } + + instanceType, err := io.ReadAll(resp.Body) + if err != nil { + return true, "" + } + + return true, string(instanceType) +} + // IsCloudShell determines whether minikube is running inside CloudShell func IsCloudShell() bool { e := os.Getenv("CLOUD_SHELL") diff --git a/site/content/en/docs/contrib/tests.en.md b/site/content/en/docs/contrib/tests.en.md index cc1a736fa5..e763d4460c 100644 --- a/site/content/en/docs/contrib/tests.en.md +++ b/site/content/en/docs/contrib/tests.en.md @@ -42,6 +42,9 @@ tests the csi hostpath driver by creating a persistent volume, snapshotting it a #### validateGCPAuthAddon tests the GCP Auth addon with either phony or real credentials and makes sure the files are mounted into pods correctly +#### validateInAccelAddon +tests the InAccel addon by trying a vadd + ## TestCertOptions makes sure minikube certs respect the --apiserver-ips and --apiserver-names parameters diff --git a/test/integration/addons_test.go b/test/integration/addons_test.go index 7b85db6b33..b7d18b7f64 100644 --- a/test/integration/addons_test.go +++ b/test/integration/addons_test.go @@ -68,6 +68,8 @@ func TestAddons(t *testing.T) { args := append([]string{"start", "-p", profile, "--wait=true", "--memory=4000", "--alsologtostderr", "--addons=registry", "--addons=metrics-server", "--addons=volumesnapshots", "--addons=csi-hostpath-driver", "--addons=gcp-auth"}, StartArgs()...) if !NoneDriver() { // none driver does not support ingress args = append(args, "--addons=ingress", "--addons=ingress-dns") + } else if isOnAmazonEC2, instanceType := detect.IsOnAmazonEC2(); isOnAmazonEC2 && strings.HasPrefix(instanceType, "f1.") { + args = append(args, "--addons=inaccel") // inaccel supports only none driver } if !arm64Platform() { args = append(args, "--addons=helm-tiller") @@ -95,6 +97,7 @@ func TestAddons(t *testing.T) { {"HelmTiller", validateHelmTillerAddon}, {"Olm", validateOlmAddon}, {"CSI", validateCSIDriverAndSnapshots}, + {"InAccel", validateInAccelAddon}, } for _, tc := range tests { tc := tc @@ -708,3 +711,40 @@ func validateGCPAuthAddon(ctx context.Context, t *testing.T, profile string) { } } } + +// validateInAccelAddon tests the inaccel addon by trying a vadd +func validateInAccelAddon(ctx context.Context, t *testing.T, profile string) { + defer PostMortemLogs(t, profile) + + if !NoneDriver() { + t.Skipf("skipping: inaccel not supported") + } + + if isOnAmazonEC2, instanceType := detect.IsOnAmazonEC2(); !(isOnAmazonEC2 && strings.HasPrefix(instanceType, "f1.")) { + t.Skipf("skipping: not running on an Amazon EC2 f1 instance") + } + + // create sample pod + rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "create", "--filename", filepath.Join(*testdataDir, "inaccel.yaml"))) + if err != nil { + t.Fatalf("creating pod with %s failed: %v", rr.Command(), err) + } + + if _, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "wait", "--for", "condition=ready", "--timeout", "-1s", "pod/inaccel-vadd")); err != nil { + t.Fatalf("failed waiting for inaccel-vadd pod: %v", err) + } + + rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "logs", "--follow", "pod/inaccel-vadd")) + if err != nil { + t.Fatalf("%q failed: %v", rr.Command(), err) + } + if !strings.Contains(rr.Stdout.String(), "Test PASSED") { + t.Fatalf("expected inaccel-vadd logs to include: %q but got: %s", "Test PASSED", rr.Output()) + } + + // delete pod + rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "delete", "pod/inaccel-vadd")) + if err != nil { + t.Fatalf("deleting pod with %s failed: %v", rr.Command(), err) + } +} diff --git a/test/integration/testdata/inaccel.yaml b/test/integration/testdata/inaccel.yaml new file mode 100644 index 0000000000..b592e742e6 --- /dev/null +++ b/test/integration/testdata/inaccel.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Pod +metadata: + annotations: + inaccel/cli: | + bitstream install https://store.inaccel.com/artifactory/bitstreams/xilinx/aws-vu9p-f1/dynamic-shell/aws/vector/1/1addition + labels: + inaccel/fpga: enabled + name: inaccel-vadd +spec: + containers: + - image: inaccel/vadd + name: inaccel-vadd + resources: + limits: + xilinx/aws-vu9p-f1: 1 + nodeSelector: + xilinx/aws-vu9p-f1: dynamic-shell + restartPolicy: Never