Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

Commit

Permalink
add merge workflow between load raw api model and validation (#1270)
Browse files Browse the repository at this point in the history
* import github.com/imdario/mergo

* add merge into loadcontainerservice workflow

* put back the testImport versions, glide.yaml and glide.lock are not sync right now
  • Loading branch information
rjtsdl authored and jackfrancis committed Aug 18, 2017
1 parent 292153f commit 13b0143
Show file tree
Hide file tree
Showing 30 changed files with 1,488 additions and 17 deletions.
4 changes: 2 additions & 2 deletions cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (dc *deployCmd) validate(cmd *cobra.Command, args []string) {
},
}
// skip validating the model fields for now
dc.containerService, dc.apiVersion, err = apiloader.LoadContainerServiceFromFile(dc.apimodelPath, false)
dc.containerService, dc.apiVersion, err = apiloader.LoadContainerServiceFromFile(dc.apimodelPath, false, nil)
if err != nil {
log.Fatalf("error parsing the api model: %s", err.Error())
}
Expand Down Expand Up @@ -235,7 +235,7 @@ func revalidateApimodel(apiloader *api.Apiloader, containerService *api.Containe
if err != nil {
return nil, "", err
}
return apiloader.DeserializeContainerService(rawVersionedAPIModel, true)
return apiloader.DeserializeContainerService(rawVersionedAPIModel, true, nil)
}

func (dc *deployCmd) run() error {
Expand Down
2 changes: 1 addition & 1 deletion cmd/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func testAutodeployCredentialHandling(t *testing.T, useManagedIdentity bool, cli
}

apimodel := getExampleAPIModel(useManagedIdentity, clientID, clientSecret)
cs, ver, err := apiloader.DeserializeContainerService([]byte(apimodel), false)
cs, ver, err := apiloader.DeserializeContainerService([]byte(apimodel), false, nil)
if err != nil {
t.Fatalf("unexpected error deserializing the example apimodel: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (gc *generateCmd) validate(cmd *cobra.Command, args []string) {
Locale: gc.locale,
},
}
gc.containerService, gc.apiVersion, err = apiloader.LoadContainerServiceFromFile(gc.apimodelPath, true)
gc.containerService, gc.apiVersion, err = apiloader.LoadContainerServiceFromFile(gc.apimodelPath, true, nil)
if err != nil {
log.Fatalf("error parsing the api model: %s", err.Error())
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (uc *upgradeCmd) validate(cmd *cobra.Command, args []string) {
Locale: uc.locale,
},
}
uc.containerService, uc.apiVersion, err = apiloader.LoadContainerServiceFromFile(apiModelPath, true)
uc.containerService, uc.apiVersion, err = apiloader.LoadContainerServiceFromFile(apiModelPath, true, nil)
if err != nil {
log.Fatalf("error parsing the api model: %s", err.Error())
}
Expand Down
6 changes: 4 additions & 2 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ import:
version: a8983c062be4b565d723c478922d7736e04fdba4
- package: github.com/Masterminds/semver
version: v1.3.1
- package: github.com/imdario/mergo
version: ^0.2.2
testImport:
- package: github.com/onsi/gomega
- package: github.com/onsi/ginkgo
version: v1.3.1
- package: github.com/kelseyhightower/envconfig
version: ~1.3.0
version: ~1.3.0
6 changes: 3 additions & 3 deletions pkg/acsengine/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestExpected(t *testing.T) {
}

for _, tuple := range *apiModelTestFiles {
containerService, version, err := apiloader.LoadContainerServiceFromFile(tuple.APIModelFilename, true)
containerService, version, err := apiloader.LoadContainerServiceFromFile(tuple.APIModelFilename, true, nil)
if err != nil {
t.Errorf("Loading file %s got error: %s", tuple.APIModelFilename, err.Error())
continue
Expand Down Expand Up @@ -139,7 +139,7 @@ func TestExpected(t *testing.T) {
if err != nil {
t.Error(err)
}
containerService, version, err = apiloader.DeserializeContainerService(b, true)
containerService, version, err = apiloader.DeserializeContainerService(b, true, nil)
if err != nil {
t.Error(err)
}
Expand Down Expand Up @@ -281,7 +281,7 @@ func TestTemplateOutputPresence(t *testing.T) {
t.Fatalf("Failed to initialize template generator: %v", err)
}

containerService, _, err := apiloader.LoadContainerServiceFromFile("./testdata/simple/kubernetes.json", true)
containerService, _, err := apiloader.LoadContainerServiceFromFile("./testdata/simple/kubernetes.json", true, nil)
if err != nil {
t.Fatalf("Failed to load container service from file: %v", err)
}
Expand Down
45 changes: 40 additions & 5 deletions pkg/api/apiloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,23 @@ type Apiloader struct {
}

// LoadContainerServiceFromFile loads an ACS Cluster API Model from a JSON file
func (a *Apiloader) LoadContainerServiceFromFile(jsonFile string, validate bool) (*ContainerService, string, error) {
func (a *Apiloader) LoadContainerServiceFromFile(jsonFile string, validate bool, existingContainerService *ContainerService) (*ContainerService, string, error) {
contents, e := ioutil.ReadFile(jsonFile)
if e != nil {
return nil, "", a.Translator.Errorf("error reading file %s: %s", jsonFile, e.Error())
}
return a.DeserializeContainerService(contents, validate)
return a.DeserializeContainerService(contents, validate, existingContainerService)
}

// DeserializeContainerService loads an ACS Cluster API Model, validates it, and returns the unversioned representation
func (a *Apiloader) DeserializeContainerService(contents []byte, validate bool) (*ContainerService, string, error) {
func (a *Apiloader) DeserializeContainerService(contents []byte, validate bool, existingContainerService *ContainerService) (*ContainerService, string, error) {
m := &TypeMeta{}
if err := json.Unmarshal(contents, &m); err != nil {
return nil, "", err
}

version := m.APIVersion
service, err := a.LoadContainerService(contents, version, validate)
service, err := a.LoadContainerService(contents, version, validate, existingContainerService)
if service == nil || err != nil {
log.Infof("Error returned by LoadContainerService: %+v. Attempting to load container service using LoadContainerServiceForAgentPoolOnlyCluster", err)
service, err = a.LoadContainerServiceForAgentPoolOnlyCluster(contents, version, validate)
Expand All @@ -46,13 +47,23 @@ func (a *Apiloader) DeserializeContainerService(contents []byte, validate bool)
}

// LoadContainerService loads an ACS Cluster API Model, validates it, and returns the unversioned representation
func (a *Apiloader) LoadContainerService(contents []byte, version string, validate bool) (*ContainerService, error) {
func (a *Apiloader) LoadContainerService(
contents []byte,
version string,
validate bool,
existingContainerService *ContainerService) (*ContainerService, error) {
switch version {
case v20160930.APIVersion:
containerService := &v20160930.ContainerService{}
if e := json.Unmarshal(contents, &containerService); e != nil {
return nil, e
}
if existingContainerService != nil {
vecs := ConvertContainerServiceToV20160930(existingContainerService)
if e := containerService.Merge(vecs); e != nil {
return nil, e
}
}
setContainerServiceDefaultsv20160930(containerService)
if e := containerService.Properties.Validate(); validate && e != nil {
return nil, e
Expand All @@ -64,6 +75,12 @@ func (a *Apiloader) LoadContainerService(contents []byte, version string, valida
if e := json.Unmarshal(contents, &containerService); e != nil {
return nil, e
}
if existingContainerService != nil {
vecs := ConvertContainerServiceToV20160330(existingContainerService)
if e := containerService.Merge(vecs); e != nil {
return nil, e
}
}
setContainerServiceDefaultsv20160330(containerService)
if e := containerService.Properties.Validate(); validate && e != nil {
return nil, e
Expand All @@ -75,6 +92,12 @@ func (a *Apiloader) LoadContainerService(contents []byte, version string, valida
if e := json.Unmarshal(contents, &containerService); e != nil {
return nil, e
}
if existingContainerService != nil {
vecs := ConvertContainerServiceToV20170131(existingContainerService)
if e := containerService.Merge(vecs); e != nil {
return nil, e
}
}
setContainerServiceDefaultsv20170131(containerService)
if e := containerService.Properties.Validate(); validate && e != nil {
return nil, e
Expand All @@ -86,6 +109,12 @@ func (a *Apiloader) LoadContainerService(contents []byte, version string, valida
if e := json.Unmarshal(contents, &containerService); e != nil {
return nil, e
}
if existingContainerService != nil {
vecs := ConvertContainerServiceToV20170701(existingContainerService)
if e := containerService.Merge(vecs); e != nil {
return nil, e
}
}
setContainerServiceDefaultsv20170701(containerService)
if e := containerService.Properties.Validate(); validate && e != nil {
return nil, e
Expand All @@ -97,6 +126,12 @@ func (a *Apiloader) LoadContainerService(contents []byte, version string, valida
if e := json.Unmarshal(contents, &containerService); e != nil {
return nil, e
}
if existingContainerService != nil {
vecs := ConvertContainerServiceToVLabs(existingContainerService)
if e := containerService.Merge(vecs); e != nil {
return nil, e
}
}
setContainerServiceDefaultsvlabs(containerService)
if e := containerService.Properties.Validate(); validate && e != nil {
return nil, e
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestCustomHyperkubeImageField(t *testing.T) {
apiloader := &Apiloader{
Translator: nil,
}
apimodel, _, err := apiloader.DeserializeContainerService([]byte(exampleAPIModel), false)
apimodel, _, err := apiloader.DeserializeContainerService([]byte(exampleAPIModel), false, nil)
if err != nil {
t.Fatalf("unexpectedly error deserializing the example apimodel: %s", err)
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/api/v20160330/merge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package v20160330

import (
"github.com/imdario/mergo"
)

// Merge existing containerService attribute into cs
func (cs *ContainerService) Merge(ecs *ContainerService) error {
if err := mergo.Merge(cs.Properties.WindowsProfile,
*ecs.Properties.WindowsProfile); err != nil {
return err
}
return nil
}
29 changes: 29 additions & 0 deletions pkg/api/v20160330/merge_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package v20160330

import "testing"

func TestMerge(t *testing.T) {
newCS := &ContainerService{
Properties: &Properties{
WindowsProfile: &WindowsProfile{
AdminUsername: "azureuser",
AdminPassword: "",
},
},
}

existingCS := &ContainerService{
Properties: &Properties{
WindowsProfile: &WindowsProfile{
AdminUsername: "azureuser",
AdminPassword: "existingPassword",
},
},
}
if err := newCS.Merge(existingCS); err != nil {
t.Fatalf("unexpectedly detected merge failure, %+v", err)
}
if newCS.Properties.WindowsProfile.AdminPassword != "existingPassword" {
t.Fatalf("unexpected Properties.WindowsProfile.AdminPassword not updated")
}
}
19 changes: 19 additions & 0 deletions pkg/api/v20160930/merge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package v20160930

import (
"github.com/imdario/mergo"
)

// Merge existing containerService attribute into cs
func (cs *ContainerService) Merge(ecs *ContainerService) error {
if err := mergo.Merge(cs.Properties.ServicePrincipalProfile,
*ecs.Properties.ServicePrincipalProfile); err != nil {
return err
}

if err := mergo.Merge(cs.Properties.WindowsProfile,
*ecs.Properties.WindowsProfile); err != nil {
return err
}
return nil
}
43 changes: 43 additions & 0 deletions pkg/api/v20160930/merge_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package v20160930

import "testing"

func TestMerge(t *testing.T) {
newCS := &ContainerService{
Properties: &Properties{
ServicePrincipalProfile: &ServicePrincipalProfile{
ClientID: "fakeID",
Secret: "",
},
WindowsProfile: &WindowsProfile{
AdminUsername: "azureuser",
AdminPassword: "",
},
},
}

existingCS := &ContainerService{
Properties: &Properties{
ServicePrincipalProfile: &ServicePrincipalProfile{
ClientID: "existingFakeID",
Secret: "existingSecret",
},
WindowsProfile: &WindowsProfile{
AdminUsername: "azureuser",
AdminPassword: "existingPassword",
},
},
}
if err := newCS.Merge(existingCS); err != nil {
t.Fatalf("unexpectedly detected merge failure, %+v", err)
}
if newCS.Properties.ServicePrincipalProfile.ClientID != "fakeID" {
t.Fatalf("unexpected Properties.ServicePrincipalProfile.ClientID changed")
}
if newCS.Properties.ServicePrincipalProfile.Secret != "existingSecret" {
t.Fatalf("unexpected Properties.ServicePrincipalProfile.Secret not updated")
}
if newCS.Properties.WindowsProfile.AdminPassword != "existingPassword" {
t.Fatalf("unexpected Properties.WindowsProfile.AdminPassword not updated")
}
}
19 changes: 19 additions & 0 deletions pkg/api/v20170131/merge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package v20170131

import (
"github.com/imdario/mergo"
)

// Merge existing containerService attribute into cs
func (cs *ContainerService) Merge(ecs *ContainerService) error {
if err := mergo.Merge(cs.Properties.ServicePrincipalProfile,
*ecs.Properties.ServicePrincipalProfile); err != nil {
return err
}

if err := mergo.Merge(cs.Properties.WindowsProfile,
*ecs.Properties.WindowsProfile); err != nil {
return err
}
return nil
}
43 changes: 43 additions & 0 deletions pkg/api/v20170131/merge_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package v20170131

import "testing"

func TestMerge(t *testing.T) {
newCS := &ContainerService{
Properties: &Properties{
ServicePrincipalProfile: &ServicePrincipalProfile{
ClientID: "fakeID",
Secret: "",
},
WindowsProfile: &WindowsProfile{
AdminUsername: "azureuser",
AdminPassword: "",
},
},
}

existingCS := &ContainerService{
Properties: &Properties{
ServicePrincipalProfile: &ServicePrincipalProfile{
ClientID: "existingFakeID",
Secret: "existingSecret",
},
WindowsProfile: &WindowsProfile{
AdminUsername: "azureuser",
AdminPassword: "existingPassword",
},
},
}
if err := newCS.Merge(existingCS); err != nil {
t.Fatalf("unexpectedly detected merge failure, %+v", err)
}
if newCS.Properties.ServicePrincipalProfile.ClientID != "fakeID" {
t.Fatalf("unexpected Properties.ServicePrincipalProfile.ClientID changed")
}
if newCS.Properties.ServicePrincipalProfile.Secret != "existingSecret" {
t.Fatalf("unexpected Properties.ServicePrincipalProfile.Secret not updated")
}
if newCS.Properties.WindowsProfile.AdminPassword != "existingPassword" {
t.Fatalf("unexpected Properties.WindowsProfile.AdminPassword not updated")
}
}
Loading

0 comments on commit 13b0143

Please sign in to comment.