mirror of
https://github.com/hanzoai/deploy.git
synced 2026-10-07 08:44:50 +00:00
go.mod still declared `module github.com/hanzoai/deploy` after the repo was renamed. A Go module path is not cosmetic — it is the resolvable location. So `go get github.com/hanzoai/cd` could not work, and anything importing this module had to spell a name that no longer exists at that address. The build log of v3.6.0 is where it surfaced: the compiler was still emitting github.com/hanzoai/deploy/cmd/cd/commands. 3541 import paths across 690 .go, 19 .proto, 4 .yaml, 3 .sh, 2 .mod, Procfile and Makefile. Plus the 62 ghcr.io/hanzoai/deploy image references, moved to ghcr.io/hanzoai/cd to match hanzo.yml's build target — a distinct string from the module path, replaced separately so neither could clobber the other. go mod tidy clean, CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./... clean. Co-authored-by: Hanzo Dev <[email protected]>
284 lines
8.9 KiB
Go
284 lines
8.9 KiB
Go
package kube
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
corev1 "k8s.io/api/core/v1"
|
|
extv1beta1 "k8s.io/api/extensions/v1beta1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"sigs.k8s.io/yaml"
|
|
|
|
"github.com/hanzoai/cd/common"
|
|
)
|
|
|
|
const depWithoutSelector = `
|
|
apiVersion: extensions/v1beta1
|
|
kind: Deployment
|
|
metadata:
|
|
name: nginx-deployment
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: nginx
|
|
spec:
|
|
containers:
|
|
- image: nginx:1.7.9
|
|
name: nginx
|
|
ports:
|
|
- containerPort: 80
|
|
`
|
|
|
|
const depWithSelector = `
|
|
apiVersion: extensions/v1beta1
|
|
kind: Deployment
|
|
metadata:
|
|
name: nginx-deployment
|
|
spec:
|
|
selector:
|
|
matchLabels:
|
|
app: nginx
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: nginx
|
|
spec:
|
|
containers:
|
|
- image: nginx:1.7.9
|
|
name: nginx
|
|
ports:
|
|
- containerPort: 80
|
|
`
|
|
|
|
func TestSetLabels(t *testing.T) {
|
|
t.Parallel()
|
|
for _, yamlStr := range []string{depWithoutSelector, depWithSelector} {
|
|
var obj unstructured.Unstructured
|
|
err := yaml.Unmarshal([]byte(yamlStr), &obj)
|
|
require.NoError(t, err)
|
|
|
|
err = SetAppInstanceLabel(&obj, common.LabelKeyAppInstance, "my-app")
|
|
require.NoError(t, err)
|
|
|
|
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
|
|
require.NoError(t, err)
|
|
log.Println(string(manifestBytes))
|
|
|
|
var depV1Beta1 extv1beta1.Deployment
|
|
err = json.Unmarshal(manifestBytes, &depV1Beta1)
|
|
require.NoError(t, err)
|
|
|
|
// the following makes sure we are not falling into legacy code which injects labels
|
|
switch yamlStr {
|
|
case depWithoutSelector:
|
|
assert.Nil(t, depV1Beta1.Spec.Selector)
|
|
case depWithSelector:
|
|
assert.Len(t, depV1Beta1.Spec.Selector.MatchLabels, 1)
|
|
assert.Equal(t, "nginx", depV1Beta1.Spec.Selector.MatchLabels["app"])
|
|
}
|
|
assert.Len(t, depV1Beta1.Spec.Template.Labels, 1)
|
|
assert.Equal(t, "nginx", depV1Beta1.Spec.Template.Labels["app"])
|
|
}
|
|
}
|
|
|
|
func TestSetLegacyLabels(t *testing.T) {
|
|
t.Parallel()
|
|
for _, yamlStr := range []string{depWithoutSelector, depWithSelector} {
|
|
var obj unstructured.Unstructured
|
|
err := yaml.Unmarshal([]byte(yamlStr), &obj)
|
|
require.NoError(t, err)
|
|
|
|
err = SetAppInstanceLabel(&obj, common.LabelKeyLegacyApplicationName, "my-app")
|
|
require.NoError(t, err)
|
|
|
|
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
|
|
require.NoError(t, err)
|
|
log.Println(string(manifestBytes))
|
|
|
|
var depV1Beta1 extv1beta1.Deployment
|
|
err = json.Unmarshal(manifestBytes, &depV1Beta1)
|
|
require.NoError(t, err)
|
|
assert.Len(t, depV1Beta1.Spec.Selector.MatchLabels, 1)
|
|
assert.Equal(t, "nginx", depV1Beta1.Spec.Selector.MatchLabels["app"])
|
|
assert.Len(t, depV1Beta1.Spec.Template.Labels, 2)
|
|
assert.Equal(t, "nginx", depV1Beta1.Spec.Template.Labels["app"])
|
|
assert.Equal(t, "my-app", depV1Beta1.Spec.Template.Labels[common.LabelKeyLegacyApplicationName])
|
|
}
|
|
}
|
|
|
|
func TestSetLegacyJobLabel(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/job.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
err = SetAppInstanceLabel(&obj, common.LabelKeyLegacyApplicationName, "my-app")
|
|
require.NoError(t, err)
|
|
|
|
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
|
|
require.NoError(t, err)
|
|
log.Println(string(manifestBytes))
|
|
|
|
job := unstructured.Unstructured{}
|
|
err = json.Unmarshal(manifestBytes, &job)
|
|
require.NoError(t, err)
|
|
|
|
labels := job.GetLabels()
|
|
assert.Equal(t, "my-app", labels[common.LabelKeyLegacyApplicationName])
|
|
|
|
templateLabels, ok, err := unstructured.NestedMap(job.UnstructuredContent(), "spec", "template", "metadata", "labels")
|
|
assert.True(t, ok)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "my-app", templateLabels[common.LabelKeyLegacyApplicationName])
|
|
}
|
|
|
|
func TestSetSvcLabel(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
err = SetAppInstanceLabel(&obj, common.LabelKeyAppInstance, "my-app")
|
|
require.NoError(t, err)
|
|
|
|
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
|
|
require.NoError(t, err)
|
|
log.Println(string(manifestBytes))
|
|
|
|
var s corev1.Service
|
|
err = json.Unmarshal(manifestBytes, &s)
|
|
require.NoError(t, err)
|
|
|
|
log.Println(s.Name)
|
|
log.Println(s.ObjectMeta)
|
|
assert.Equal(t, "my-app", s.Labels[common.LabelKeyAppInstance])
|
|
}
|
|
|
|
func TestIsValidResourceName(t *testing.T) {
|
|
t.Parallel()
|
|
assert.True(t, IsValidResourceName("guestbook-ui"))
|
|
assert.True(t, IsValidResourceName("guestbook-ui1"))
|
|
assert.False(t, IsValidResourceName("Guestbook-ui"))
|
|
assert.False(t, IsValidResourceName("-guestbook-ui"))
|
|
}
|
|
|
|
func TestSetAppInstanceAnnotation(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
err = SetAppInstanceAnnotation(&obj, common.LabelKeyAppInstance, "my-app")
|
|
require.NoError(t, err)
|
|
|
|
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
|
|
require.NoError(t, err)
|
|
log.Println(string(manifestBytes))
|
|
|
|
var s corev1.Service
|
|
err = json.Unmarshal(manifestBytes, &s)
|
|
require.NoError(t, err)
|
|
|
|
log.Println(s.Name)
|
|
log.Println(s.ObjectMeta)
|
|
assert.Equal(t, "my-app", s.Annotations[common.LabelKeyAppInstance])
|
|
}
|
|
|
|
func TestSetAppInstanceAnnotationWithInvalidData(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/svc-with-invalid-data.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
err = SetAppInstanceAnnotation(&obj, common.LabelKeyAppInstance, "my-app")
|
|
assert.EqualError(t, err, "failed to get annotations from target object /v1, Kind=Service /my-service: .metadata.annotations accessor error: contains non-string value in the map under key \"invalid-annotation\": <nil> is of the type <nil>, expected string")
|
|
}
|
|
|
|
func TestGetAppInstanceAnnotation(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
err = SetAppInstanceAnnotation(&obj, common.LabelKeyAppInstance, "my-app")
|
|
require.NoError(t, err)
|
|
|
|
annotation, err := GetAppInstanceAnnotation(&obj, common.LabelKeyAppInstance)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "my-app", annotation)
|
|
}
|
|
|
|
func TestGetAppInstanceAnnotationWithInvalidData(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/svc-with-invalid-data.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
|
|
_, err = GetAppInstanceAnnotation(&obj, "valid-annotation")
|
|
assert.EqualError(t, err, "failed to get annotations from target object /v1, Kind=Service /my-service: .metadata.annotations accessor error: contains non-string value in the map under key \"invalid-annotation\": <nil> is of the type <nil>, expected string")
|
|
}
|
|
|
|
func TestGetAppInstanceLabel(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
err = SetAppInstanceLabel(&obj, common.LabelKeyAppInstance, "my-app")
|
|
require.NoError(t, err)
|
|
label, err := GetAppInstanceLabel(&obj, common.LabelKeyAppInstance)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "my-app", label)
|
|
}
|
|
|
|
func TestGetAppInstanceLabelWithInvalidData(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/svc-with-invalid-data.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
_, err = GetAppInstanceLabel(&obj, "valid-label")
|
|
assert.EqualError(t, err, "failed to get labels for /v1, Kind=Service /my-service: .metadata.labels accessor error: contains non-string value in the map under key \"invalid-label\": <nil> is of the type <nil>, expected string")
|
|
}
|
|
|
|
func TestRemoveLabel(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
obj.SetLabels(map[string]string{"test": "value"})
|
|
|
|
err = RemoveLabel(&obj, "test")
|
|
require.NoError(t, err)
|
|
|
|
assert.Nil(t, obj.GetLabels())
|
|
}
|
|
|
|
func TestRemoveLabelWithInvalidData(t *testing.T) {
|
|
t.Parallel()
|
|
yamlBytes, err := os.ReadFile("testdata/svc-with-invalid-data.yaml")
|
|
require.NoError(t, err)
|
|
var obj unstructured.Unstructured
|
|
err = yaml.Unmarshal(yamlBytes, &obj)
|
|
require.NoError(t, err)
|
|
|
|
err = RemoveLabel(&obj, "valid-label")
|
|
assert.EqualError(t, err, "failed to get labels for /v1, Kind=Service /my-service: .metadata.labels accessor error: contains non-string value in the map under key \"invalid-label\": <nil> is of the type <nil>, expected string")
|
|
}
|