refactor(yaml): moved AppVersion into metadata

This commit is contained in:
Patrick Sy 2025-10-07 16:01:38 +02:00
parent cc8b9e791b
commit 06f921963a
8 changed files with 57 additions and 64 deletions

View file

@ -137,11 +137,11 @@ func createTestManagerConfig(t *testing.T) *config.EdgeConnectConfig {
return &config.EdgeConnectConfig{ return &config.EdgeConnectConfig{
Kind: "edgeconnect-deployment", Kind: "edgeconnect-deployment",
Metadata: config.Metadata{ Metadata: config.Metadata{
Name: "test-app", Name: "test-app",
AppVersion: "1.0.0",
}, },
Spec: config.Spec{ Spec: config.Spec{
K8sApp: &config.K8sApp{ K8sApp: &config.K8sApp{
AppVersion: "1.0.0",
ManifestFile: manifestFile, ManifestFile: manifestFile,
}, },
InfraTemplate: []config.InfraTemplate{ InfraTemplate: []config.InfraTemplate{

View file

@ -134,7 +134,7 @@ func (p *EdgeConnectPlanner) planAppAction(ctx context.Context, config *config.E
// Build desired app state // Build desired app state
desired := &AppState{ desired := &AppState{
Name: config.Metadata.Name, Name: config.Metadata.Name,
Version: config.Spec.GetAppVersion(), Version: config.Metadata.AppVersion,
Organization: config.Spec.InfraTemplate[0].Organization, // Use first infra template for org Organization: config.Spec.InfraTemplate[0].Organization, // Use first infra template for org
Region: config.Spec.InfraTemplate[0].Region, // Use first infra template for region Region: config.Spec.InfraTemplate[0].Region, // Use first infra template for region
Exists: false, // Will be set based on current state Exists: false, // Will be set based on current state
@ -204,6 +204,7 @@ func (p *EdgeConnectPlanner) planAppAction(ctx context.Context, config *config.E
action.Type = ActionUpdate action.Type = ActionUpdate
action.Changes = changes action.Changes = changes
action.Reason = "Application configuration has changed" action.Reason = "Application configuration has changed"
fmt.Printf("Changes: %v\n", changes)
if manifestChanged { if manifestChanged {
warnings = append(warnings, "Manifest file has changed - instances may need to be recreated") warnings = append(warnings, "Manifest file has changed - instances may need to be recreated")
@ -219,11 +220,11 @@ func (p *EdgeConnectPlanner) planInstanceActions(ctx context.Context, config *co
var warnings []string var warnings []string
for _, infra := range config.Spec.InfraTemplate { for _, infra := range config.Spec.InfraTemplate {
instanceName := getInstanceName(config.Metadata.Name, config.Spec.GetAppVersion()) instanceName := getInstanceName(config.Metadata.Name, config.Metadata.AppVersion)
desired := &InstanceState{ desired := &InstanceState{
Name: instanceName, Name: instanceName,
AppVersion: config.Spec.GetAppVersion(), AppVersion: config.Metadata.AppVersion,
Organization: infra.Organization, Organization: infra.Organization,
Region: infra.Region, Region: infra.Region,
CloudletOrg: infra.CloudletOrg, CloudletOrg: infra.CloudletOrg,

View file

@ -112,11 +112,11 @@ func createTestConfig(t *testing.T) *config.EdgeConnectConfig {
return &config.EdgeConnectConfig{ return &config.EdgeConnectConfig{
Kind: "edgeconnect-deployment", Kind: "edgeconnect-deployment",
Metadata: config.Metadata{ Metadata: config.Metadata{
Name: "test-app", Name: "test-app",
AppVersion: "1.0.0",
}, },
Spec: config.Spec{ Spec: config.Spec{
K8sApp: &config.K8sApp{ K8sApp: &config.K8sApp{
AppVersion: "1.0.0",
ManifestFile: manifestFile, ManifestFile: manifestFile,
}, },
InfraTemplate: []config.InfraTemplate{ InfraTemplate: []config.InfraTemplate{

View file

@ -440,7 +440,7 @@ func (r *RecreateStrategy) createInstance(ctx context.Context, action InstanceAc
AppKey: edgeconnect.AppKey{ AppKey: edgeconnect.AppKey{
Organization: action.Target.Organization, Organization: action.Target.Organization,
Name: config.Metadata.Name, Name: config.Metadata.Name,
Version: config.Spec.GetAppVersion(), Version: config.Metadata.AppVersion,
}, },
Flavor: edgeconnect.Flavor{ Flavor: edgeconnect.Flavor{
Name: action.Target.FlavorName, Name: action.Target.FlavorName,

View file

@ -28,7 +28,7 @@ func TestParseExampleConfig(t *testing.T) {
// Check k8s app configuration // Check k8s app configuration
require.NotNil(t, config.Spec.K8sApp) require.NotNil(t, config.Spec.K8sApp)
assert.Equal(t, "1.0.0", config.Spec.K8sApp.AppVersion) assert.Equal(t, "1.0.0", config.Metadata.AppVersion)
// Note: ManifestFile path should be resolved to absolute path // Note: ManifestFile path should be resolved to absolute path
assert.Contains(t, config.Spec.K8sApp.ManifestFile, "k8s-deployment.yaml") assert.Contains(t, config.Spec.K8sApp.ManifestFile, "k8s-deployment.yaml")
@ -59,7 +59,6 @@ func TestParseExampleConfig(t *testing.T) {
// Test utility methods // Test utility methods
assert.Equal(t, "edge-app-demo", config.Metadata.Name) assert.Equal(t, "edge-app-demo", config.Metadata.Name)
assert.Equal(t, "1.0.0", config.Spec.GetAppVersion())
assert.Contains(t, config.Spec.GetManifestFile(), "k8s-deployment.yaml") assert.Contains(t, config.Spec.GetManifestFile(), "k8s-deployment.yaml")
assert.True(t, config.Spec.IsK8sApp()) assert.True(t, config.Spec.IsK8sApp())
assert.False(t, config.Spec.IsDockerApp()) assert.False(t, config.Spec.IsDockerApp())
@ -73,10 +72,10 @@ func TestValidateExampleStructure(t *testing.T) {
Kind: "edgeconnect-deployment", Kind: "edgeconnect-deployment",
Metadata: Metadata{ Metadata: Metadata{
Name: "edge-app-demo", Name: "edge-app-demo",
AppVersion: "1.0.0",
}, },
Spec: Spec{ Spec: Spec{
DockerApp: &DockerApp{ // Use DockerApp to avoid manifest file validation DockerApp: &DockerApp{ // Use DockerApp to avoid manifest file validation
AppVersion: "1.0.0",
Image: "nginx:latest", Image: "nginx:latest",
}, },
InfraTemplate: []InfraTemplate{ InfraTemplate: []InfraTemplate{

View file

@ -32,9 +32,9 @@ func TestConfigParser_ParseBytes(t *testing.T) {
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
k8sApp: k8sApp:
appVersion: "1.0.0"
manifestFile: "./test-manifest.yaml" manifestFile: "./test-manifest.yaml"
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"
@ -52,9 +52,9 @@ spec:
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
dockerApp: dockerApp:
appVersion: "1.0.0"
image: "nginx:latest" image: "nginx:latest"
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"
@ -70,9 +70,9 @@ spec:
yaml: ` yaml: `
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
k8sApp: k8sApp:
appVersion: "1.0.0"
manifestFile: "./test-manifest.yaml" manifestFile: "./test-manifest.yaml"
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"
@ -90,9 +90,9 @@ spec:
kind: invalid-kind kind: invalid-kind
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
dockerApp: dockerApp:
appVersion: "1.0.0"
image: "nginx:latest" image: "nginx:latest"
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"
@ -110,6 +110,7 @@ spec:
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"
@ -127,13 +128,12 @@ spec:
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
k8sApp: k8sApp:
appVersion: "1.0.0"
manifestFile: "./test-manifest.yaml" manifestFile: "./test-manifest.yaml"
dockerApp: dockerApp:
appName: "test-app" appName: "test-app"
appVersion: "1.0.0"
image: "nginx:latest" image: "nginx:latest"
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"
@ -151,9 +151,9 @@ spec:
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
dockerApp: dockerApp:
appVersion: "1.0.0"
image: "nginx:latest" image: "nginx:latest"
infraTemplate: [] infraTemplate: []
`, `,
@ -166,9 +166,9 @@ spec:
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
dockerApp: dockerApp:
appVersion: "1.0.0"
image: "nginx:latest" image: "nginx:latest"
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"
@ -222,9 +222,9 @@ func TestConfigParser_ParseFile(t *testing.T) {
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
dockerApp: dockerApp:
appVersion: "1.0.0"
image: "nginx:latest" image: "nginx:latest"
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"
@ -284,9 +284,9 @@ func TestConfigParser_RelativePathResolution(t *testing.T) {
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
k8sApp: k8sApp:
appVersion: "1.0.0"
manifestFile: "./manifest.yaml" manifestFile: "./manifest.yaml"
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"
@ -322,10 +322,10 @@ func TestEdgeConnectConfig_Validate(t *testing.T) {
Kind: "edgeconnect-deployment", Kind: "edgeconnect-deployment",
Metadata: Metadata{ Metadata: Metadata{
Name: "test-app", Name: "test-app",
AppVersion: "1.0.0",
}, },
Spec: Spec{ Spec: Spec{
DockerApp: &DockerApp{ DockerApp: &DockerApp{
AppVersion: "1.0.0",
Image: "nginx:latest", Image: "nginx:latest",
}, },
InfraTemplate: []InfraTemplate{ InfraTemplate: []InfraTemplate{
@ -385,24 +385,42 @@ func TestMetadata_Validate(t *testing.T) {
}{ }{
{ {
name: "valid metadata", name: "valid metadata",
metadata: Metadata{Name: "test-app"}, metadata: Metadata{Name: "test-app", AppVersion: "1.0.0"},
wantErr: false, wantErr: false,
}, },
{ {
name: "empty name", name: "empty name",
metadata: Metadata{Name: ""}, metadata: Metadata{Name: "", AppVersion: "1.0.0"},
wantErr: true, wantErr: true,
errMsg: "metadata.name is required", errMsg: "metadata.name is required",
}, },
{ {
name: "name with leading whitespace", name: "name with leading whitespace",
metadata: Metadata{Name: " test-app"}, metadata: Metadata{Name: " test-app", AppVersion: "1.0.0"},
wantErr: true, wantErr: true,
errMsg: "cannot have leading/trailing whitespace", errMsg: "cannot have leading/trailing whitespace",
}, },
{ {
name: "name with trailing whitespace", name: "name with trailing whitespace",
metadata: Metadata{Name: "test-app "}, metadata: Metadata{Name: "test-app ", AppVersion: "1.0.0"},
wantErr: true,
errMsg: "cannot have leading/trailing whitespace",
},
{
name: "empty app version",
metadata: Metadata{Name: "test-app", AppVersion: ""},
wantErr: true,
errMsg: "metadata.appVersion is required",
},
{
name: "app version with leading whitespace",
metadata: Metadata{Name: "test-app", AppVersion: " 1.0.0"},
wantErr: true,
errMsg: "cannot have leading/trailing whitespace",
},
{
name: "app version with trailing whitespace",
metadata: Metadata{Name: "test-app", AppVersion: "1.0.0 "},
wantErr: true, wantErr: true,
errMsg: "cannot have leading/trailing whitespace", errMsg: "cannot have leading/trailing whitespace",
}, },
@ -526,24 +544,20 @@ func TestOutboundConnection_Validate(t *testing.T) {
func TestSpec_GetMethods(t *testing.T) { func TestSpec_GetMethods(t *testing.T) {
k8sSpec := &Spec{ k8sSpec := &Spec{
K8sApp: &K8sApp{ K8sApp: &K8sApp{
AppVersion: "1.0.0",
ManifestFile: "k8s.yaml", ManifestFile: "k8s.yaml",
}, },
} }
dockerSpec := &Spec{ dockerSpec := &Spec{
DockerApp: &DockerApp{ DockerApp: &DockerApp{
AppVersion: "2.0.0",
ManifestFile: "docker.yaml", ManifestFile: "docker.yaml",
}, },
} }
assert.Equal(t, "1.0.0", k8sSpec.GetAppVersion())
assert.Equal(t, "k8s.yaml", k8sSpec.GetManifestFile()) assert.Equal(t, "k8s.yaml", k8sSpec.GetManifestFile())
assert.True(t, k8sSpec.IsK8sApp()) assert.True(t, k8sSpec.IsK8sApp())
assert.False(t, k8sSpec.IsDockerApp()) assert.False(t, k8sSpec.IsDockerApp())
assert.Equal(t, "2.0.0", dockerSpec.GetAppVersion())
assert.Equal(t, "docker.yaml", dockerSpec.GetManifestFile()) assert.Equal(t, "docker.yaml", dockerSpec.GetManifestFile())
assert.False(t, dockerSpec.IsK8sApp()) assert.False(t, dockerSpec.IsK8sApp())
assert.True(t, dockerSpec.IsDockerApp()) assert.True(t, dockerSpec.IsDockerApp())
@ -564,9 +578,9 @@ func TestReadManifestFile(t *testing.T) {
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "test-app" name: "test-app"
appVersion: "1.0.0"
spec: spec:
k8sApp: k8sApp:
appVersion: "1.0.0"
manifestFile: "./manifest.yaml" manifestFile: "./manifest.yaml"
infraTemplate: infraTemplate:
- organization: "testorg" - organization: "testorg"

View file

@ -18,7 +18,8 @@ type EdgeConnectConfig struct {
// Metadata contains configuration metadata // Metadata contains configuration metadata
type Metadata struct { type Metadata struct {
Name string `yaml:"name"` Name string `yaml:"name"`
AppVersion string `yaml:"appVersion"`
} }
// Spec defines the application and infrastructure specification // Spec defines the application and infrastructure specification
@ -32,13 +33,11 @@ type Spec struct {
// K8sApp defines Kubernetes application configuration // K8sApp defines Kubernetes application configuration
type K8sApp struct { type K8sApp struct {
AppVersion string `yaml:"appVersion"`
ManifestFile string `yaml:"manifestFile"` ManifestFile string `yaml:"manifestFile"`
} }
// DockerApp defines Docker application configuration // DockerApp defines Docker application configuration
type DockerApp struct { type DockerApp struct {
AppVersion string `yaml:"appVersion"`
ManifestFile string `yaml:"manifestFile"` ManifestFile string `yaml:"manifestFile"`
Image string `yaml:"image"` Image string `yaml:"image"`
} }
@ -113,6 +112,15 @@ func (m *Metadata) Validate() error {
return fmt.Errorf("metadata.name cannot have leading/trailing whitespace") return fmt.Errorf("metadata.name cannot have leading/trailing whitespace")
} }
if m.AppVersion == "" {
return fmt.Errorf("metadata.appVersion is required")
}
// Validate version format
if strings.TrimSpace(m.AppVersion) != m.AppVersion {
return fmt.Errorf("metadata.appVersion cannot have leading/trailing whitespace")
}
return nil return nil
} }
@ -171,10 +179,6 @@ func (s *Spec) Validate() error {
// Validate validates k8s app configuration // Validate validates k8s app configuration
func (k *K8sApp) Validate() error { func (k *K8sApp) Validate() error {
if k.AppVersion == "" {
return fmt.Errorf("appVersion is required")
}
if k.ManifestFile == "" { if k.ManifestFile == "" {
return fmt.Errorf("manifestFile is required") return fmt.Errorf("manifestFile is required")
} }
@ -184,29 +188,15 @@ func (k *K8sApp) Validate() error {
return fmt.Errorf("manifestFile does not exist: %s", k.ManifestFile) return fmt.Errorf("manifestFile does not exist: %s", k.ManifestFile)
} }
// Validate version format
if strings.TrimSpace(k.AppVersion) != k.AppVersion {
return fmt.Errorf("appVersion cannot have leading/trailing whitespace")
}
return nil return nil
} }
// Validate validates docker app configuration // Validate validates docker app configuration
func (d *DockerApp) Validate() error { func (d *DockerApp) Validate() error {
if d.AppVersion == "" {
return fmt.Errorf("appVersion is required")
}
if d.Image == "" { if d.Image == "" {
return fmt.Errorf("image is required") return fmt.Errorf("image is required")
} }
// Validate version format
if strings.TrimSpace(d.AppVersion) != d.AppVersion {
return fmt.Errorf("appVersion cannot have leading/trailing whitespace")
}
// Check if manifest file exists if specified // Check if manifest file exists if specified
if d.ManifestFile != "" { if d.ManifestFile != "" {
if _, err := os.Stat(d.ManifestFile); os.IsNotExist(err) { if _, err := os.Stat(d.ManifestFile); os.IsNotExist(err) {
@ -326,17 +316,6 @@ func (d *DockerApp) GetManifestPath(configDir string) string {
return filepath.Join(configDir, d.ManifestFile) return filepath.Join(configDir, d.ManifestFile)
} }
// GetAppVersion returns the application version from the active app type
func (s *Spec) GetAppVersion() string {
if s.K8sApp != nil {
return s.K8sApp.AppVersion
}
if s.DockerApp != nil {
return s.DockerApp.AppVersion
}
return ""
}
// GetManifestFile returns the manifest file path from the active app type // GetManifestFile returns the manifest file path from the active app type
func (s *Spec) GetManifestFile() string { func (s *Spec) GetManifestFile() string {
if s.K8sApp != nil { if s.K8sApp != nil {

View file

@ -3,13 +3,13 @@
kind: edgeconnect-deployment kind: edgeconnect-deployment
metadata: metadata:
name: "edge-app-demo" # name could be used for appName name: "edge-app-demo" # name could be used for appName
appVersion: "1.0.0"
spec: spec:
# dockerApp: # Docker is OBSOLETE # dockerApp: # Docker is OBSOLETE
# appVersion: "1.0.0" # appVersion: "1.0.0"
# manifestFile: "./docker-compose.yaml" # manifestFile: "./docker-compose.yaml"
# image: "https://registry-1.docker.io/library/nginx:latest" # image: "https://registry-1.docker.io/library/nginx:latest"
k8sApp: k8sApp:
appVersion: "1.0.0"
manifestFile: "./k8s-deployment.yaml" manifestFile: "./k8s-deployment.yaml"
infraTemplate: infraTemplate:
- organization: "edp2" - organization: "edp2"