Skip to content

Commit ea924ac

Browse files
authored
Merge pull request #278 from calebschoepp/spintainer
First take at getting spintainer working
2 parents 32daa7c + fe862a9 commit ea924ac

17 files changed

+310
-51
lines changed

api/v1alpha1/spinappexecutor_types.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,15 @@ type SpinAppExecutorSpec struct {
3636

3737
type ExecutorDeploymentConfig struct {
3838
// RuntimeClassName is the runtime class name that should be used by pods created
39-
// as part of a deployment.
40-
RuntimeClassName string `json:"runtimeClassName"`
39+
// as part of a deployment. This should only be defined when SpintainerImage is not defined.
40+
RuntimeClassName *string `json:"runtimeClassName,omitempty"`
41+
42+
// SpinImage points to an image that will run Spin in a container to execute
43+
// your SpinApp. This is an alternative to using the shim to execute your
44+
// SpinApp. This should only be defined when RuntimeClassName is not
45+
// defined. When specified, application images must be available without
46+
// authentication.
47+
SpinImage *string `json:"spinImage,omitempty"`
4148

4249
// CACertSecret specifies the name of the secret containing the CA
4350
// certificates to be mounted to the deployment.

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/core.spinoperator.dev_spinappexecutors.yaml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,16 @@ spec:
8484
runtimeClassName:
8585
description: |-
8686
RuntimeClassName is the runtime class name that should be used by pods created
87-
as part of a deployment.
87+
as part of a deployment. This should only be defined when SpintainerImage is not defined.
88+
type: string
89+
spinImage:
90+
description: |-
91+
SpinImage points to an image that will run Spin in a container to execute
92+
your SpinApp. This is an alternative to using the shim to execute your
93+
SpinApp. This should only be defined when RuntimeClassName is not
94+
defined. When specified, application images must be available without
95+
authentication.
8896
type: string
89-
required:
90-
- runtimeClassName
9197
type: object
9298
required:
9399
- createDeployment
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: core.spinoperator.dev/v1alpha1
2+
kind: SpinAppExecutor
3+
metadata:
4+
name: spintainer
5+
spec:
6+
createDeployment: true
7+
deploymentConfig:
8+
installDefaultCACerts: true
9+
spinImage: ghcr.io/fermyon/spin:v2.7.0

config/samples/spintainer.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: core.spinoperator.dev/v1alpha1
2+
kind: SpinApp
3+
metadata:
4+
name: spintainer-spinapp
5+
spec:
6+
image: "ghcr.io/spinkube/spin-operator/hello-world:20240708-130250-gfefd2b1"
7+
replicas: 1
8+
executor: spintainer

e2e/crd_installed_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func TestCRDInstalled(t *testing.T) {
1414
Assess("spinapp crd installed", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
1515
client := cfg.Client()
1616
if err := apiextensionsV1.AddToScheme(client.Resources().GetScheme()); err != nil {
17-
t.Fatalf("failed to register the v1 API extension types with Kuberenets scheme: %s", err)
17+
t.Fatalf("failed to register the v1 API extension types with Kubernetes scheme: %s", err)
1818
}
1919
name := "spinapps.core.spinoperator.dev"
2020
var crd apiextensionsV1.CustomResourceDefinition
@@ -31,7 +31,7 @@ func TestCRDInstalled(t *testing.T) {
3131
Assess("spinappexecutor crd installed", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
3232
client := cfg.Client()
3333
if err := apiextensionsV1.AddToScheme(client.Resources().GetScheme()); err != nil {
34-
t.Fatalf("failed to register the v1 API extension types with Kuberenets scheme: %s", err)
34+
t.Fatalf("failed to register the v1 API extension types with Kubernetes scheme: %s", err)
3535
}
3636

3737
name := "spinappexecutors.core.spinoperator.dev"

e2e/default_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func TestDefaultSetup(t *testing.T) {
3030
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
3131
client = cfg.Client()
3232

33-
testSpinApp := newSpinAppCR(testSpinAppName, helloWorldImage)
33+
testSpinApp := newSpinAppCR(testSpinAppName, helloWorldImage, "containerd-shim-spin")
3434
if err := client.Resources().Create(ctx, testSpinApp); err != nil {
3535
t.Fatalf("Failed to create spinapp: %s", err)
3636
}
@@ -69,7 +69,7 @@ func TestDefaultSetup(t *testing.T) {
6969
testEnv.Test(t, defaultTest)
7070
}
7171

72-
func newSpinAppCR(name, image string) *spinapps_v1alpha1.SpinApp {
72+
func newSpinAppCR(name, image, executor string) *spinapps_v1alpha1.SpinApp {
7373
return &spinapps_v1alpha1.SpinApp{
7474
ObjectMeta: metav1.ObjectMeta{
7575
Name: name,
@@ -78,7 +78,7 @@ func newSpinAppCR(name, image string) *spinapps_v1alpha1.SpinApp {
7878
Spec: spinapps_v1alpha1.SpinAppSpec{
7979
Replicas: 1,
8080
Image: image,
81-
Executor: "containerd-shim-spin",
81+
Executor: executor,
8282
},
8383
}
8484
}

e2e/main_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func newContainerdShimExecutor(namespace string) *spinapps_v1alpha1.SpinAppExecu
144144
Spec: spinapps_v1alpha1.SpinAppExecutorSpec{
145145
CreateDeployment: true,
146146
DeploymentConfig: &spinapps_v1alpha1.ExecutorDeploymentConfig{
147-
RuntimeClassName: runtimeClassName,
147+
RuntimeClassName: &runtimeClassName,
148148
InstallDefaultCACerts: true,
149149
CACertSecret: testCACertSecret,
150150
},

e2e/spintainer_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"testing"
6+
"time"
7+
8+
v1 "k8s.io/api/core/v1"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"sigs.k8s.io/e2e-framework/klient"
11+
"sigs.k8s.io/e2e-framework/klient/k8s"
12+
"sigs.k8s.io/e2e-framework/klient/wait"
13+
"sigs.k8s.io/e2e-framework/klient/wait/conditions"
14+
"sigs.k8s.io/e2e-framework/pkg/envconf"
15+
"sigs.k8s.io/e2e-framework/pkg/features"
16+
17+
spinapps_v1alpha1 "github.com/spinkube/spin-operator/api/v1alpha1"
18+
"github.com/spinkube/spin-operator/internal/generics"
19+
)
20+
21+
// TestSpintainer is a test that checks that the minimal setup works
22+
// with the spintainer executor
23+
func TestSpintainer(t *testing.T) {
24+
var client klient.Client
25+
26+
helloWorldImage := "ghcr.io/spinkube/spin-operator/hello-world:20240708-130250-gfefd2b1"
27+
testSpinAppName := "test-spintainer-app"
28+
29+
defaultTest := features.New("default and most minimal setup").
30+
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
31+
32+
client = cfg.Client()
33+
34+
if err := spinapps_v1alpha1.AddToScheme(client.Resources(testNamespace).GetScheme()); err != nil {
35+
t.Fatalf("failed to register the spinapps_v1alpha1 types with Kubernetes scheme: %s", err)
36+
}
37+
38+
return ctx
39+
}).
40+
Assess("spin app custom resource is created", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
41+
testSpinApp := newSpinAppCR(testSpinAppName, helloWorldImage, "spintainer")
42+
43+
if err := client.Resources().Create(ctx, newSpintainerExecutor(testNamespace)); err != nil {
44+
t.Fatalf("Failed to create spinappexecutor: %s", err)
45+
}
46+
47+
if err := client.Resources().Create(ctx, testSpinApp); err != nil {
48+
t.Fatalf("Failed to create spinapp: %s", err)
49+
}
50+
// wait for spinapp to be created
51+
if err := wait.For(
52+
conditions.New(client.Resources()).ResourceMatch(testSpinApp, func(object k8s.Object) bool {
53+
return true
54+
}),
55+
wait.WithTimeout(3*time.Minute),
56+
wait.WithInterval(30*time.Second),
57+
); err != nil {
58+
t.Fatal(err)
59+
}
60+
61+
return ctx
62+
}).
63+
Assess("spin app deployment and service are available", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
64+
// wait for deployment to be ready
65+
if err := wait.For(
66+
conditions.New(client.Resources()).DeploymentAvailable(testSpinAppName, testNamespace),
67+
wait.WithTimeout(3*time.Minute),
68+
wait.WithInterval(30*time.Second),
69+
); err != nil {
70+
t.Fatal(err)
71+
}
72+
73+
svc := &v1.ServiceList{
74+
Items: []v1.Service{
75+
{ObjectMeta: metav1.ObjectMeta{Name: testSpinAppName, Namespace: testNamespace}},
76+
},
77+
}
78+
79+
if err := wait.For(
80+
conditions.New(client.Resources()).ResourcesFound(svc),
81+
wait.WithTimeout(3*time.Minute),
82+
wait.WithInterval(30*time.Second),
83+
); err != nil {
84+
t.Fatal(err)
85+
}
86+
return ctx
87+
}).
88+
Feature()
89+
testEnv.Test(t, defaultTest)
90+
}
91+
92+
func newSpintainerExecutor(namespace string) *spinapps_v1alpha1.SpinAppExecutor {
93+
var testSpinAppExecutor = &spinapps_v1alpha1.SpinAppExecutor{
94+
ObjectMeta: metav1.ObjectMeta{
95+
Name: "spintainer",
96+
Namespace: namespace,
97+
},
98+
Spec: spinapps_v1alpha1.SpinAppExecutorSpec{
99+
CreateDeployment: true,
100+
DeploymentConfig: &spinapps_v1alpha1.ExecutorDeploymentConfig{
101+
SpinImage: generics.Ptr("ghcr.io/fermyon/spin:v2.7.0"),
102+
},
103+
},
104+
}
105+
106+
return testSpinAppExecutor
107+
}

internal/controller/deployment.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func constructRuntimeConfigSecretMount(_ctx context.Context, secretName string)
2020
VolumeSource: corev1.VolumeSource{
2121
Secret: &corev1.SecretVolumeSource{
2222
SecretName: secretName,
23-
Optional: ptr(true),
23+
Optional: generics.Ptr(true),
2424
Items: []corev1.KeyToPath{
2525
{
2626
Key: "runtime-config.toml",
@@ -46,7 +46,7 @@ func constructCASecretMount(_ context.Context, caSecretName string) (corev1.Volu
4646
VolumeSource: corev1.VolumeSource{
4747
Secret: &corev1.SecretVolumeSource{
4848
SecretName: caSecretName,
49-
Optional: ptr(true),
49+
Optional: generics.Ptr(true),
5050
Items: []corev1.KeyToPath{{
5151
Key: "ca-certificates.crt",
5252
Path: "ca-certificates.crt",

0 commit comments

Comments
 (0)