diff --git a/hack/generated/controllers/crd_cosmosdb_test.go b/hack/generated/controllers/crd_cosmosdb_test.go index 523f40b766e..da28d606cc6 100644 --- a/hack/generated/controllers/crd_cosmosdb_test.go +++ b/hack/generated/controllers/crd_cosmosdb_test.go @@ -29,15 +29,13 @@ func Test_CosmosDB_CRUD(t *testing.T) { acct := &documentdb.DatabaseAccount{ ObjectMeta: tc.MakeObjectMetaWithName(namer.GenerateName("db")), Spec: documentdb.DatabaseAccounts_Spec{ - Location: &tc.AzureRegion, - Owner: testcommon.AsOwner(rg.ObjectMeta), - Kind: &kind, - Properties: documentdb.DatabaseAccountCreateUpdateProperties{ - DatabaseAccountOfferType: documentdb.DatabaseAccountCreateUpdatePropertiesDatabaseAccountOfferTypeStandard, - Locations: []documentdb.Location{ - { - LocationName: &tc.AzureRegion, - }, + Location: &tc.AzureRegion, + Owner: testcommon.AsOwner(rg.ObjectMeta), + Kind: &kind, + DatabaseAccountOfferType: documentdb.DatabaseAccountsSpecPropertiesDatabaseAccountOfferTypeStandard, + Locations: []documentdb.Location{ + { + LocationName: &tc.AzureRegion, }, }, }, diff --git a/hack/generated/controllers/crd_disk_test.go b/hack/generated/controllers/crd_disk_test.go index d32e84619de..e57caed78e4 100644 --- a/hack/generated/controllers/crd_disk_test.go +++ b/hack/generated/controllers/crd_disk_test.go @@ -33,26 +33,24 @@ func Test_Disk_CRUD(t *testing.T) { Sku: &compute.DiskSku{ Name: &standardSkuName, }, - Properties: compute.DiskProperties{ - CreationData: compute.CreationData{ - CreateOption: "Empty", - }, - DiskSizeGB: &sizeInGb, + CreationData: compute.CreationData{ + CreateOption: "Empty", }, + DiskSizeGB: &sizeInGb, }, } tc.CreateResourceAndWait(disk) tc.Expect(disk.Status.Location).To(Equal(tc.AzureRegion)) tc.Expect(disk.Status.Sku.Name).To(BeEquivalentTo(&standardSkuName)) - tc.Expect(*disk.Status.Properties.DiskSizeGB).To(BeNumerically(">=", 500)) + tc.Expect(*disk.Status.DiskSizeGB).To(BeNumerically(">=", 500)) tc.Expect(disk.Status.Id).ToNot(BeNil()) armId := *disk.Status.Id // Perform a simple patch. patcher := tc.NewResourcePatcher(disk) - networkAccessPolicy := compute.DiskPropertiesNetworkAccessPolicyDenyAll - disk.Spec.Properties.NetworkAccessPolicy = &networkAccessPolicy + networkAccessPolicy := compute.DisksSpecPropertiesNetworkAccessPolicyDenyAll + disk.Spec.NetworkAccessPolicy = &networkAccessPolicy patcher.Patch(disk) objectKey, err := client.ObjectKeyFromObject(disk) @@ -62,7 +60,7 @@ func Test_Disk_CRUD(t *testing.T) { tc.Eventually(func() *compute.NetworkAccessPolicy_Status { var updatedDisk compute.Disk tc.GetResource(objectKey, &updatedDisk) - return updatedDisk.Status.Properties.NetworkAccessPolicy + return updatedDisk.Status.NetworkAccessPolicy }).Should(BeEquivalentTo(&networkAccessPolicy)) tc.DeleteResourceAndWait(disk) diff --git a/hack/generated/controllers/crd_networking_loadbalancer_test.go b/hack/generated/controllers/crd_networking_loadbalancer_test.go index 9cd0b1a3944..6749c91c642 100644 --- a/hack/generated/controllers/crd_networking_loadbalancer_test.go +++ b/hack/generated/controllers/crd_networking_loadbalancer_test.go @@ -40,9 +40,7 @@ func Test_LoadBalancer_CRUD(t *testing.T) { Sku: &network.PublicIPAddressSku{ Name: &sku, }, - Properties: network.PublicIPAddressPropertiesFormat{ - PublicIPAllocationMethod: network.PublicIPAddressPropertiesFormatPublicIPAllocationMethodStatic, - }, + PublicIPAllocationMethod: network.PublicIPAddressesSpecPropertiesPublicIPAllocationMethodStatic, }, } @@ -60,33 +58,31 @@ func Test_LoadBalancer_CRUD(t *testing.T) { Sku: &network.LoadBalancerSku{ Name: &loadBalancerSku, }, - Properties: network.LoadBalancerPropertiesFormat{ - FrontendIPConfigurations: []network.FrontendIPConfiguration{ - { - Name: lbFrontendName, - Properties: &network.FrontendIPConfigurationPropertiesFormat{ - PublicIPAddress: &network.SubResource{ - Reference: tc.MakeReferenceFromResource(publicIPAddress), - }, + FrontendIPConfigurations: []network.FrontendIPConfiguration{ + { + Name: lbFrontendName, + Properties: &network.FrontendIPConfigurationPropertiesFormat{ + PublicIPAddress: &network.SubResource{ + Reference: tc.MakeReferenceFromResource(publicIPAddress), }, }, }, - // TODO: The below stuff isn't really necessary for LB CRUD but is required for VMSS... - InboundNatPools: []network.InboundNatPool{ - { - Name: "MyFancyNatPool", - Properties: &network.InboundNatPoolPropertiesFormat{ - FrontendIPConfiguration: network.SubResource{ - Reference: genruntime.ResourceReference{ - // TODO: This is still really awkward - ARMID: tc.MakeARMId(rg.Name, "Microsoft.Network", "loadBalancers", lbName, "frontendIPConfigurations", lbFrontendName), - }, + }, + // TODO: The below stuff isn't really necessary for LB CRUD but is required for VMSS... + InboundNatPools: []network.InboundNatPool{ + { + Name: "MyFancyNatPool", + Properties: &network.InboundNatPoolPropertiesFormat{ + FrontendIPConfiguration: network.SubResource{ + Reference: genruntime.ResourceReference{ + // TODO: This is still really awkward + ARMID: tc.MakeARMId(rg.Name, "Microsoft.Network", "loadBalancers", lbName, "frontendIPConfigurations", lbFrontendName), }, - Protocol: network.InboundNatPoolPropertiesFormatProtocolTcp, - FrontendPortRangeStart: 50000, - FrontendPortRangeEnd: 51000, - BackendPort: 22, }, + Protocol: network.InboundNatPoolPropertiesFormatProtocolTcp, + FrontendPortRangeStart: 50000, + FrontendPortRangeEnd: 51000, + BackendPort: 22, }, }, }, diff --git a/hack/generated/controllers/crd_networking_publicip_test.go b/hack/generated/controllers/crd_networking_publicip_test.go index 7f6a0f3ea73..735d0befb63 100644 --- a/hack/generated/controllers/crd_networking_publicip_test.go +++ b/hack/generated/controllers/crd_networking_publicip_test.go @@ -34,9 +34,7 @@ func Test_PublicIP_CRUD(t *testing.T) { Sku: &network.PublicIPAddressSku{ Name: &sku, }, - Properties: network.PublicIPAddressPropertiesFormat{ - PublicIPAllocationMethod: network.PublicIPAddressPropertiesFormatPublicIPAllocationMethodStatic, - }, + PublicIPAllocationMethod: network.PublicIPAddressesSpecPropertiesPublicIPAllocationMethodStatic, }, } @@ -49,7 +47,7 @@ func Test_PublicIP_CRUD(t *testing.T) { patcher := tc.NewResourcePatcher(publicIPAddress) idleTimeoutInMinutes := 7 - publicIPAddress.Spec.Properties.IdleTimeoutInMinutes = &idleTimeoutInMinutes + publicIPAddress.Spec.IdleTimeoutInMinutes = &idleTimeoutInMinutes patcher.Patch(publicIPAddress) objectKey, err := client.ObjectKeyFromObject(publicIPAddress) @@ -59,7 +57,7 @@ func Test_PublicIP_CRUD(t *testing.T) { tc.Eventually(func() *int { updatedIP := &network.PublicIPAddresses{} tc.GetResource(objectKey, updatedIP) - return updatedIP.Status.Properties.IdleTimeoutInMinutes + return updatedIP.Status.IdleTimeoutInMinutes }).Should(Equal(&idleTimeoutInMinutes)) tc.DeleteResourceAndWait(publicIPAddress) diff --git a/hack/generated/controllers/crd_servicebus_basic_test.go b/hack/generated/controllers/crd_servicebus_basic_test.go index 3557022685a..7f657d7915e 100644 --- a/hack/generated/controllers/crd_servicebus_basic_test.go +++ b/hack/generated/controllers/crd_servicebus_basic_test.go @@ -32,9 +32,7 @@ func Test_ServiceBus_Basic_CRUD(t *testing.T) { Sku: &servicebus.SBSku{ Name: servicebus.SBSkuNameBasic, }, - Properties: servicebus.SBNamespaceProperties{ - ZoneRedundant: &zoneRedundant, - }, + ZoneRedundant: &zoneRedundant, }, } @@ -76,6 +74,6 @@ func ServiceBus_Queue_CRUD(tc testcommon.KubePerTestContext, sbNamespace metav1. tc.Expect(queue.Status.Id).ToNot(BeNil()) // a basic assertion on a property - tc.Expect(queue.Status.Properties.SizeInBytes).ToNot(BeNil()) - tc.Expect(*queue.Status.Properties.SizeInBytes).To(Equal(0)) + tc.Expect(queue.Status.SizeInBytes).ToNot(BeNil()) + tc.Expect(*queue.Status.SizeInBytes).To(Equal(0)) } diff --git a/hack/generated/controllers/crd_servicebus_standard_test.go b/hack/generated/controllers/crd_servicebus_standard_test.go index 0b67e548e80..11d58282177 100644 --- a/hack/generated/controllers/crd_servicebus_standard_test.go +++ b/hack/generated/controllers/crd_servicebus_standard_test.go @@ -32,9 +32,7 @@ func Test_ServiceBus_Standard_CRUD(t *testing.T) { Sku: &servicebus.SBSku{ Name: servicebus.SBSkuNameStandard, }, - Properties: servicebus.SBNamespaceProperties{ - ZoneRedundant: &zoneRedundant, - }, + ZoneRedundant: &zoneRedundant, }, } @@ -79,6 +77,6 @@ func ServiceBus_Topic_CRUD(tc testcommon.KubePerTestContext, sbNamespace metav1. tc.Expect(topic.Status.Id).ToNot(BeNil()) // a basic assertion on a property - tc.Expect(topic.Status.Properties.SizeInBytes).ToNot(BeNil()) - tc.Expect(*topic.Status.Properties.SizeInBytes).To(Equal(0)) + tc.Expect(topic.Status.SizeInBytes).ToNot(BeNil()) + tc.Expect(*topic.Status.SizeInBytes).To(Equal(0)) } diff --git a/hack/generated/controllers/crd_storageaccount_test.go b/hack/generated/controllers/crd_storageaccount_test.go index ea3d8c58206..e111b6f0be3 100644 --- a/hack/generated/controllers/crd_storageaccount_test.go +++ b/hack/generated/controllers/crd_storageaccount_test.go @@ -33,13 +33,11 @@ func Test_StorageAccount_CRUD(t *testing.T) { Location: tc.AzureRegion, Owner: testcommon.AsOwner(rg.ObjectMeta), Kind: storage.StorageAccountsSpecKindBlobStorage, - Sku: storage.Sku{ - Name: storage.SkuNameStandardLRS, + Sku: storage.StorageAccounts_Spec_Sku{ + Name: storage.StorageAccountsSpecSkuNameStandardLRS, }, // TODO: They mark this property as optional but actually it is required - Properties: &storage.StorageAccountPropertiesCreateParameters{ - AccessTier: &accessTier, - }, + AccessTier: &accessTier, }, } diff --git a/hack/generated/controllers/crd_virtualnetwork_test.go b/hack/generated/controllers/crd_virtualnetwork_test.go index 940111d8b09..89ecf3060f4 100644 --- a/hack/generated/controllers/crd_virtualnetwork_test.go +++ b/hack/generated/controllers/crd_virtualnetwork_test.go @@ -26,10 +26,8 @@ func Test_VirtualNetwork_CRUD(t *testing.T) { Spec: network.VirtualNetworks_Spec{ Owner: testcommon.AsOwner(rg.ObjectMeta), Location: testcommon.DefaultTestRegion, - Properties: network.VirtualNetworkPropertiesFormat{ - AddressSpace: network.AddressSpace{ - AddressPrefixes: []string{"10.0.0.0/8"}, - }, + AddressSpace: network.AddressSpace{ + AddressPrefixes: []string{"10.0.0.0/8"}, }, }, } diff --git a/hack/generated/pkg/reconcilers/azure_deployment_reconciler.go b/hack/generated/pkg/reconcilers/azure_deployment_reconciler.go index 2ead35f6ea3..76fef26d20f 100644 --- a/hack/generated/pkg/reconcilers/azure_deployment_reconciler.go +++ b/hack/generated/pkg/reconcilers/azure_deployment_reconciler.go @@ -70,8 +70,10 @@ const ( DeleteActionMonitorDelete = DeleteAction("MonitorDelete") ) -type CreateOrUpdateActionFunc = func(ctx context.Context) (ctrl.Result, error) -type DeleteActionFunc = func(ctx context.Context) (ctrl.Result, error) +type ( + CreateOrUpdateActionFunc = func(ctx context.Context) (ctrl.Result, error) + DeleteActionFunc = func(ctx context.Context) (ctrl.Result, error) +) var _ genruntime.Reconciler = &AzureDeploymentReconciler{} @@ -109,7 +111,6 @@ func NewAzureDeploymentReconciler( func (r *AzureDeploymentReconciler) CreateOrUpdate(ctx context.Context) (ctrl.Result, error) { action, actionFunc, err := r.DetermineCreateOrUpdateAction() - if err != nil { r.log.Error(err, "error determining create or update action") r.recorder.Event(r.obj, v1.EventTypeWarning, "DetermineCreateOrUpdateActionError", err.Error()) @@ -128,7 +129,6 @@ func (r *AzureDeploymentReconciler) CreateOrUpdate(ctx context.Context) (ctrl.Re func (r *AzureDeploymentReconciler) Delete(ctx context.Context) (ctrl.Result, error) { action, actionFunc, err := r.DetermineDeleteAction() - if err != nil { r.log.Error(err, "error determining delete action") r.recorder.Event(r.obj, v1.EventTypeWarning, "DetermineDeleteActionError", err.Error()) @@ -350,7 +350,6 @@ func NoAction(_ context.Context) (ctrl.Result, error) { // StartDeleteOfResource will begin the delete of a resource by telling Azure to start deleting it. The resource will be // marked with the provisioning state of "Deleting". func (r *AzureDeploymentReconciler) StartDeleteOfResource(ctx context.Context) (ctrl.Result, error) { - msg := "Starting delete of resource" r.log.Info(msg) r.recorder.Event(r.obj, v1.EventTypeNormal, string(DeleteActionBeginDelete), msg) @@ -364,7 +363,6 @@ func (r *AzureDeploymentReconciler) StartDeleteOfResource(ctx context.Context) ( // TODO: return the data we need. // TODO(matthchr): For now just emulate this with reflection resource, err := r.constructArmResource(ctx) - if err != nil { // If the error is that the owner isn't found, that probably // means that the owner was deleted in Kubernetes. The current @@ -373,9 +371,9 @@ func (r *AzureDeploymentReconciler) StartDeleteOfResource(ctx context.Context) ( var typedErr *genruntime.ReferenceNotFound if errors.As(err, &typedErr) { // TODO: We should confirm the above assumption by performing a HEAD on - // TODO: the resource in Azure. This requires GetApiVersion() on metaObj which + // TODO: the resource in Azure. This requires GetAPIVersion() on metaObj which // TODO: we don't currently have in the interface. - // gr.ARMClient.HeadResource(ctx, data.resourceID, r.obj.GetApiVersion()) + // gr.ARMClient.HeadResource(ctx, data.resourceID, r.obj.GetAPIVersion()) return ctrl.Result{}, r.deleteResourceSucceeded(ctx) } @@ -413,7 +411,6 @@ func (r *AzureDeploymentReconciler) StartDeleteOfResource(ctx context.Context) ( // MonitorDelete will call Azure to check if the resource still exists. If so, it will requeue, else, // the finalizer will be removed. func (r *AzureDeploymentReconciler) MonitorDelete(ctx context.Context) (ctrl.Result, error) { - msg := "Continue monitoring deletion" r.log.V(1).Info(msg) r.recorder.Event(r.obj, v1.EventTypeNormal, string(DeleteActionMonitorDelete), msg) @@ -594,7 +591,6 @@ func (r *AzureDeploymentReconciler) MonitorDeployment(ctx context.Context) (ctrl func (r *AzureDeploymentReconciler) ManageOwnership(ctx context.Context) (ctrl.Result, error) { r.log.V(1).Info("applying ownership", "action", CreateOrUpdateActionManageOwnership) isOwnerReady, err := r.isOwnerReady(ctx) - if err != nil { return ctrl.Result{}, err } diff --git a/hack/generated/pkg/reflecthelpers/reflect_helpers_test.go b/hack/generated/pkg/reflecthelpers/reflect_helpers_test.go index eb8e1041fd2..7da415bf258 100644 --- a/hack/generated/pkg/reflecthelpers/reflect_helpers_test.go +++ b/hack/generated/pkg/reflecthelpers/reflect_helpers_test.go @@ -15,6 +15,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + //nolint:staticcheck // ignoring deprecation (SA1019) to unblock CI builds "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -22,6 +23,7 @@ import ( "github.com/Azure/azure-service-operator/hack/generated/pkg/genruntime" "github.com/Azure/azure-service-operator/hack/generated/pkg/reflecthelpers" "github.com/Azure/azure-service-operator/hack/generated/pkg/util/kubeclient" + // TODO: Do we want to use a sample object rather than a code generated one? batch "github.com/Azure/azure-service-operator/hack/generated/_apis/microsoft.batch/v1alpha1api20210101" @@ -51,7 +53,6 @@ func createDummyResource() *batch.BatchAccount { Owner: genruntime.KnownResourceReference{ Name: "myrg", }, - Properties: batch.BatchAccountCreateProperties{}, }, ObjectMeta: metav1.ObjectMeta{ Name: "test-group", @@ -162,7 +163,7 @@ func Test_FindReferences(t *testing.T) { g.Expect(test.client.Create(ctx, rg)).To(Succeed()) account := createDummyResource() ref := genruntime.ResourceReference{ARMID: "test"} - account.Spec.Properties.KeyVaultReference = &batch.KeyVaultReference{ + account.Spec.KeyVaultReference = &batch.KeyVaultReference{ Reference: ref, } g.Expect(test.client.Create(ctx, account)).To(Succeed()) diff --git a/hack/generated/pkg/util/patch/patch_test.go b/hack/generated/pkg/util/patch/patch_test.go index 169c26733bc..4a774f65bb0 100644 --- a/hack/generated/pkg/util/patch/patch_test.go +++ b/hack/generated/pkg/util/patch/patch_test.go @@ -87,7 +87,6 @@ func TestPatchNotFound(t *testing.T) { } func TestHelperPatch(t *testing.T) { - tests := []struct { name string before runtime.Object diff --git a/hack/generator/azure-arm.yaml b/hack/generator/azure-arm.yaml index acf18d1bf7e..bc31d82297a 100644 --- a/hack/generator/azure-arm.yaml +++ b/hack/generator/azure-arm.yaml @@ -283,11 +283,11 @@ typeTransformers: because: it has no writable properties in swagger # Deal with properties that should have been marked readOnly but weren't - - name: SBNamespaceProperties + - name: Namespaces_Spec group: microsoft.servicebus property: PrivateEndpointConnections remove: true - because: The this property should have been marked readonly but wasn't. + because: This property should have been marked readonly but wasn't. status: schemaRoot: "./specs/azure-rest-api-specs/specification" diff --git a/hack/generator/pkg/astbuilder/assignments.go b/hack/generator/pkg/astbuilder/assignments.go index afbdd83a482..01ec66af0e1 100644 --- a/hack/generator/pkg/astbuilder/assignments.go +++ b/hack/generator/pkg/astbuilder/assignments.go @@ -26,6 +26,17 @@ func SimpleAssignment(lhs dst.Expr, tok token.Token, rhs dst.Expr) *dst.AssignSt } } +// QualifiedAssignment performs a simple assignment like: +// . := // tok = token.DEFINE +// or . = // tok = token.ASSIGN +func QualifiedAssignment(lhs dst.Expr, lhsSel string, tok token.Token, rhs dst.Expr) *dst.AssignStmt { + return &dst.AssignStmt{ + Lhs: []dst.Expr{Selector(lhs, lhsSel)}, + Tok: tok, + Rhs: []dst.Expr{dst.Clone(rhs).(dst.Expr)}, + } +} + // SimpleAssignmentWithErr performs a simple assignment like: // , err := // tok = token.DEFINE // or , err = // tok = token.ASSIGN diff --git a/hack/generator/pkg/astbuilder/builder.go b/hack/generator/pkg/astbuilder/builder.go index d094d7158e7..24252761afa 100644 --- a/hack/generator/pkg/astbuilder/builder.go +++ b/hack/generator/pkg/astbuilder/builder.go @@ -18,7 +18,6 @@ import ( // return , err // } func CheckErrorAndReturn(otherReturns ...dst.Expr) dst.Stmt { - returnValues := append([]dst.Expr{}, cloneExprSlice(otherReturns)...) returnValues = append(returnValues, dst.NewIdent("err")) @@ -35,12 +34,11 @@ func CheckErrorAndReturn(otherReturns ...dst.Expr) dst.Stmt { // // } func CheckErrorAndSingleStatement(stmt dst.Stmt) dst.Stmt { - return &dst.IfStmt{ Cond: &dst.BinaryExpr{ X: dst.NewIdent("err"), Op: token.NEQ, - Y: dst.NewIdent("nil"), + Y: Nil(), }, Body: &dst.BlockStmt{ List: []dst.Stmt{ @@ -88,13 +86,17 @@ func NewVariableQualified(varName string, qualifier string, structName string) d // // …as that does not work for enum types. func NewVariable(varName string, structName string) dst.Stmt { + return NewVariableWithType(varName, dst.NewIdent(structName)) +} + +func NewVariableWithType(varName string, varType dst.Expr) dst.Stmt { return &dst.DeclStmt{ Decl: &dst.GenDecl{ Tok: token.VAR, Specs: []dst.Spec{ &dst.TypeSpec{ Name: dst.NewIdent(varName), - Type: dst.NewIdent(structName), + Type: varType, }, }, }, @@ -140,7 +142,6 @@ func VariableDeclaration(ident string, typ dst.Expr, comment string) *dst.GenDec // , ok := .() // func TypeAssert(lhs dst.Expr, rhs dst.Expr, typ dst.Expr) *dst.AssignStmt { - return &dst.AssignStmt{ Lhs: []dst.Expr{ dst.Clone(lhs).(dst.Expr), @@ -192,7 +193,7 @@ func ReturnIfNil(toCheck dst.Expr, returns ...dst.Expr) dst.Stmt { &dst.BinaryExpr{ X: dst.Clone(toCheck).(dst.Expr), Op: token.EQL, - Y: dst.NewIdent("nil"), + Y: Nil(), }, returns...) } @@ -208,7 +209,7 @@ func ReturnIfNotNil(toCheck dst.Expr, returns ...dst.Expr) dst.Stmt { &dst.BinaryExpr{ X: dst.Clone(toCheck).(dst.Expr), Op: token.NEQ, - Y: dst.NewIdent("nil"), + Y: Nil(), }, returns...) } @@ -303,7 +304,7 @@ func Returns(returns ...dst.Expr) dst.Stmt { // return nil // func ReturnNoError() dst.Stmt { - result := Returns(dst.NewIdent("nil")) + result := Returns(Nil()) result.Decorations().Before = dst.EmptyLine result.Decorations().Start.Append("// No error") return result @@ -335,13 +336,19 @@ func QualifiedTypeName(pkg string, name string) *dst.SelectorExpr { // Selector generates a field reference into an existing expression // -// . +// ..(.…) // -func Selector(expr dst.Expr, name string) *dst.SelectorExpr { - return &dst.SelectorExpr{ - X: dst.Clone(expr).(dst.Expr), - Sel: dst.NewIdent(name), +func Selector(expr dst.Expr, names ...string) *dst.SelectorExpr { + exprs := []dst.Expr{dst.Clone(expr).(dst.Expr)} + for _, name := range names { + exprs = append(exprs, dst.NewIdent(name)) } + + return Reduce( + func(l, r dst.Expr) dst.Expr { + return &dst.SelectorExpr{X: l, Sel: r.(*dst.Ident)} + }, + exprs...).(*dst.SelectorExpr) } // NotEqual generates a != comparison between the two expressions @@ -356,6 +363,16 @@ func NotEqual(lhs dst.Expr, rhs dst.Expr) *dst.BinaryExpr { } } +// NotNil generates an `x != nil` comparison +func NotNil(x dst.Expr) *dst.BinaryExpr { + return NotEqual(x, Nil()) +} + +// Nil returns the nil identifier (not keyword!) +func Nil() *dst.Ident { + return dst.NewIdent("nil") +} + // StatementBlock generates a block containing the supplied statements func StatementBlock(statements ...dst.Stmt) *dst.BlockStmt { return &dst.BlockStmt{ @@ -415,3 +432,32 @@ func cloneStmtSlice(stmts []dst.Stmt) []dst.Stmt { return result } + +func JoinOr(exprs ...dst.Expr) dst.Expr { + return JoinBinaryOp(token.LOR, exprs...) +} + +func JoinAnd(exprs ...dst.Expr) dst.Expr { + return JoinBinaryOp(token.LAND, exprs...) +} + +func JoinBinaryOp(op token.Token, exprs ...dst.Expr) dst.Expr { + return Reduce( + func(x, y dst.Expr) dst.Expr { + return &dst.BinaryExpr{X: x, Op: op, Y: y} + }, + exprs...) +} + +func Reduce(operator func(l, r dst.Expr) dst.Expr, exprs ...dst.Expr) dst.Expr { + if len(exprs) == 0 { + panic("must provide at least one expression to reduce") + } + + result := exprs[0] + for _, e := range exprs[1:] { + result = operator(result, e) + } + + return result +} diff --git a/hack/generator/pkg/astbuilder/builder_test.go b/hack/generator/pkg/astbuilder/builder_test.go new file mode 100644 index 00000000000..a47aaa58fda --- /dev/null +++ b/hack/generator/pkg/astbuilder/builder_test.go @@ -0,0 +1,78 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +package astbuilder + +import ( + "go/token" + "testing" + + "github.com/dave/dst" + "github.com/onsi/gomega" + . "github.com/onsi/gomega" +) + +func asplode(l, r dst.Expr) dst.Expr { + panic("asplode was invoked") +} + +func TestReduceZero(t *testing.T) { + g := gomega.NewWithT(t) + + g.Expect(func() { Reduce(asplode) }).To(PanicWith("must provide at least one expression to reduce")) +} + +func TestReduceOne(t *testing.T) { + g := gomega.NewWithT(t) + + expr := &dst.BadExpr{} + g.Expect(Reduce(asplode, expr)).To(BeIdenticalTo(expr)) +} + +func TestJoinOr(t *testing.T) { + g := gomega.NewWithT(t) + + expr1 := &dst.CallExpr{} + expr2 := &dst.BadExpr{} + + expected := &dst.BinaryExpr{X: expr1, Op: token.LOR, Y: expr2} + + g.Expect(JoinOr(expr1, expr2)).To(Equal(expected)) +} + +func TestJoinAnd(t *testing.T) { + g := gomega.NewWithT(t) + + expr1 := &dst.CallExpr{} + expr2 := &dst.BadExpr{} + + expected := &dst.BinaryExpr{X: expr1, Op: token.LAND, Y: expr2} + + g.Expect(JoinAnd(expr1, expr2)).To(Equal(expected)) +} + +func TestSelectorWithMoreNames(t *testing.T) { + g := gomega.NewWithT(t) + + selector := Selector( + dst.NewIdent("chair"), + "table", + "miracle", + "ecstasy", + ) + + expectedSelector := &dst.SelectorExpr{ + X: &dst.SelectorExpr{ + X: &dst.SelectorExpr{ + X: dst.NewIdent("chair"), + Sel: dst.NewIdent("table"), + }, + Sel: dst.NewIdent("miracle"), + }, + Sel: dst.NewIdent("ecstasy"), + } + + g.Expect(selector).To(Equal(expectedSelector)) +} diff --git a/hack/generator/pkg/astbuilder/conditions.go b/hack/generator/pkg/astbuilder/conditions.go index a4bd9253920..e29541e8dd9 100644 --- a/hack/generator/pkg/astbuilder/conditions.go +++ b/hack/generator/pkg/astbuilder/conditions.go @@ -6,8 +6,9 @@ package astbuilder import ( - "github.com/dave/dst" "go/token" + + "github.com/dave/dst" ) // SimpleIfElse creates a simple if statement with a single statement in each branch @@ -39,7 +40,7 @@ func IfNotNil(toCheck dst.Expr, statements ...dst.Stmt) *dst.IfStmt { Cond: &dst.BinaryExpr{ X: dst.Clone(toCheck).(dst.Expr), Op: token.NEQ, - Y: dst.NewIdent("nil"), + Y: Nil(), }, Body: StatementBlock(statements...), } diff --git a/hack/generator/pkg/astmodel/arm_spec_interface.go b/hack/generator/pkg/astmodel/arm_spec_interface.go index 557aed153b6..2485e551a97 100644 --- a/hack/generator/pkg/astmodel/arm_spec_interface.go +++ b/hack/generator/pkg/astmodel/arm_spec_interface.go @@ -23,7 +23,7 @@ const ( func checkPropertyPresence(o *ObjectType, name PropertyName) error { _, ok := o.Property(name) if !ok { - return errors.Errorf("Resource spec doesn't have %q property", name) + return errors.Errorf("resource spec doesn't have %q property", name) } return nil diff --git a/hack/generator/pkg/astmodel/armconversion/convert_from_arm_function_builder.go b/hack/generator/pkg/astmodel/armconversion/convert_from_arm_function_builder.go index 4847b1e4be4..45f0513431c 100644 --- a/hack/generator/pkg/astmodel/armconversion/convert_from_arm_function_builder.go +++ b/hack/generator/pkg/astmodel/armconversion/convert_from_arm_function_builder.go @@ -8,6 +8,7 @@ package armconversion import ( "fmt" "go/token" + "strings" "github.com/dave/dst" @@ -64,6 +65,7 @@ func newConvertFromARMFunctionBuilder( result.namePropertyHandler, result.referencePropertyHandler, result.ownerPropertyHandler, + result.flattenedPropertyHandler, result.propertiesWithSameNameHandler, } @@ -71,7 +73,6 @@ func newConvertFromARMFunctionBuilder( } func (builder *convertFromARMBuilder) functionDeclaration() *dst.FuncDecl { - fn := &astbuilder.FuncDetails{ Name: builder.methodName, ReceiverIdent: builder.receiverIdent, @@ -94,50 +95,42 @@ func (builder *convertFromARMBuilder) functionDeclaration() *dst.FuncDecl { func (builder *convertFromARMBuilder) functionBodyStatements() []dst.Stmt { var result []dst.Stmt - assertStmts := builder.assertInputTypeIsARM() - conversionStmts := generateTypeConversionAssignments( builder.armType, builder.kubeType, builder.propertyConversionHandler) - // No conversions to perform -- some properties might be ignored - if len(removeEmptyStatements(conversionStmts)) == 0 { - return []dst.Stmt{ - astbuilder.ReturnNoError(), - } - } + hasConversions := len(removeEmptyStatements(conversionStmts)) > 0 + + assertStmts := builder.assertInputTypeIsARM(hasConversions) // perform a type assert and check its results result = append(result, assertStmts...) - // Do all of the assignments for each property - result = append( - result, - conversionStmts...) + if hasConversions { + result = append(result, conversionStmts...) + } - // Return nil error if we make it to the end - result = append( - result, - &dst.ReturnStmt{ - Results: []dst.Expr{ - dst.NewIdent("nil"), - }, - }) + result = append(result, astbuilder.ReturnNoError()) return result } -func (builder *convertFromARMBuilder) assertInputTypeIsARM() []dst.Stmt { +func (builder *convertFromARMBuilder) assertInputTypeIsARM(needsResult bool) []dst.Stmt { var result []dst.Stmt fmtPackage := builder.codeGenerationContext.MustGetImportedPackageName(astmodel.FmtReference) + dest := builder.typedInputIdent + if !needsResult { + dest = "_" // drop result + } + // perform a type assert result = append( result, astbuilder.TypeAssert( - dst.NewIdent(builder.typedInputIdent), + dst.NewIdent(dest), dst.NewIdent(builder.inputIdent), dst.NewIdent(builder.armTypeIdent))) @@ -217,13 +210,150 @@ func (builder *convertFromARMBuilder) ownerPropertyHandler( return nil } - result := astbuilder.SimpleAssignment( - astbuilder.Selector(dst.NewIdent(builder.receiverIdent), string(toProp.PropertyName())), + result := astbuilder.QualifiedAssignment( + dst.NewIdent(builder.receiverIdent), + string(toProp.PropertyName()), token.ASSIGN, dst.NewIdent(builder.idFactory.CreateIdentifier(astmodel.OwnerProperty, astmodel.NotExported))) return []dst.Stmt{result} } +// flattenedPropertyHandler generates conversions for properties that +// were flattened out from inside other properties. The code it generates will +// look something like: +// +// If 'X' is a property that was flattened: +// +// k8sObj.Y1 = armObj.X.Y1; +// k8sObj.Y2 = armObj.X.Y2; +// +// in reality each assignment is likely to be another conversion that is specific +// to the type being converted. +func (builder *convertFromARMBuilder) flattenedPropertyHandler( + toProp *astmodel.PropertyDefinition, + fromType *astmodel.ObjectType) []dst.Stmt { + + if !toProp.WasFlattened() { + return nil + } + + for _, fromProp := range fromType.Properties() { + if toProp.WasFlattenedFrom(fromProp.PropertyName()) { + return builder.buildFlattenedAssignment(toProp, fromProp) + } + } + + panic(fmt.Sprintf("couldn’t find source ARM property ‘%s’ that k8s property ‘%s’ was flattened from", toProp.FlattenedFrom()[0], toProp.PropertyName())) +} + +func (builder *convertFromARMBuilder) buildFlattenedAssignment(toProp *astmodel.PropertyDefinition, fromProp *astmodel.PropertyDefinition) []dst.Stmt { + if len(toProp.FlattenedFrom()) > 1 { + // this doesn't appear to happen anywhere in the JSON schemas currently + + var props []string + for _, ff := range toProp.FlattenedFrom() { + props = append(props, string(ff)) + } + + panic(fmt.Sprintf("need to implement multiple levels of flattening: property ‘%s’ on %s was flattened from ‘%s’", + toProp.PropertyName(), + builder.receiverIdent, + strings.Join(props, "."))) + } + + allTypes := builder.codeGenerationContext.GetAllReachableTypes() + + // the from shape here must be: + // 1. maybe a typename, pointing to… + // 2. maybe optional, wrapping … + // 3. maybe a typename, pointing to… + // 4. an object type + + // (1.) resolve any outer typename + fromPropType, err := allTypes.FullyResolve(fromProp.PropertyType()) + if err != nil { + panic(err) + } + + var fromPropObjType *astmodel.ObjectType + var objOk bool + // (2.) resolve any optional type + generateNilCheck := false + if fromPropOptType, ok := fromPropType.(*astmodel.OptionalType); ok { + generateNilCheck = true + // (3.) resolve any inner typename + elementType, err := allTypes.FullyResolve(fromPropOptType.Element()) + if err != nil { + panic(err) + } + + // (4.) resolve the inner object type + fromPropObjType, objOk = elementType.(*astmodel.ObjectType) + } else { + // (4.) resolve the inner object type + fromPropObjType, objOk = fromPropType.(*astmodel.ObjectType) + } + + if !objOk { + // see pipeline_flatten_properties.go:flattenPropType which will only flatten from (optional) object types + panic(fmt.Sprintf("property ‘%s’ marked as flattened from non-object type %T, which shouldn’t be possible", + toProp.PropertyName(), + fromPropType)) + } + + // *** Now generate the code! *** + toPropName := toProp.PropertyName() + nestedProp, ok := fromPropObjType.Property(toPropName) + if !ok { + panic("couldn't find source of flattened property") + } + + // need to make a clone of builder.locals if we are going to nest in an if statement + locals := builder.locals + if generateNilCheck { + locals = locals.Clone() + } + + stmts := builder.typeConversionBuilder.BuildConversion( + astmodel.ConversionParameters{ + Source: astbuilder.Selector(dst.NewIdent(builder.typedInputIdent), string(fromProp.PropertyName()), string(toPropName)), + SourceType: nestedProp.PropertyType(), + Destination: astbuilder.Selector(dst.NewIdent(builder.receiverIdent), string(toPropName)), + DestinationType: toProp.PropertyType(), + NameHint: string(toProp.PropertyName()), + ConversionContext: nil, + AssignmentHandler: nil, + Locals: locals, + }) + + // we were unable to generate an inner conversion so we cannot generate the overall conversion + if len(stmts) == 0 { + return nil + } + + if generateNilCheck { + propToCheck := astbuilder.Selector(dst.NewIdent(builder.typedInputIdent), string(fromProp.PropertyName())) + stmts = []dst.Stmt{ + &dst.IfStmt{ + Cond: astbuilder.NotNil(propToCheck), + Body: &dst.BlockStmt{List: stmts}, + }, + } + } + + result := []dst.Stmt{ + &dst.EmptyStmt{ + Decs: dst.EmptyStmtDecorations{ + NodeDecs: dst.NodeDecs{ + End: []string{"// copying flattened property:"}, + }, + }, + }, + } + + return append(result, stmts...) +} + func (builder *convertFromARMBuilder) propertiesWithSameNameHandler( toProp *astmodel.PropertyDefinition, fromType *astmodel.ObjectType) []dst.Stmt { @@ -259,7 +389,6 @@ func (builder *convertFromARMBuilder) propertiesWithSameNameHandler( // } // = func (builder *convertFromARMBuilder) convertComplexTypeNameProperty(conversionBuilder *astmodel.ConversionFunctionBuilder, params astmodel.ConversionParameters) []dst.Stmt { - destinationType, ok := params.DestinationType.(astmodel.TypeName) if !ok { return nil diff --git a/hack/generator/pkg/astmodel/armconversion/convert_to_arm_function_builder.go b/hack/generator/pkg/astmodel/armconversion/convert_to_arm_function_builder.go index 2a7ac636389..4c0e4783ebe 100644 --- a/hack/generator/pkg/astmodel/armconversion/convert_to_arm_function_builder.go +++ b/hack/generator/pkg/astmodel/armconversion/convert_to_arm_function_builder.go @@ -15,8 +15,10 @@ import ( "github.com/Azure/azure-service-operator/hack/generator/pkg/astmodel" ) -const nameParameterString = "name" -const resolvedReferencesParameterString = "resolvedReferences" +const ( + nameParameterString = "name" + resolvedReferencesParameterString = "resolvedReferences" +) type convertToARMBuilder struct { conversionBuilder @@ -65,6 +67,7 @@ func newConvertToARMFunctionBuilder( result.referencePropertyHandler, result.fixedValuePropertyHandler(astmodel.TypeProperty), result.fixedValuePropertyHandler(astmodel.APIVersionProperty), + result.flattenedPropertyHandler, result.propertiesWithSameNameHandler, } @@ -98,7 +101,7 @@ func (builder *convertToARMBuilder) functionBodyStatements() []dst.Stmt { // but saves us some nil-checks result = append( result, - astbuilder.ReturnIfNil(dst.NewIdent(builder.receiverIdent), dst.NewIdent("nil"), dst.NewIdent("nil"))) + astbuilder.ReturnIfNil(dst.NewIdent(builder.receiverIdent), astbuilder.Nil(), astbuilder.Nil())) result = append(result, astbuilder.NewVariable(builder.resultIdent, builder.armTypeIdent)) // Each ARM object property needs to be filled out @@ -112,7 +115,7 @@ func (builder *convertToARMBuilder) functionBodyStatements() []dst.Stmt { returnStatement := &dst.ReturnStmt{ Results: []dst.Expr{ dst.NewIdent(builder.resultIdent), - dst.NewIdent("nil"), + astbuilder.Nil(), }, } result = append(result, returnStatement) @@ -135,8 +138,9 @@ func (builder *convertToARMBuilder) namePropertyHandler( // we do not read from AzureName() but instead use // the passed-in 'name' parameter which contains // a full name including any owners, etc - result := astbuilder.SimpleAssignment( - astbuilder.Selector(dst.NewIdent(builder.resultIdent), string(toProp.PropertyName())), + result := astbuilder.QualifiedAssignment( + dst.NewIdent(builder.resultIdent), + string(toProp.PropertyName()), token.ASSIGN, dst.NewIdent(nameParameterString)) @@ -184,6 +188,148 @@ func (builder *convertToARMBuilder) referencePropertyHandler( ) } +// flattenedPropertyHandler generates conversions for properties that +// were flattened out from inside other properties. The code it generates will +// look something like: +// +// If 'X' is a property that was flattened: +// +// armObj.X.Y1 = k8sObj.Y1; +// armObj.X.Y2 = k8sObj.Y2; +// +// in reality each assignment is likely to be another conversion that is specific +// to the type being converted. +func (builder *convertToARMBuilder) flattenedPropertyHandler( + toProp *astmodel.PropertyDefinition, + fromType *astmodel.ObjectType) []dst.Stmt { + + toPropName := toProp.PropertyName() + + // collect any fromProps that were flattened from the to-prop + var fromProps []*astmodel.PropertyDefinition + for _, prop := range fromType.Properties() { + if prop.WasFlattenedFrom(toPropName) { + fromProps = append(fromProps, prop) + } + } + + // there are none to copy; exit + if len(fromProps) == 0 { + return nil + } + + allTypes := builder.codeGenerationContext.GetAllReachableTypes() + + // the toProp shape here must be: + // 1. maybe a typename, pointing to… + // 2. maybe optional, wrapping … + // 3. maybe a typename, pointing to… + // 4. an object type + + // (1.) resolve the outer typename + toPropType, err := allTypes.FullyResolve(toProp.PropertyType()) + if err != nil { + panic(err) + } + + needToInitializeToProp := false // we need to init the target if it is optional + var toPropTypeName astmodel.TypeName + // (2.) resolve any optional type + if optType, ok := toPropType.(*astmodel.OptionalType); ok { + needToInitializeToProp = true + // (3.) resolve any inner typename + toPropTypeName = optType.Element().(astmodel.TypeName) + toPropType, err = allTypes.FullyResolve(optType.Element()) + if err != nil { + panic(err) + } + } + + // (4.) we have found the underlying object type + toPropObjType := toPropType.(*astmodel.ObjectType) + + // *** Now generate the code! *** + + // Build the initializer for the to-prop (if needed) + var result []dst.Stmt + if needToInitializeToProp { + result = []dst.Stmt{builder.buildToPropInitializer(fromProps, toPropTypeName, toPropName)} + } + + // Copy each from-prop into the to-prop + for _, fromProp := range fromProps { + // find the corresponding inner property on the to-prop type + toSubProp, ok := toPropObjType.Property(fromProp.PropertyName()) + if !ok { + panic(fmt.Sprintf("unable to find expected property %s inside property %s", fromProp.PropertyName(), toPropName)) + } + + // generate conversion + stmts := builder.typeConversionBuilder.BuildConversion( + astmodel.ConversionParameters{ + Source: astbuilder.Selector(dst.NewIdent(builder.receiverIdent), string(fromProp.PropertyName())), + SourceType: fromProp.PropertyType(), + Destination: astbuilder.Selector(dst.NewIdent(builder.resultIdent), string(toPropName), string(toSubProp.PropertyName())), + DestinationType: toSubProp.PropertyType(), + NameHint: string(toSubProp.PropertyName()), + ConversionContext: nil, + AssignmentHandler: nil, + Locals: builder.locals, + }) + + // we were unable to generate an inner conversion so we cannot generate the overall conversion + if len(stmts) == 0 { + return nil + } + + result = append(result, stmts...) + } + + return result +} + +// buildToPropInitializer builds an initializer for a given “to” property +// that assigns it a value if any of the “from” properties are not nil. +// +// Resultant code looks like: +// if (from1 != nil) || (from2 != nil) || … { +// . = &{} +// } +func (builder *convertToARMBuilder) buildToPropInitializer( + fromProps []*astmodel.PropertyDefinition, + toPropTypeName astmodel.TypeName, + toPropName astmodel.PropertyName) dst.Stmt { + + // build (x != nil, y != nil, …) + conds := make([]dst.Expr, 0, len(fromProps)) + for _, prop := range fromProps { + propSel := astbuilder.Selector(dst.NewIdent(builder.receiverIdent), string(prop.PropertyName())) + conds = append(conds, astbuilder.NotNil(propSel)) + } + + // build (x || y || …) + cond := astbuilder.JoinOr(conds...) + + // build if (conds…) { target.prop = &TargetType{} } + return &dst.IfStmt{ + Cond: cond, + Body: &dst.BlockStmt{ + List: []dst.Stmt{ + astbuilder.QualifiedAssignment( + dst.NewIdent(builder.resultIdent), + string(toPropName), + token.ASSIGN, + &dst.UnaryExpr{ + Op: token.AND, + X: &dst.CompositeLit{ + Type: toPropTypeName.AsType(builder.codeGenerationContext), + }, + }), + }, + }, + } +} + func (builder *convertToARMBuilder) fixedValuePropertyHandler(propertyName astmodel.PropertyName) propertyConversionHandler { return func(toProp *astmodel.PropertyDefinition, fromType *astmodel.ObjectType) []dst.Stmt { if toProp.PropertyName() != propertyName || !builder.isSpecType { @@ -212,8 +358,9 @@ func (builder *convertToARMBuilder) fixedValuePropertyHandler(propertyName astmo optionId := astmodel.GetEnumValueId(def.Name().Name(), enumType.Options()[0]) - result := astbuilder.SimpleAssignment( - astbuilder.Selector(dst.NewIdent(builder.resultIdent), string(toProp.PropertyName())), + result := astbuilder.QualifiedAssignment( + dst.NewIdent(builder.resultIdent), + string(toProp.PropertyName()), token.ASSIGN, dst.NewIdent(optionId)) @@ -274,7 +421,7 @@ func (builder *convertToARMBuilder) convertReferenceProperty(_ *astmodel.Convers "ARMIDOrErr", params.Source)) - returnIfNotNil := astbuilder.ReturnIfNotNil(dst.NewIdent("err"), dst.NewIdent("nil"), dst.NewIdent("err")) + returnIfNotNil := astbuilder.ReturnIfNotNil(dst.NewIdent("err"), astbuilder.Nil(), dst.NewIdent("err")) result := params.AssignmentHandlerOrDefault()(params.Destination, dst.NewIdent(localVarName)) @@ -351,7 +498,7 @@ func callToARMFunction(source dst.Expr, destination dst.Expr, methodName string) }, } results = append(results, propertyToARMInvocation) - results = append(results, astbuilder.CheckErrorAndReturn(dst.NewIdent("nil"))) + results = append(results, astbuilder.CheckErrorAndReturn(astbuilder.Nil())) return results } diff --git a/hack/generator/pkg/astmodel/armconversion/shared.go b/hack/generator/pkg/astmodel/armconversion/shared.go index 2ffa73bf2d7..ea43361c1c5 100644 --- a/hack/generator/pkg/astmodel/armconversion/shared.go +++ b/hack/generator/pkg/astmodel/armconversion/shared.go @@ -51,8 +51,10 @@ func (builder conversionBuilder) propertyConversionHandler( type propertyConversionHandler = func(toProp *astmodel.PropertyDefinition, fromType *astmodel.ObjectType) []dst.Stmt -var once sync.Once -var azureNameProperty *astmodel.PropertyDefinition +var ( + once sync.Once + azureNameProperty *astmodel.PropertyDefinition +) func initializeAzureName(idFactory astmodel.IdentifierFactory) { azureNameFieldDescription := "The name of the resource in Azure. This is often the same as" + @@ -94,14 +96,33 @@ func generateTypeConversionAssignments( var result []dst.Stmt for _, toField := range toType.Properties() { fieldConversionStmts := propertyHandler(toField, fromType) - result = append(result, fieldConversionStmts...) + if len(fieldConversionStmts) > 0 { + result = append(result, &dst.EmptyStmt{ + Decs: dst.EmptyStmtDecorations{ + NodeDecs: dst.NodeDecs{ + Before: dst.EmptyLine, + End: []string{fmt.Sprintf("// Set property ‘%s’:", toField.PropertyName())}, + }, + }, + }) + result = append(result, fieldConversionStmts...) + } else { + result = append(result, &dst.EmptyStmt{ + Decs: dst.EmptyStmtDecorations{ + NodeDecs: dst.NodeDecs{ + Before: dst.EmptyLine, + End: []string{fmt.Sprintf("// no assignment for property ‘%s’:", toField.PropertyName())}, + }, + }, + }) + } } return result } -// NewARMTransformerImpl creates a new interface with the specified ARM conversion functions -func NewARMTransformerImpl( +// NewARMConversionImplementation creates an interface implementation with the specified ARM conversion functions +func NewARMConversionImplementation( armTypeName astmodel.TypeName, armType *astmodel.ObjectType, idFactory astmodel.IdentifierFactory, @@ -139,7 +160,7 @@ func NewARMTransformerImpl( convertToARMFunc, populateFromARMFunc) } else { - // only convert in one direction with the FromARMConverter interface + // can only convert in one direction with the FromARMConverter interface return astmodel.NewInterfaceImplementation( astmodel.MakeTypeName(astmodel.GenRuntimeReference, "FromARMConverter"), createEmptyARMValueFunc, diff --git a/hack/generator/pkg/astmodel/array_type.go b/hack/generator/pkg/astmodel/array_type.go index 05aa6bf9113..b57be2e6585 100644 --- a/hack/generator/pkg/astmodel/array_type.go +++ b/hack/generator/pkg/astmodel/array_type.go @@ -10,6 +10,8 @@ import ( "strings" "github.com/dave/dst" + + "github.com/Azure/azure-service-operator/hack/generator/pkg/astbuilder" ) // ArrayType is used for properties that contain an array of values @@ -43,7 +45,7 @@ func (array *ArrayType) AsType(codeGenerationContext *CodeGenerationContext) dst // AsZero renders an expression for the "zero" value of the array by calling make() func (array *ArrayType) AsZero(_ Types, ctx *CodeGenerationContext) dst.Expr { - return dst.NewIdent("nil") + return astbuilder.Nil() } // RequiredPackageReferences returns a list of packages required by this diff --git a/hack/generator/pkg/astmodel/code_generation_context.go b/hack/generator/pkg/astmodel/code_generation_context.go index 49ce01a52d4..f8d98af8b12 100644 --- a/hack/generator/pkg/astmodel/code_generation_context.go +++ b/hack/generator/pkg/astmodel/code_generation_context.go @@ -142,7 +142,9 @@ func (codeGenContext *CodeGenerationContext) GetAllReachableTypes() Types { for _, pkgImport := range codeGenContext.packageImports.AsSlice() { types, found := codeGenContext.GetTypesInPackage(pkgImport.packageReference) if found { - result.AddTypes(types) + for k, v := range types { + result[k] = v + } } } diff --git a/hack/generator/pkg/astmodel/conversion_function_builder.go b/hack/generator/pkg/astmodel/conversion_function_builder.go index 17c26813ca4..b8d4f8222e9 100644 --- a/hack/generator/pkg/astmodel/conversion_function_builder.go +++ b/hack/generator/pkg/astmodel/conversion_function_builder.go @@ -139,6 +139,8 @@ func NewConversionFunctionBuilder(idFactory IdentifierFactory, codeGenerationCon IdentityAssignValidatedTypeDestination, IdentityAssignValidatedTypeSource, IdentityAssignPrimitiveType, + AssignToOptional, + AssignFromOptional, IdentityDeepCopyJSON, IdentityAssignTypeName, }, @@ -168,8 +170,8 @@ func (builder *ConversionFunctionBuilder) BuildConversion(params ConversionParam var sourceSB strings.Builder params.SourceType.WriteDebugDescription(&sourceSB, types) var destinationSB strings.Builder - params.SourceType.WriteDebugDescription(&destinationSB, types) - panic(fmt.Sprintf("don't know how to perform conversion for %T -> %T", sourceSB.String(), destinationSB.String())) + params.DestinationType.WriteDebugDescription(&destinationSB, types) + panic(fmt.Sprintf("don't know how to perform conversion for %s -> %s", sourceSB.String(), destinationSB.String())) } // IdentityConvertComplexOptionalProperty handles conversion for optional properties with complex elements @@ -212,11 +214,7 @@ func IdentityConvertComplexOptionalProperty(builder *ConversionFunctionBuilder, astbuilder.AddrOf(dst.NewIdent(tempVarIdent)))) result := &dst.IfStmt{ - Cond: &dst.BinaryExpr{ - X: params.GetSource(), - Op: token.NEQ, - Y: dst.NewIdent("nil"), - }, + Cond: astbuilder.NotNil(params.GetSource()), Body: &dst.BlockStmt{ List: innerStatements, }, @@ -231,7 +229,6 @@ func IdentityConvertComplexOptionalProperty(builder *ConversionFunctionBuilder, // = append(, ) // } func IdentityConvertComplexArrayProperty(builder *ConversionFunctionBuilder, params ConversionParameters) []dst.Stmt { - destinationType, ok := params.DestinationType.(*ArrayType) if !ok { return nil @@ -371,11 +368,7 @@ func IdentityConvertComplexMapProperty(builder *ConversionFunctionBuilder, param } result := &dst.IfStmt{ - Cond: &dst.BinaryExpr{ - X: params.GetSource(), - Op: token.NEQ, - Y: dst.NewIdent("nil"), - }, + Cond: astbuilder.NotNil(params.GetSource()), Body: &dst.BlockStmt{ List: []dst.Stmt{ makeMapStatement, @@ -437,6 +430,104 @@ func IdentityAssignPrimitiveType(_ *ConversionFunctionBuilder, params Conversion } } +// AssignToOptional assigns address of source to destination. +// This function generates code that looks like this, for simple conversions: +// & +// +// or: +// Temp := convert() +// &Temp +func AssignToOptional(builder *ConversionFunctionBuilder, params ConversionParameters) []dst.Stmt { + optDest, ok := params.DestinationType.(*OptionalType) + if !ok { + return nil + } + + if optDest.Element().Equals(params.SourceType) { + return []dst.Stmt{ + params.AssignmentHandlerOrDefault()(params.GetDestination(), &dst.UnaryExpr{Op: token.AND, X: params.GetSource()}), + } + } + + // a more complex conversion is needed + dstType := optDest.Element() + tmpLocal := builder.CreateLocal(params.Locals, "temp", params.NameHint) + + conversion := builder.BuildConversion( + ConversionParameters{ + Source: params.Source, + SourceType: params.SourceType, + Destination: dst.NewIdent(tmpLocal), + DestinationType: dstType, + NameHint: tmpLocal, + ConversionContext: nil, + AssignmentHandler: nil, + Locals: params.Locals, + }) + + if len(conversion) == 0 { + return nil // unable to build inner conversion + } + + var result []dst.Stmt + result = append(result, astbuilder.LocalVariableDeclaration(tmpLocal, dstType.AsType(builder.CodeGenerationContext), "")) + result = append(result, conversion...) + result = append(result, params.AssignmentHandlerOrDefault()(params.GetDestination(), &dst.UnaryExpr{Op: token.AND, X: dst.NewIdent(tmpLocal)})) + return result +} + +// AssignFromOptional assigns address of source to destination. +// This function generates code that looks like this, for simple conversions: +// if ( != nil) { +// * +// } +// +// or: +// if ( != nil) { +// Temp := convert(*) +// Temp +// } +func AssignFromOptional(builder *ConversionFunctionBuilder, params ConversionParameters) []dst.Stmt { + optSrc, ok := params.SourceType.(*OptionalType) + if !ok { + return nil + } + + if optSrc.Element().Equals(params.DestinationType) { + return []dst.Stmt{ + astbuilder.IfNotNil(params.GetSource(), + params.AssignmentHandlerOrDefault()(params.GetDestination(), &dst.UnaryExpr{Op: token.MUL, X: params.GetSource()}), + ), + } + } + + // a more complex conversion is needed + srcType := optSrc.Element() + tmpLocal := builder.CreateLocal(params.Locals, "temp", params.NameHint) + + conversion := builder.BuildConversion( + ConversionParameters{ + Source: &dst.UnaryExpr{Op: token.MUL, X: params.GetSource()}, + SourceType: srcType, + Destination: dst.NewIdent(tmpLocal), + DestinationType: params.DestinationType, + NameHint: tmpLocal, + ConversionContext: nil, + AssignmentHandler: nil, + Locals: params.Locals, + }) + + if len(conversion) == 0 { + return nil // unable to build inner conversion + } + + var result []dst.Stmt + result = append(result, astbuilder.LocalVariableDeclaration(tmpLocal, params.DestinationType.AsType(builder.CodeGenerationContext), "")) + result = append(result, conversion...) + result = append(result, params.AssignmentHandlerOrDefault()(params.GetDestination(), dst.NewIdent(tmpLocal))) + return result +} + // IdentityAssignValidatedTypeDestination generates an assignment to the underlying validated type Element func IdentityAssignValidatedTypeDestination(builder *ConversionFunctionBuilder, params ConversionParameters) []dst.Stmt { validatedType, ok := params.DestinationType.(*ValidatedType) @@ -465,7 +556,6 @@ func IdentityAssignValidatedTypeSource(builder *ConversionFunctionBuilder, param // It generates code that looks like: // = *.DeepCopy() func IdentityDeepCopyJSON(builder *ConversionFunctionBuilder, params ConversionParameters) []dst.Stmt { - if !params.DestinationType.Equals(JSONTypeName) { return nil } diff --git a/hack/generator/pkg/astmodel/kubernetes_admissions_validator.go b/hack/generator/pkg/astmodel/kubernetes_admissions_validator.go index c496aa7017d..5fcdf478380 100644 --- a/hack/generator/pkg/astmodel/kubernetes_admissions_validator.go +++ b/hack/generator/pkg/astmodel/kubernetes_admissions_validator.go @@ -15,8 +15,10 @@ import ( "github.com/Azure/azure-service-operator/hack/generator/pkg/astbuilder" ) -var ValidatorInterfaceName = MakeTypeName(ControllerRuntimeAdmission, "Validator") -var GenRuntimeValidatorInterfaceName = MakeTypeName(GenRuntimeReference, "Validator") +var ( + ValidatorInterfaceName = MakeTypeName(ControllerRuntimeAdmission, "Validator") + GenRuntimeValidatorInterfaceName = MakeTypeName(GenRuntimeReference, "Validator") +) // ValidationKind determines when a particular validation should be run type ValidationKind string @@ -365,7 +367,7 @@ func (v *ValidatorBuilder) localValidationFuncBody(kind ValidationKind, codeGene } if len(elements) == 0 { - return []dst.Stmt{astbuilder.Returns(dst.NewIdent("nil"))} + return []dst.Stmt{astbuilder.Returns(astbuilder.Nil())} } returnStmt := astbuilder.Returns(&dst.CompositeLit{ @@ -402,7 +404,7 @@ func (v *ValidatorBuilder) makeLocalValidationElement( return &dst.FuncLit{ Decs: dst.FuncLitDecorations{ NodeDecs: dst.NodeDecs{ - //Start: doc, + // Start: doc, Before: dst.NewLine, After: dst.NewLine, }, diff --git a/hack/generator/pkg/astmodel/kubernetes_resource_interface.go b/hack/generator/pkg/astmodel/kubernetes_resource_interface.go index 7f0cb716564..540874cc144 100644 --- a/hack/generator/pkg/astmodel/kubernetes_resource_interface.go +++ b/hack/generator/pkg/astmodel/kubernetes_resource_interface.go @@ -134,12 +134,12 @@ func getAzureNameFunctionsForType(r **ResourceType, spec *ObjectType, t Type, ty return fixedValueGetAzureNameFunction("default"), nil, nil // no SetAzureName for this case } else { // ignoring for now: - //return nil, errors.Errorf("unable to handle pattern in Name property: %s", validations.Pattern.String()) + // return nil, errors.Errorf("unable to handle pattern in Name property: %s", validations.Pattern.String()) return getStringAzureNameFunction, setStringAzureNameFunction, nil } } else { // ignoring length validations for now - //return nil, errors.Errorf("unable to handle validations on Name property …TODO") + // return nil, errors.Errorf("unable to handle validations on Name property …TODO") return getStringAzureNameFunction, setStringAzureNameFunction, nil } @@ -265,7 +265,6 @@ func setEnumAzureNameFunction(enumType TypeName) objectFunctionHandler { // fixedValueGetAzureNameFunction adds an AzureName() function that returns a fixed value func fixedValueGetAzureNameFunction(fixedValue string) objectFunctionHandler { - // ensure fixedValue is quoted. This is always the case with enum values we pass, // but let's be safe: if len(fixedValue) == 0 { @@ -314,7 +313,6 @@ func IsKubernetesResourceProperty(name PropertyName) bool { // ownerFunction returns a function that returns the owner of the resource func ownerFunction(k *objectFunction, codeGenerationContext *CodeGenerationContext, receiver TypeName, methodName string) *dst.FuncDecl { - receiverIdent := k.idFactory.CreateIdentifier(receiver.Name(), NotExported) fn := &astbuilder.FuncDetails{ @@ -444,11 +442,9 @@ func setStringAzureNameFunction(k *objectFunction, codeGenerationContext *CodeGe X: receiverType, }, Body: []dst.Stmt{ - astbuilder.SimpleAssignment( - &dst.SelectorExpr{ - X: dst.NewIdent(receiverIdent), - Sel: dst.NewIdent(AzureNameProperty), - }, + astbuilder.QualifiedAssignment( + dst.NewIdent(receiverIdent), + AzureNameProperty, token.ASSIGN, dst.NewIdent("azureName")), }, diff --git a/hack/generator/pkg/astmodel/map_type.go b/hack/generator/pkg/astmodel/map_type.go index c053a39468f..a9fc0532bad 100644 --- a/hack/generator/pkg/astmodel/map_type.go +++ b/hack/generator/pkg/astmodel/map_type.go @@ -10,6 +10,8 @@ import ( "strings" "github.com/dave/dst" + + "github.com/Azure/azure-service-operator/hack/generator/pkg/astbuilder" ) // MapType is used to define properties that contain additional property values @@ -55,7 +57,7 @@ func (m *MapType) AsType(codeGenerationContext *CodeGenerationContext) dst.Expr // AsZero renders an expression for the "zero" value of a map by calling make() func (m *MapType) AsZero(_ Types, ctx *CodeGenerationContext) dst.Expr { - return dst.NewIdent("nil") + return astbuilder.Nil() } // RequiredPackageReferences returns a list of packages required by this diff --git a/hack/generator/pkg/astmodel/object_type.go b/hack/generator/pkg/astmodel/object_type.go index f31fa8bc0bd..583905bdada 100644 --- a/hack/generator/pkg/astmodel/object_type.go +++ b/hack/generator/pkg/astmodel/object_type.go @@ -155,7 +155,7 @@ func (objectType *ObjectType) EmbeddedProperties() []*PropertyDefinition { // A sorted slice is returned to preserve immutability and provide determinism func (objectType *ObjectType) Functions() []Function { - var functions []Function + functions := make([]Function, 0, len(objectType.functions)) for _, f := range objectType.functions { functions = append(functions, f) } diff --git a/hack/generator/pkg/astmodel/one_of_json_marshal_function.go b/hack/generator/pkg/astmodel/one_of_json_marshal_function.go index aedc66c2c74..6925dd56352 100644 --- a/hack/generator/pkg/astmodel/one_of_json_marshal_function.go +++ b/hack/generator/pkg/astmodel/one_of_json_marshal_function.go @@ -7,10 +7,10 @@ package astmodel import ( "fmt" - "go/token" - "github.com/Azure/azure-service-operator/hack/generator/pkg/astbuilder" "github.com/dave/dst" + + "github.com/Azure/azure-service-operator/hack/generator/pkg/astbuilder" ) const JSONMarshalFunctionName string = "MarshalJSON" @@ -63,28 +63,22 @@ func (f *OneOfJSONMarshalFunction) AsFunc( for _, property := range f.oneOfObject.Properties() { ifStatement := dst.IfStmt{ - Cond: &dst.BinaryExpr{ - X: &dst.SelectorExpr{ - X: dst.NewIdent(receiverName), - Sel: dst.NewIdent(string(property.propertyName)), - }, - Op: token.NEQ, - Y: dst.NewIdent("nil"), - }, + Cond: astbuilder.NotNil( + astbuilder.Selector( + dst.NewIdent(receiverName), + string(property.propertyName))), Body: &dst.BlockStmt{ List: []dst.Stmt{ &dst.ReturnStmt{ Results: []dst.Expr{ &dst.CallExpr{ - Fun: &dst.SelectorExpr{ - X: dst.NewIdent(jsonPackage), - Sel: dst.NewIdent("Marshal"), - }, + Fun: astbuilder.Selector( + dst.NewIdent(jsonPackage), + "Marshal"), Args: []dst.Expr{ - &dst.SelectorExpr{ - X: dst.NewIdent(receiverName), - Sel: dst.NewIdent(string(property.propertyName)), - }, + astbuilder.Selector( + dst.NewIdent(receiverName), + string(property.propertyName)), }, }, }, @@ -97,10 +91,7 @@ func (f *OneOfJSONMarshalFunction) AsFunc( } finalReturnStatement := &dst.ReturnStmt{ - Results: []dst.Expr{ - dst.NewIdent("nil"), - dst.NewIdent("nil"), - }, + Results: []dst.Expr{astbuilder.Nil(), astbuilder.Nil()}, } statements = append(statements, finalReturnStatement) diff --git a/hack/generator/pkg/astmodel/optional_type.go b/hack/generator/pkg/astmodel/optional_type.go index 423a374fa9b..78d8590aa62 100644 --- a/hack/generator/pkg/astmodel/optional_type.go +++ b/hack/generator/pkg/astmodel/optional_type.go @@ -10,6 +10,8 @@ import ( "strings" "github.com/dave/dst" + + "github.com/Azure/azure-service-operator/hack/generator/pkg/astbuilder" ) // OptionalType is used for items that may or may not be present @@ -69,9 +71,7 @@ func (optional *OptionalType) AsType(codeGenerationContext *CodeGenerationContex // AsZero renders an expression for the "zero" value of the type // by returning a literal "nil" func (optional *OptionalType) AsZero(_ Types, _ *CodeGenerationContext) dst.Expr { - return &dst.BasicLit{ - Value: "nil", - } + return astbuilder.Nil() } // RequiredPackageReferences returns the imports required by the 'element' type diff --git a/hack/generator/pkg/astmodel/package_definition.go b/hack/generator/pkg/astmodel/package_definition.go index 39f841a2188..49ef65fec2a 100644 --- a/hack/generator/pkg/astmodel/package_definition.go +++ b/hack/generator/pkg/astmodel/package_definition.go @@ -42,7 +42,7 @@ func (p *PackageDefinition) GetDefinition(typeName TypeName) (TypeDefinition, er } } - return TypeDefinition{}, errors.Errorf("No error with name %v found", typeName) + return TypeDefinition{}, errors.Errorf("no error with name %v found", typeName) } // AddDefinition adds a Definition to the PackageDefinition @@ -52,11 +52,9 @@ func (p *PackageDefinition) AddDefinition(def TypeDefinition) { // EmitDefinitions emits the PackageDefinition to an output directory func (p *PackageDefinition) EmitDefinitions(outputDir string, generatedPackages map[PackageReference]*PackageDefinition) (int, error) { - filesToGenerate := allocateTypesToFiles(p.definitions) err := p.emitFiles(filesToGenerate, outputDir, generatedPackages) - if err != nil { return 0, err } diff --git a/hack/generator/pkg/astmodel/property_definition.go b/hack/generator/pkg/astmodel/property_definition.go index 89af81f7f64..de4eea61eff 100644 --- a/hack/generator/pkg/astmodel/property_definition.go +++ b/hack/generator/pkg/astmodel/property_definition.go @@ -18,13 +18,47 @@ import ( // PropertyName is a semantic type type PropertyName string +// Implement Stringer for easy fmt printing +func (pn PropertyName) String() string { + return string(pn) +} + // PropertyDefinition encapsulates the definition of a property type PropertyDefinition struct { propertyName PropertyName propertyType Type description string hasKubebuilderRequiredValidation bool - tags map[string][]string + + // Two properties to handle flattening: + // - flatten is set when a property should be flattened and its inner properties + // moved out into the parent object. + // - flattenedFrom is set once an ‘inner’ property has been flattened, to record + // which property(/ies) (that had flatten:true) it was flattened from. this + // is stored with most-recent first so that `[0].[1].[2]` would form the + // correct nested property name. + flatten bool // maps to x-ms-client-flatten: should the propertyType be flattened into the parent? + flattenedFrom []PropertyName // a list of property names from whence this property was flattened + + tags map[string][]string +} + +func (property *PropertyDefinition) AddFlattenedFrom(name PropertyName) *PropertyDefinition { + result := *property + result.flattenedFrom = append([]PropertyName{name}, result.flattenedFrom...) + return &result +} + +func (property *PropertyDefinition) WasFlattened() bool { + return len(property.flattenedFrom) > 0 +} + +func (property *PropertyDefinition) WasFlattenedFrom(name PropertyName) bool { + return property.WasFlattened() && property.flattenedFrom[0] == name +} + +func (property *PropertyDefinition) FlattenedFrom() []PropertyName { + return append([]PropertyName{}, property.flattenedFrom...) } var _ fmt.Stringer = &PropertyDefinition{} @@ -58,11 +92,26 @@ func (property *PropertyDefinition) PropertyType() Type { // Note that this does not in any way change the underlying type that this PropertyDefinition points to, unlike // MakeRequired and MakeOptional. func (property *PropertyDefinition) WithKubebuilderRequiredValidation(required bool) *PropertyDefinition { + if required == property.hasKubebuilderRequiredValidation { + return property + } + result := *property result.hasKubebuilderRequiredValidation = required return &result } +// SetFlatten sets if the property should be flattened or not +func (property *PropertyDefinition) SetFlatten(flatten bool) *PropertyDefinition { + if flatten == property.flatten { + return property + } + + result := *property + result.flatten = flatten + return &result +} + // WithDescription returns a new PropertyDefinition with the specified description func (property *PropertyDefinition) WithDescription(description string) *PropertyDefinition { if description == property.description { @@ -81,6 +130,9 @@ func (property *PropertyDefinition) Description() string { // WithType clones the property and returns it with a new type func (property *PropertyDefinition) WithType(newType Type) *PropertyDefinition { + if newType == nil { + panic("nil type provided to WithType") + } if property.propertyType.Equals(newType) { return property @@ -118,7 +170,7 @@ func (property *PropertyDefinition) WithoutTag(key string, value string) *Proper if value != "" { // Find the value and remove it - //TODO: Do we want a generic helper that does this? + // TODO: Do we want a generic helper that does this? var tagsWithoutValue []string for _, item := range result.tags[key] { if item == value { @@ -224,6 +276,11 @@ func (property *PropertyDefinition) HasKubebuilderRequiredValidation() bool { return property.hasKubebuilderRequiredValidation } +// Flatten returns true iff the property is marked with 'flatten'. +func (property *PropertyDefinition) Flatten() bool { + return property.flatten +} + // hasOptionalType returns true if the type of this property is an optional reference to a value // (and might therefore be nil). func (property *PropertyDefinition) hasOptionalType() bool { diff --git a/hack/generator/pkg/astmodel/property_definition_test.go b/hack/generator/pkg/astmodel/property_definition_test.go index 48213e72b0f..72e20dad3df 100644 --- a/hack/generator/pkg/astmodel/property_definition_test.go +++ b/hack/generator/pkg/astmodel/property_definition_test.go @@ -520,3 +520,31 @@ func TestPropertyDefinition_Equals_WhenGivenPropertyDefinition_ReturnsExpectedRe }) } } + +func TestSettingSameRequiredValueDoesNotAllocateNewPropertyDefinition(t *testing.T) { + g := NewGomegaWithT(t) + + strProperty := createStringProperty("FullName", "Full Legal Name") + strPropertyRequired := strProperty.WithKubebuilderRequiredValidation(true) + + // safety check + g.Expect(strProperty).ToNot(Equal(strPropertyRequired)) + + // actual asserts + g.Expect(strProperty.WithKubebuilderRequiredValidation(false)).To(BeIdenticalTo(strProperty)) + g.Expect(strPropertyRequired.WithKubebuilderRequiredValidation(true)).To(BeIdenticalTo(strPropertyRequired)) +} + +func TestSettingSameFlattenValueDoesNotAllocateNewPropertyDefinition(t *testing.T) { + g := NewGomegaWithT(t) + + strProperty := createStringProperty("FullName", "Full Legal Name") + strPropertyFlatten := strProperty.SetFlatten(true) + + // safety check + g.Expect(strProperty).ToNot(Equal(strPropertyFlatten)) + + // actual asserts + g.Expect(strProperty.SetFlatten(false)).To(BeIdenticalTo(strProperty)) + g.Expect(strPropertyFlatten.SetFlatten(true)).To(BeIdenticalTo(strPropertyFlatten)) +} diff --git a/hack/generator/pkg/astmodel/reference_graph.go b/hack/generator/pkg/astmodel/reference_graph.go index 464c3ca6f91..1a29673a084 100644 --- a/hack/generator/pkg/astmodel/reference_graph.go +++ b/hack/generator/pkg/astmodel/reference_graph.go @@ -33,13 +33,13 @@ func CollectARMSpecAndStatusDefinitions(definitions Types) TypeNameSet { findARMType := func(t Type) (TypeName, error) { name, ok := t.(TypeName) if !ok { - return TypeName{}, errors.Errorf("Type was not of type TypeName, instead %T", t) + return TypeName{}, errors.Errorf("type was not of type TypeName, instead %T", t) } armName := CreateARMTypeName(name) if _, ok = definitions[armName]; !ok { - return TypeName{}, errors.Errorf("Couldn't find ARM type %q", armName) + return TypeName{}, errors.Errorf("couldn't find ARM type %q", armName) } return armName, nil @@ -47,7 +47,6 @@ func CollectARMSpecAndStatusDefinitions(definitions Types) TypeNameSet { armSpecAndStatus := make(TypeNameSet) for _, def := range definitions { - if resourceType, ok := definitions.ResolveResourceType(def.Type()); ok { armSpecName, err := findARMType(resourceType.spec) diff --git a/hack/generator/pkg/astmodel/types.go b/hack/generator/pkg/astmodel/types.go index 8f3766ba92f..17c22b9a286 100644 --- a/hack/generator/pkg/astmodel/types.go +++ b/hack/generator/pkg/astmodel/types.go @@ -14,6 +14,23 @@ import ( // Types is a map of TypeName to TypeDefinition, representing a set of types. type Types map[TypeName]TypeDefinition +// A restricted interface to indicate that the +// consumer won’t modify the contained types. +type ReadonlyTypes interface { + FullyResolve(t Type) (Type, error) + Get(t TypeName) TypeDefinition + TryGet(t TypeName) (TypeDefinition, bool) +} + +func (types Types) Get(t TypeName) TypeDefinition { + return types[t] +} + +func (types Types) TryGet(t TypeName) (TypeDefinition, bool) { + result, ok := types[t] + return result, ok +} + // Add adds a type to the set, with safety check that it has not already been defined func (types Types) Add(def TypeDefinition) { key := def.Name() diff --git a/hack/generator/pkg/codegen/code_generator.go b/hack/generator/pkg/codegen/code_generator.go index 71f8c3f24f2..ca68a5f71d2 100644 --- a/hack/generator/pkg/codegen/code_generator.go +++ b/hack/generator/pkg/codegen/code_generator.go @@ -83,7 +83,7 @@ func createAllPipelineStages(idFactory astmodel.IdentifierFactory, configuration pipeline.LoadSchemaIntoTypes(idFactory, configuration, pipeline.DefaultSchemaLoader), // Import status info from Swagger: - pipeline.AugmentResourcesWithStatus(idFactory, configuration), + pipeline.AddStatusFromSwagger(idFactory, configuration), // Reduces oneOf/allOf types from schemas to object types: pipeline.ConvertAllOfAndOneOfToObjects(idFactory), @@ -92,6 +92,9 @@ func createAllPipelineStages(idFactory astmodel.IdentifierFactory, configuration // get named with names like Resource_Spec_Spec_Spec: pipeline.FlattenResources(), + // Copy additional swagger-derived information from status into spec + pipeline.AugmentSpecWithStatus().RequiresPrerequisiteStages("allof-anyof-objects", "addStatusFromSwagger"), + pipeline.StripUnreferencedTypeDefinitions(), // Name all anonymous object, enum, and validated types (required by controller-gen): @@ -139,6 +142,9 @@ func createAllPipelineStages(idFactory astmodel.IdentifierFactory, configuration pipeline.ApplyARMConversionInterface(idFactory).UsedFor(pipeline.ARMTarget), pipeline.ApplyKubernetesResourceInterface(idFactory).UsedFor(pipeline.ARMTarget), + // Effects the "flatten" property of Properties: + pipeline.FlattenProperties(), + pipeline.AddCrossplaneOwnerProperties(idFactory).UsedFor(pipeline.CrossplaneTarget), pipeline.AddCrossplaneForProvider(idFactory).UsedFor(pipeline.CrossplaneTarget), pipeline.AddCrossplaneAtProvider(idFactory).UsedFor(pipeline.CrossplaneTarget), diff --git a/hack/generator/pkg/codegen/golden_files_test.go b/hack/generator/pkg/codegen/golden_files_test.go index d44fc46d58e..feba1587be7 100644 --- a/hack/generator/pkg/codegen/golden_files_test.go +++ b/hack/generator/pkg/codegen/golden_files_test.go @@ -76,7 +76,6 @@ func injectEmbeddedStructType() pipeline.Stage { "injectEmbeddedStructType", "Injects an embedded struct into each object", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { - results := make(astmodel.Types) embeddedTypeDef := makeEmbeddedTestTypeDefinition() for _, def := range defs { @@ -104,6 +103,8 @@ func injectEmbeddedStructType() pipeline.Stage { } func runGoldenTest(t *testing.T, path string, testConfig GoldenTestConfig) { + ctx := context.Background() + for _, p := range testConfig.Pipelines { testName := strings.TrimPrefix(t.Name(), "TestGolden/") @@ -118,7 +119,7 @@ func runGoldenTest(t *testing.T, path string, testConfig GoldenTestConfig) { t.Fatalf("failed to create code generator: %v", err) } - err = codegen.Generate(context.TODO()) + err = codegen.Generate(ctx) if err != nil { t.Fatalf("codegen failed: %v", err) } @@ -197,7 +198,6 @@ func loadTestSchemaIntoTypes( loader := gojsonschema.NewSchemaLoader() schema, err := loader.Compile(gojsonschema.NewBytesLoader(inputFile)) - if err != nil { return nil, errors.Wrapf(err, "could not compile input") } @@ -316,7 +316,6 @@ func addCrossResourceReferencesForTest(idFactory astmodel.IdentifierFactory) pip } func TestGolden(t *testing.T) { - type Test struct { name string path string @@ -335,7 +334,6 @@ func TestGolden(t *testing.T) { return nil }) - if err != nil { t.Fatalf("Error enumerating files: %v", err) } diff --git a/hack/generator/pkg/codegen/pipeline/add_arm_conversion_interface.go b/hack/generator/pkg/codegen/pipeline/add_arm_conversion_interface.go index 0623599ca84..c0b9c1612dd 100644 --- a/hack/generator/pkg/codegen/pipeline/add_arm_conversion_interface.go +++ b/hack/generator/pkg/codegen/pipeline/add_arm_conversion_interface.go @@ -119,7 +119,6 @@ func (c *armConversionApplier) transformResourceStatuses() (astmodel.Types, erro // transformTypes adds the required ARM conversion information to all applicable types. // If a type doesn't need any modification, it is returned unmodified. func (c *armConversionApplier) transformTypes() (astmodel.Types, error) { - result := make(astmodel.Types) // Specs @@ -167,7 +166,6 @@ func (c *armConversionApplier) transformTypes() (astmodel.Types, error) { // transformSpec adds an owner property to the given resource spec, and adds the ARM conversion interface // to the spec with some special property remappings (for Type, Name, APIVersion, etc). func (c *armConversionApplier) transformSpec(resourceType *astmodel.ResourceType) (astmodel.TypeDefinition, error) { - resourceSpecDef, err := c.definitions.ResolveResourceSpecDefinition(resourceType) if err != nil { return astmodel.TypeDefinition{}, err @@ -226,7 +224,7 @@ func (c *armConversionApplier) addARMConversionInterface( } addInterfaceHandler := func(t *astmodel.ObjectType) (astmodel.Type, error) { - result := t.WithInterface(armconversion.NewARMTransformerImpl( + result := t.WithInterface(armconversion.NewARMConversionImplementation( armDef.Name(), objectType, c.idFactory, @@ -238,14 +236,13 @@ func (c *armConversionApplier) addARMConversionInterface( if err != nil { emptyDef := astmodel.TypeDefinition{} return emptyDef, - errors.Errorf("Failed to add ARM conversion interface to Kubenetes object definition %v", armDef.Name()) + errors.Errorf("failed to add ARM conversion interface to Kubenetes object definition %v", armDef.Name()) } return result, nil } func (c *armConversionApplier) createOwnerProperty(ownerTypeName *astmodel.TypeName) (*astmodel.PropertyDefinition, error) { - knownResourceReferenceType := astmodel.MakeTypeName( astmodel.GenRuntimeReference, "KnownResourceReference") diff --git a/hack/generator/pkg/codegen/pipeline/create_arm_types.go b/hack/generator/pkg/codegen/pipeline/create_arm_types.go index 43d0ef5a828..90119c147c7 100644 --- a/hack/generator/pkg/codegen/pipeline/create_arm_types.go +++ b/hack/generator/pkg/codegen/pipeline/create_arm_types.go @@ -22,10 +22,8 @@ func CreateARMTypes(idFactory astmodel.IdentifierFactory) Stage { "createArmTypes", "Create types for interaction with ARM", func(ctx context.Context, definitions astmodel.Types) (astmodel.Types, error) { - armTypeCreator := &armTypeCreator{definitions: definitions, idFactory: idFactory} armTypes, err := armTypeCreator.createARMTypes() - if err != nil { return nil, err } @@ -57,7 +55,6 @@ func getAllSpecDefinitions(definitions astmodel.Types) (astmodel.Types, error) { } func (c *armTypeCreator) createARMTypes() (astmodel.Types, error) { - result := make(astmodel.Types) resourceSpecDefs, err := getAllSpecDefinitions(c.definitions) if err != nil { @@ -144,8 +141,8 @@ func removeValidations(t *astmodel.ObjectType) (*astmodel.ObjectType, error) { } func (c *armTypeCreator) createARMTypeDefinition(isSpecType bool, def astmodel.TypeDefinition) (astmodel.TypeDefinition, error) { - convertPropertiesToARMTypesWrapper := func(t *astmodel.ObjectType) (*astmodel.ObjectType, error) { - return c.convertPropertiesToARMTypes(t, isSpecType) + convertObjectPropertiesForARM := func(t *astmodel.ObjectType) (*astmodel.ObjectType, error) { + return c.convertObjectPropertiesForARM(t, isSpecType) } addOneOfConversionFunctionIfNeeded := func(t *astmodel.ObjectType) (*astmodel.ObjectType, error) { @@ -158,7 +155,7 @@ func (c *armTypeCreator) createARMTypeDefinition(isSpecType bool, def astmodel.T } armName := astmodel.CreateARMTypeName(def.Name()) - armDef, err := def.WithName(armName).ApplyObjectTransformations(removeValidations, convertPropertiesToARMTypesWrapper, addOneOfConversionFunctionIfNeeded) + armDef, err := def.WithName(armName).ApplyObjectTransformations(removeValidations, convertObjectPropertiesForARM, addOneOfConversionFunctionIfNeeded) if err != nil { return astmodel.TypeDefinition{}, errors.Wrapf(err, "creating ARM prototype %v from Kubernetes definition %v", armName, def.Name()) @@ -176,7 +173,6 @@ func (c *armTypeCreator) createARMTypeDefinition(isSpecType bool, def astmodel.T } func (c *armTypeCreator) convertARMPropertyTypeIfNeeded(t astmodel.Type) (astmodel.Type, error) { - createArmTypeName := func(this *astmodel.TypeVisitor, it astmodel.TypeName, ctx interface{}) (astmodel.Type, error) { // Allow json type to pass through. if it == astmodel.JSONTypeName { @@ -185,7 +181,7 @@ func (c *armTypeCreator) convertARMPropertyTypeIfNeeded(t astmodel.Type) (astmod def, ok := c.definitions[it] if !ok { - return nil, errors.Errorf("Failed to lookup %v", it) + return nil, errors.Errorf("failed to lookup %v", it) } if _, ok := def.Type().(*astmodel.ObjectType); ok { @@ -213,7 +209,9 @@ func (c *armTypeCreator) convertARMPropertyTypeIfNeeded(t astmodel.Type) (astmod return visitor.Visit(t, nil) } -func (c *armTypeCreator) convertPropertiesToARMTypes(t *astmodel.ObjectType, isSpecType bool) (*astmodel.ObjectType, error) { +// convertObjectPropertiesForARM returns the given object type with +// any properties updated that need to be changed for ARM +func (c *armTypeCreator) convertObjectPropertiesForARM(t *astmodel.ObjectType, isSpecType bool) (*astmodel.ObjectType, error) { result := t var errs []error @@ -255,15 +253,13 @@ func (c *armTypeCreator) convertPropertiesToARMTypes(t *astmodel.ObjectType, isS } result = result.WithProperty(newProp) - } else { - propType := prop.PropertyType() - newType, err := c.convertARMPropertyTypeIfNeeded(propType) + newType, err := c.convertARMPropertyTypeIfNeeded(prop.PropertyType()) + if err != nil { errs = append(errs, err) - } else if newType != propType { - newProp := prop.WithType(newType) - result = result.WithProperty(newProp) + } else { + result = result.WithProperty(prop.WithType(newType)) } } } diff --git a/hack/generator/pkg/codegen/pipeline/flatten_properties.go b/hack/generator/pkg/codegen/pipeline/flatten_properties.go new file mode 100644 index 00000000000..4a8da5302c8 --- /dev/null +++ b/hack/generator/pkg/codegen/pipeline/flatten_properties.go @@ -0,0 +1,146 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +package pipeline + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/Azure/azure-service-operator/hack/generator/pkg/astmodel" +) + +func FlattenProperties() Stage { + return MakeStage("flattenProperties", "Apply flattening to properties marked for flattening", applyPropertyFlattening) +} + +func applyPropertyFlattening( + ctx context.Context, + defs astmodel.Types) (astmodel.Types, error) { + visitor := makeFlatteningVisitor(defs) + + result := make(astmodel.Types) + for name, def := range defs { + newDef, err := visitor.VisitDefinition(def, name) + if err != nil { + return nil, err + } + + result.Add(newDef) + } + + return result, nil +} + +func makeFlatteningVisitor(defs astmodel.Types) astmodel.TypeVisitor { + return astmodel.TypeVisitorBuilder{ + VisitObjectType: func(this *astmodel.TypeVisitor, it *astmodel.ObjectType, ctx interface{}) (astmodel.Type, error) { + newIt, err := astmodel.IdentityVisitOfObjectType(this, it, ctx) + if err != nil { + return nil, err + } + + it = newIt.(*astmodel.ObjectType) + + newProps, err := collectAndFlattenProperties(it, defs) + if err != nil { + return nil, err + } + + // safety check: + if err := checkForDuplicateNames(newProps); err != nil { + return nil, err + } + + result := it.WithoutProperties().WithProperties(newProps...) + + return result, nil + }, + VisitFlaggedType: func(this *astmodel.TypeVisitor, it *astmodel.FlaggedType, ctx interface{}) (astmodel.Type, error) { + // skip ARM types, do not flatten + if it.HasFlag(astmodel.ARMFlag) { + return it, nil + } + + return astmodel.IdentityVisitOfFlaggedType(this, it, ctx) + }, + }.Build() +} + +func checkForDuplicateNames(props []*astmodel.PropertyDefinition) error { + names := make(map[astmodel.PropertyName]struct{}) + for _, p := range props { + if _, ok := names[p.PropertyName()]; ok { + return errors.Errorf("flattening caused duplicate property name %q", p.PropertyName()) + } + + names[p.PropertyName()] = struct{}{} + } + + return nil +} + +// collectAndFlattenProperties walks the object type and extracts all properties, flattening any properties that require flattening +func collectAndFlattenProperties(objectType *astmodel.ObjectType, defs astmodel.Types) ([]*astmodel.PropertyDefinition, error) { + var flattenedProps []*astmodel.PropertyDefinition + + props := objectType.Properties() + for _, prop := range props { + if prop.Flatten() { + innerProps, err := flattenPropType(prop.PropertyType(), defs) + if err != nil { + return nil, err + } + + for _, innerProp := range innerProps { + flattenedProps = append(flattenedProps, innerProp.AddFlattenedFrom(prop.PropertyName())) + } + } else { + flattenedProps = append(flattenedProps, prop) + } + } + + return flattenedProps, nil +} + +// flattenPropType is invoked on a property marked for flattening to collect all inner properties +func flattenPropType(propType astmodel.Type, defs astmodel.Types) ([]*astmodel.PropertyDefinition, error) { + switch propType := propType.(type) { + // "base case" + case *astmodel.ObjectType: + return collectAndFlattenProperties(propType, defs) + + // typename must be resolved + case astmodel.TypeName: + resolved, err := defs.FullyResolve(propType) + if err != nil { + return nil, err + } + + props, err := flattenPropType(resolved, defs) + if err != nil { + return nil, err + } + + return props, nil + + // flattening something that is optional makes everything inside it optional + case *astmodel.OptionalType: + innerProps, err := flattenPropType(propType.Element(), defs) + if err != nil { + return nil, err + } + + for ix := range innerProps { + innerProps[ix] = innerProps[ix].MakeOptional() + } + + return innerProps, nil + + default: + return nil, errors.Errorf("flatten applied to non-object type: %s", propType.String()) + } +} diff --git a/hack/generator/pkg/codegen/pipeline/flatten_properties_test.go b/hack/generator/pkg/codegen/pipeline/flatten_properties_test.go new file mode 100644 index 00000000000..3ca289ac32e --- /dev/null +++ b/hack/generator/pkg/codegen/pipeline/flatten_properties_test.go @@ -0,0 +1,77 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +package pipeline + +import ( + "context" + "testing" + + . "github.com/onsi/gomega" + + "github.com/Azure/azure-service-operator/hack/generator/pkg/astmodel" +) + +var placeholderPackage = astmodel.MakeLocalPackageReference("prefix", "group", "version") + +func TestDuplicateNamesAreCaught(t *testing.T) { + g := NewGomegaWithT(t) + + prop := astmodel.NewPropertyDefinition("duplicate", "dupe", astmodel.StringType) + + innerObj := astmodel.NewObjectType().WithProperties(prop) + innerObjProp := astmodel.NewPropertyDefinition("inner", "inner", innerObj).SetFlatten(true) + + objType := astmodel.NewObjectType().WithProperties(prop, innerObjProp) + + types := make(astmodel.Types) + types.Add(astmodel.MakeTypeDefinition(astmodel.MakeTypeName(placeholderPackage, "objType"), objType)) + + result, err := applyPropertyFlattening(context.Background(), types) + g.Expect(result).To(BeNil()) + g.Expect(err).To(MatchError("visit of type of \"prefix/group/version/objType\" failed: flattening caused duplicate property name \"duplicate\"")) +} + +func TestFlatteningWorks(t *testing.T) { + g := NewGomegaWithT(t) + + inner2Obj := astmodel.NewObjectType().WithProperties( + astmodel.NewPropertyDefinition("x", "x", astmodel.StringType)) + + innerObj := astmodel.NewObjectType().WithProperties( + astmodel.NewPropertyDefinition("inner2", "inner2", inner2Obj).SetFlatten(true), + astmodel.NewPropertyDefinition("y", "y", astmodel.IntType)) + + objType := astmodel.NewObjectType().WithProperties( + astmodel.NewPropertyDefinition("inner", "inner", innerObj).SetFlatten(true), + astmodel.NewPropertyDefinition("z", "z", astmodel.IntType)) + + types := make(astmodel.Types) + types.Add(astmodel.MakeTypeDefinition(astmodel.MakeTypeName(placeholderPackage, "objType"), objType)) + + result, err := applyPropertyFlattening(context.Background(), types) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(result).To(HaveLen(1)) + + var it astmodel.Type + for _, single := range result { + it = single.Type() + break + } + + ot := it.(*astmodel.ObjectType) + g.Expect(ot.Properties()).To(HaveLen(3)) + + xProp, ok := ot.Property("x") + g.Expect(ok).To(BeTrue()) + yProp, ok := ot.Property("y") + g.Expect(ok).To(BeTrue()) + zProp, ok := ot.Property("z") + g.Expect(ok).To(BeTrue()) + + g.Expect(xProp.FlattenedFrom()).To(Equal([]astmodel.PropertyName{"inner", "inner2"})) + g.Expect(yProp.FlattenedFrom()).To(Equal([]astmodel.PropertyName{"inner"})) + g.Expect(zProp.FlattenedFrom()).To(Equal([]astmodel.PropertyName{})) +} diff --git a/hack/generator/pkg/codegen/pipeline/flatten_resources.go b/hack/generator/pkg/codegen/pipeline/flatten_resources.go index a60fad88c4f..973596b2674 100644 --- a/hack/generator/pkg/codegen/pipeline/flatten_resources.go +++ b/hack/generator/pkg/codegen/pipeline/flatten_resources.go @@ -19,7 +19,6 @@ func FlattenResources() Stage { "flattenResources", "Flatten nested resource types", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { - flattenEachResource := func(this *astmodel.TypeVisitor, it *astmodel.ResourceType, ctx interface{}) (astmodel.Type, error) { // visit inner types: visited, err := astmodel.IdentityVisitOfResourceType(this, it, ctx) diff --git a/hack/generator/pkg/codegen/pipeline/status_augment.go b/hack/generator/pkg/codegen/pipeline/status_augment.go new file mode 100644 index 00000000000..6888004ea93 --- /dev/null +++ b/hack/generator/pkg/codegen/pipeline/status_augment.go @@ -0,0 +1,130 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +package pipeline + +import ( + "context" + + "github.com/Azure/azure-service-operator/hack/generator/pkg/astmodel" +) + +func AugmentSpecWithStatus() Stage { + return MakeStage( + "augmentSpecWithStatus", + "Merges information from Status into Spec", + func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { + // build the augmenter we will use: + augmenter := fuseAugmenters( + flattenAugmenter(types), + ) + + newTypes := make(astmodel.Types) + + for _, typeDef := range types { + if resource, ok := typeDef.Type().(*astmodel.ResourceType); ok { + // augment spec with any bits needed from status + newSpec, err := augmenter(resource.SpecType(), resource.StatusType()) + if err != nil { + return nil, err + } + + newTypes.Add(typeDef.WithType(resource.WithSpec(newSpec))) + } else { + newTypes.Add(typeDef) + } + } + + return newTypes, nil + }) +} + +// an augmenter adds information from the Swagger-derived type to +// the main JSON schema-derived type, and returns the new type +type augmenter func(main astmodel.Type, swagger astmodel.Type) (astmodel.Type, error) + +// fuseAugmenters merges multiple augments into one by applying each +// augmenter in order to the result of the previous augmenter +func fuseAugmenters(augments ...augmenter) augmenter { + return func(main astmodel.Type, swagger astmodel.Type) (astmodel.Type, error) { + var err error + for _, augment := range augments { + main, err = augment(main, swagger) + if err != nil { + return nil, err + } + } + + return main, nil + } +} + +// flattenAugmenter copies across the "flatten" property from Swagger +func flattenAugmenter(allTypes astmodel.ReadonlyTypes) augmenter { + return func(main astmodel.Type, swagger astmodel.Type) (astmodel.Type, error) { + merger := astmodel.NewTypeMerger(func(ctx interface{}, left, right astmodel.Type) (astmodel.Type, error) { + // as a fallback, return left (= main) if we have nothing else to do + return left, nil + }) + + merger.Add(func(main, swagger astmodel.TypeName) (astmodel.Type, error) { + // when we merge two typenames we know that (structurally) they must + // be the ‘same’ type, even if they have different names + + // this allows us to handle cases where names differ greatly from JSON schema to Swagger, + // we rely on the structure of the types to tell us which types are the same + + newType, err := merger.Merge(allTypes.Get(main).Type(), allTypes.Get(swagger).Type()) + if err != nil { + return nil, err + } + + return newType, nil + }) + + // need to resolve main type + merger.Add(func(main astmodel.TypeName, swagger astmodel.Type) (astmodel.Type, error) { + newMain, err := merger.Merge(allTypes.Get(main).Type(), swagger) + if err != nil { + return nil, err + } + + return newMain, nil + }) + + // need to resolve swagger type + merger.Add(func(main astmodel.Type, swagger astmodel.TypeName) (astmodel.Type, error) { + result, err := merger.Merge(main, allTypes.Get(swagger).Type()) + if err != nil { + return nil, err + } + + return result, nil + }) + + merger.Add(func(main, swagger *astmodel.ObjectType) (astmodel.Type, error) { + props := main.Properties() + for ix, mainProp := range props { + // find a matching property in the swagger spec + if swaggerProp, ok := swagger.Property(mainProp.PropertyName()); ok { + // first copy over flatten property + mainProp = mainProp.SetFlatten(swaggerProp.Flatten()) + + // now recursively merge property types + newType, err := merger.Merge(mainProp.PropertyType(), swaggerProp.PropertyType()) + if err != nil { + return nil, err + } + + props[ix] = mainProp.WithType(newType) + } + } + + return main.WithProperties(props...), nil + }) + + return merger.Merge(main, swagger) + } +} diff --git a/hack/generator/pkg/codegen/pipeline/augment_status.go b/hack/generator/pkg/codegen/pipeline/status_from_swagger.go similarity index 77% rename from hack/generator/pkg/codegen/pipeline/augment_status.go rename to hack/generator/pkg/codegen/pipeline/status_from_swagger.go index ff843e58193..aab3654a490 100644 --- a/hack/generator/pkg/codegen/pipeline/augment_status.go +++ b/hack/generator/pkg/codegen/pipeline/status_from_swagger.go @@ -16,11 +16,10 @@ import ( "strings" "sync" - kerrors "k8s.io/apimachinery/pkg/util/errors" - "github.com/go-openapi/spec" "github.com/pkg/errors" "golang.org/x/sync/errgroup" + kerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/klog/v2" "github.com/Azure/azure-service-operator/hack/generator/pkg/astmodel" @@ -28,7 +27,7 @@ import ( "github.com/Azure/azure-service-operator/hack/generator/pkg/jsonast" ) -/* AugmentResourcesWithStatus creates a Stage to add status information into the generated resources. +/* addStatusFromSwagger creates a PipelineStage to add status information into the generated resources. This information is derived from the Azure Swagger specifications. We parse the Swagger specs and look for any actions that appear to be ARM resources (have PUT methods with types we can use and appropriate names in the @@ -41,12 +40,11 @@ added to the Status field of the Resource type, after we have renamed all the st avoid any conflicts with existing Spec types that have already been defined. */ -func AugmentResourcesWithStatus(idFactory astmodel.IdentifierFactory, config *config.Configuration) Stage { +func AddStatusFromSwagger(idFactory astmodel.IdentifierFactory, config *config.Configuration) Stage { return MakeStage( - "augmentStatus", + "addStatusFromSwagger", "Add information from Swagger specs for 'status' fields", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { - if config.Status.SchemaRoot == "" { klog.Warningf("No status schema root specified, will not generate status types") return types, nil @@ -61,40 +59,35 @@ func AugmentResourcesWithStatus(idFactory astmodel.IdentifierFactory, config *co klog.V(1).Infof("Loaded Swagger data (%v resources, %v other types)", len(swaggerTypes.resources), len(swaggerTypes.otherTypes)) - newTypes := make(astmodel.Types) - statusTypes, err := generateStatusTypes(swaggerTypes) if err != nil { return nil, err } - found := 0 + // put all types into a new set + newTypes := make(astmodel.Types) + // all non-resources from Swagger are added regardless of whether they are used + // if they are not used they will be pruned off by a later pipeline stage + // (there will be no name clashes here due to suffixing with "_Status") + newTypes.AddTypes(statusTypes.otherTypes) + + matchedResources := 0 + // find any resources and update them with status info for typeName, typeDef := range types { - // for resources, try to find the matching Status type if resource, ok := typeDef.Type().(*astmodel.ResourceType); ok { - var newStatus astmodel.Type - if statusDef, ok := statusTypes.resourceTypes.tryFind(typeName); ok { - klog.V(4).Infof("Swagger information found for %v", typeName) - newStatus = statusDef - found++ - } else { - klog.V(4).Infof("Swagger information missing for %v", typeName) - // add a warning that the status is missing - // this will be reported if the type is not pruned - newStatus = astmodel.NewErroredType(nil, nil, []string{fmt.Sprintf("missing status information for %v", typeName)}) + // find the status type (= Swagger resource type) + newStatus, located := statusTypes.findResourceType(typeName) + if located { + matchedResources++ } - newTypes.Add(astmodel.MakeTypeDefinition(typeName, resource.WithStatus(newStatus))) + + newTypes.Add(typeDef.WithType(resource.WithStatus(newStatus))) } else { - // other types are simply copied newTypes.Add(typeDef) } } - // all non-resources are added regardless of whether they are used - // if they are not used they will be pruned off by a later pipeline stage - newTypes.AddAll(statusTypes.otherTypes) - - klog.V(1).Infof("Found status information for %v resources", found) + klog.V(1).Infof("Found status information for %v resources", matchedResources) klog.V(1).Infof("Input %v types, output %v types", len(types), len(newTypes)) return newTypes, nil @@ -107,7 +100,19 @@ type statusTypes struct { resourceTypes resourceLookup // otherTypes has all other Status types renamed to avoid clashes with Spec Types - otherTypes []astmodel.TypeDefinition + otherTypes astmodel.Types +} + +func (st statusTypes) findResourceType(typeName astmodel.TypeName) (astmodel.Type, bool) { + if statusDef, ok := st.resourceTypes.tryFind(typeName); ok { + klog.V(4).Infof("Swagger information found for %v", typeName) + return statusDef, true + } else { + klog.V(3).Infof("Swagger information missing for %v", typeName) + // add a warning that the status is missing + // this will be reported if the type is not pruned + return astmodel.NewErroredType(nil, nil, []string{fmt.Sprintf("missing status information for %v", typeName)}), false + } } type resourceLookup map[astmodel.TypeName]astmodel.Type @@ -130,33 +135,36 @@ func (resourceLookup resourceLookup) add(name astmodel.TypeName, theType astmode resourceLookup[lower] = theType } -// generateStatusTypes returns the statusTypes for the input swaggerTypes -func generateStatusTypes(swaggerTypes swaggerTypes) (statusTypes, error) { - appendStatusToName := func(typeName astmodel.TypeName) astmodel.TypeName { - return astmodel.MakeTypeName(typeName.PackageReference, typeName.Name()+"_Status") - } +// statusTypeRenamer appends "_Status" to all types +var statusTypeRenamer astmodel.TypeVisitor = makeRenamingVisitor(appendStatusSuffix) - renamer := makeRenamingVisitor(appendStatusToName) +func appendStatusSuffix(typeName astmodel.TypeName) astmodel.TypeName { + return astmodel.MakeTypeName(typeName.PackageReference, typeName.Name()+"_Status") +} +// generateStatusTypes returns the statusTypes for the input swaggerTypes +// all types (apart from Resources) are renamed to have "_Status" as a +// suffix, to avoid name clashes. +func generateStatusTypes(swaggerTypes swaggerTypes) (statusTypes, error) { var errs []error - var otherTypes []astmodel.TypeDefinition + otherTypes := make(astmodel.Types) for _, typeDef := range swaggerTypes.otherTypes { - renamedDef, err := renamer.VisitDefinition(typeDef, nil) + renamedDef, err := statusTypeRenamer.VisitDefinition(typeDef, nil) if err != nil { errs = append(errs, err) } else { - otherTypes = append(otherTypes, renamedDef) + otherTypes.Add(renamedDef) } } - lookup := make(resourceLookup) + resources := make(resourceLookup) for resourceName, resourceDef := range swaggerTypes.resources { // resourceName is not renamed as this is a lookup for the Spec type - renamedDef, err := renamer.Visit(resourceDef.Type(), nil) + renamedDef, err := statusTypeRenamer.Visit(resourceDef.Type(), nil) if err != nil { errs = append(errs, err) } else { - lookup.add(resourceName, renamedDef) + resources.add(resourceName, renamedDef) } } @@ -164,17 +172,15 @@ func generateStatusTypes(swaggerTypes swaggerTypes) (statusTypes, error) { return statusTypes{}, kerrors.NewAggregate(errs) } - return statusTypes{lookup, otherTypes}, nil + return statusTypes{resources, otherTypes}, nil } func makeRenamingVisitor(rename func(astmodel.TypeName) astmodel.TypeName) astmodel.TypeVisitor { - builder := astmodel.TypeVisitorBuilder{ - VisitTypeName: func(it astmodel.TypeName) (astmodel.Type, error) { + return astmodel.TypeVisitorBuilder{ + VisitTypeName: func(this *astmodel.TypeVisitor, it astmodel.TypeName, ctx interface{}) (astmodel.Type, error) { return rename(it), nil }, - } - - return builder.Build() + }.Build() } var swaggerVersionRegex = regexp.MustCompile(`\d{4}-\d{2}-\d{2}(-preview)?`) @@ -185,7 +191,6 @@ type swaggerTypes struct { } func loadSwaggerData(ctx context.Context, idFactory astmodel.IdentifierFactory, config *config.Configuration) (swaggerTypes, error) { - result := swaggerTypes{ resources: make(astmodel.Types), otherTypes: make(astmodel.Types), @@ -265,7 +270,6 @@ func loadAllSchemas( schemas := make(map[string]spec.Swagger) err := filepath.Walk(rootPath, func(filePath string, fileInfo os.FileInfo, err error) error { - if err != nil { return err } diff --git a/hack/generator/pkg/codegen/pipeline/augment_status_test.go b/hack/generator/pkg/codegen/pipeline/status_from_swagger_test.go similarity index 100% rename from hack/generator/pkg/codegen/pipeline/augment_status_test.go rename to hack/generator/pkg/codegen/pipeline/status_from_swagger_test.go diff --git a/hack/generator/pkg/codegen/testdata/ARMCodeGeneratorPipeline.golden b/hack/generator/pkg/codegen/testdata/ARMCodeGeneratorPipeline.golden index 1fcdb185879..5b853aed2a1 100644 --- a/hack/generator/pkg/codegen/testdata/ARMCodeGeneratorPipeline.golden +++ b/hack/generator/pkg/codegen/testdata/ARMCodeGeneratorPipeline.golden @@ -1,9 +1,10 @@ Expected Pipeline Stages for ARM Code Generation ------------------------------------------------ loadSchema Load and walk schema -augmentStatus Add information from Swagger specs for 'status' fields +addStatusFromSwagger Add information from Swagger specs for 'status' fields allof-anyof-objects Convert allOf and oneOf to object types flattenResources Flatten nested resource types +augmentSpecWithStatus Merges information from Status into Spec stripUnreferenced Strip unreferenced types nameTypes Name inner types for CRD propertyRewrites Modify property types using configured transforms @@ -22,6 +23,7 @@ reportTypesAndVersions azure Generate reports on types and ver createArmTypes azure Create types for interaction with ARM applyArmConversionInterface azure Add ARM conversion interfaces to Kubernetes types applyKubernetesResourceInterface azure Add the KubernetesResource interface to every resource +flattenProperties Apply flattening to properties marked for flattening addCrossplaneOwnerProperties crossplane Add the 3-tuple of (xName, xNameRef, xNameSelector) for each owning resource addCrossplaneForProviderProperty crossplane Add a 'ForProvider' property on every spec addCrossplaneAtProviderProperty crossplane Add an 'AtProvider' property on every status diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_oneof_resource_conversion_on_arm_type_only_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_oneof_resource_conversion_on_arm_type_only_azure.golden index 6a16988cfaf..87a5392a351 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_oneof_resource_conversion_on_arm_type_only_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_oneof_resource_conversion_on_arm_type_only_azure.golden @@ -205,8 +205,14 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef return nil, nil } var result FakeResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = FakeResourceSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if fakeResourceSpec.Properties != nil { propertiesARM, err := (*fakeResourceSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -215,6 +221,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef properties := propertiesARM.(PropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = FakeResourceSpecTypeMicrosoftAzureFakeResource return result, nil } @@ -230,8 +238,14 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: fakeResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: fakeResourceSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 Properties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -241,6 +255,8 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know properties := properties1 fakeResourceSpec.Properties = &properties } + + // No error return nil } @@ -310,6 +326,8 @@ func (properties *Properties) ConvertToARM(name string, resolvedReferences genru return nil, nil } var result PropertiesARM + + // Set property ‘Bar’: if properties.Bar != nil { barARM, err := (*properties.Bar).ConvertToARM(name, resolvedReferences) if err != nil { @@ -318,6 +336,8 @@ func (properties *Properties) ConvertToARM(name string, resolvedReferences genru bar := barARM.(BarARM) result.Bar = &bar } + + // Set property ‘Baz’: if properties.Baz != nil { bazARM, err := (*properties.Baz).ConvertToARM(name, resolvedReferences) if err != nil { @@ -326,6 +346,8 @@ func (properties *Properties) ConvertToARM(name string, resolvedReferences genru baz := bazARM.(BazARM) result.Baz = &baz } + + // Set property ‘Foo’: if properties.Foo != nil { fooARM, err := (*properties.Foo).ConvertToARM(name, resolvedReferences) if err != nil { @@ -348,6 +370,8 @@ func (properties *Properties) PopulateFromARM(owner genruntime.KnownResourceRefe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected PropertiesARM, got %T", armInput) } + + // Set property ‘Bar’: if typedInput.Bar != nil { var bar1 Bar err := bar1.PopulateFromARM(owner, *typedInput.Bar) @@ -357,6 +381,8 @@ func (properties *Properties) PopulateFromARM(owner genruntime.KnownResourceRefe bar := bar1 properties.Bar = &bar } + + // Set property ‘Baz’: if typedInput.Baz != nil { var baz1 Baz err := baz1.PopulateFromARM(owner, *typedInput.Baz) @@ -366,6 +392,8 @@ func (properties *Properties) PopulateFromARM(owner genruntime.KnownResourceRefe baz := baz1 properties.Baz = &baz } + + // Set property ‘Foo’: if typedInput.Foo != nil { var foo1 Foo err := foo1.PopulateFromARM(owner, *typedInput.Foo) @@ -375,6 +403,8 @@ func (properties *Properties) PopulateFromARM(owner genruntime.KnownResourceRefe foo := foo1 properties.Foo = &foo } + + // No error return nil } @@ -392,6 +422,8 @@ func (bar *Bar) ConvertToARM(name string, resolvedReferences genruntime.Resolved return nil, nil } var result BarARM + + // Set property ‘Size’: result.Size = bar.Size return result, nil } @@ -407,7 +439,11 @@ func (bar *Bar) PopulateFromARM(owner genruntime.KnownResourceReference, armInpu if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected BarARM, got %T", armInput) } + + // Set property ‘Size’: bar.Size = typedInput.Size + + // No error return nil } @@ -425,6 +461,8 @@ func (baz *Baz) ConvertToARM(name string, resolvedReferences genruntime.Resolved return nil, nil } var result BazARM + + // Set property ‘Enabled’: result.Enabled = baz.Enabled return result, nil } @@ -440,7 +478,11 @@ func (baz *Baz) PopulateFromARM(owner genruntime.KnownResourceReference, armInpu if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected BazARM, got %T", armInput) } + + // Set property ‘Enabled’: baz.Enabled = typedInput.Enabled + + // No error return nil } @@ -457,6 +499,8 @@ func (foo *Foo) ConvertToARM(name string, resolvedReferences genruntime.Resolved return nil, nil } var result FooARM + + // Set property ‘Name’: if foo.Name != nil { name := *foo.Name result.Name = &name @@ -475,10 +519,14 @@ func (foo *Foo) PopulateFromARM(owner genruntime.KnownResourceReference, armInpu if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FooARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name foo.Name = &name } + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_dependent_resource_and_ownership_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_dependent_resource_and_ownership_azure.golden index 238a85901a0..ef8e95556c5 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_dependent_resource_and_ownership_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_dependent_resource_and_ownership_azure.golden @@ -688,8 +688,14 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result A_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = ASpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Type’: result.Type = ASpecTypeMicrosoftAzureA return result, nil } @@ -705,8 +711,14 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected A_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: aSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: aSpec.Owner = owner + + // No error return nil } @@ -740,8 +752,14 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result B_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = BSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Type’: result.Type = BSpecTypeMicrosoftAzureB return result, nil } @@ -757,8 +775,14 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected B_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: bSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: bSpec.Owner = owner + + // No error return nil } @@ -792,8 +816,14 @@ func (cSpec *C_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result C_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = CSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Type’: result.Type = CSpecTypeMicrosoftAzureC return result, nil } @@ -809,8 +839,14 @@ func (cSpec *C_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected C_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: cSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: cSpec.Owner = owner + + // No error return nil } @@ -844,8 +880,14 @@ func (dSpec *D_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result D_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = DSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Type’: result.Type = DSpecTypeMicrosoftAzureD return result, nil } @@ -861,8 +903,14 @@ func (dSpec *D_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected D_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: dSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: dSpec.Owner = owner + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_empty_objecttype_removed_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_empty_objecttype_removed_azure.golden index ad78fe27f30..e5c07e0efa1 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_empty_objecttype_removed_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_empty_objecttype_removed_azure.golden @@ -373,8 +373,14 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result A_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = ASpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if aSpec.Properties != nil { propertiesARM, err := (*aSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -383,6 +389,8 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(APropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = ASpecTypeMicrosoftAzureA return result, nil } @@ -398,8 +406,14 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected A_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: aSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: aSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 AProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -409,6 +423,8 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 aSpec.Properties = &properties } + + // No error return nil } @@ -448,8 +464,14 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result B_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = BSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if bSpec.Properties != nil { propertiesARM, err := (*bSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -458,6 +480,8 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(BPropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = BSpecTypeMicrosoftAzureB return result, nil } @@ -473,8 +497,14 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected B_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: bSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: bSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 BProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -484,6 +514,8 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 bSpec.Properties = &properties } + + // No error return nil } @@ -504,10 +536,14 @@ func (aProperties *AProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result APropertiesARM + + // Set property ‘IntField’: if aProperties.IntField != nil { intField := *aProperties.IntField result.IntField = &intField } + + // Set property ‘StringField’: if aProperties.StringField != nil { stringField := *aProperties.StringField result.StringField = &stringField @@ -526,14 +562,20 @@ func (aProperties *AProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected APropertiesARM, got %T", armInput) } + + // Set property ‘IntField’: if typedInput.IntField != nil { intField := *typedInput.IntField aProperties.IntField = &intField } + + // Set property ‘StringField’: if typedInput.StringField != nil { stringField := *typedInput.StringField aProperties.StringField = &stringField } + + // No error return nil } @@ -550,6 +592,8 @@ func (bProperties *BProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result BPropertiesARM + + // Set property ‘EnumField’: if bProperties.EnumField != nil { enumField := *bProperties.EnumField result.EnumField = &enumField @@ -568,10 +612,14 @@ func (bProperties *BProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected BPropertiesARM, got %T", armInput) } + + // Set property ‘EnumField’: if typedInput.EnumField != nil { enumField := *typedInput.EnumField bProperties.EnumField = &enumField } + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_has_embedded_resource_inside_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_has_embedded_resource_inside_azure.golden index b749258a050..1760933bbad 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_has_embedded_resource_inside_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_has_embedded_resource_inside_azure.golden @@ -537,8 +537,14 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result A_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = ASpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if aSpec.Properties != nil { propertiesARM, err := (*aSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -547,6 +553,8 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(APropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = ASpecTypeMicrosoftAzureA return result, nil } @@ -562,8 +570,14 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected A_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: aSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: aSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 AProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -573,6 +587,8 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 aSpec.Properties = &properties } + + // No error return nil } @@ -613,8 +629,14 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result B_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = BSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if bSpec.Properties != nil { propertiesARM, err := (*bSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -623,6 +645,8 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(BPropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = BSpecTypeMicrosoftAzureB return result, nil } @@ -638,8 +662,14 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected B_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: bSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: bSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 BProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -649,6 +679,8 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 bSpec.Properties = &properties } + + // No error return nil } @@ -689,8 +721,14 @@ func (cSpec *C_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result C_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = CSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if cSpec.Properties != nil { propertiesARM, err := (*cSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -699,6 +737,8 @@ func (cSpec *C_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(CPropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = CSpecTypeMicrosoftAzureC return result, nil } @@ -714,8 +754,14 @@ func (cSpec *C_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected C_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: cSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: cSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 CProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -725,6 +771,8 @@ func (cSpec *C_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 cSpec.Properties = &properties } + + // No error return nil } @@ -746,10 +794,14 @@ func (aProperties *AProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result APropertiesARM + + // Set property ‘IntField’: if aProperties.IntField != nil { intField := *aProperties.IntField result.IntField = &intField } + + // Set property ‘RefField’: if aProperties.RefField != nil { refFieldARM, err := (*aProperties.RefField).ConvertToARM(name, resolvedReferences) if err != nil { @@ -758,6 +810,8 @@ func (aProperties *AProperties) ConvertToARM(name string, resolvedReferences gen refField := refFieldARM.(BResourceARM) result.RefField = &refField } + + // Set property ‘StringField’: if aProperties.StringField != nil { stringField := *aProperties.StringField result.StringField = &stringField @@ -776,10 +830,14 @@ func (aProperties *AProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected APropertiesARM, got %T", armInput) } + + // Set property ‘IntField’: if typedInput.IntField != nil { intField := *typedInput.IntField aProperties.IntField = &intField } + + // Set property ‘RefField’: if typedInput.RefField != nil { var refField1 BResource err := refField1.PopulateFromARM(owner, *typedInput.RefField) @@ -789,10 +847,14 @@ func (aProperties *AProperties) PopulateFromARM(owner genruntime.KnownResourceRe refField := refField1 aProperties.RefField = &refField } + + // Set property ‘StringField’: if typedInput.StringField != nil { stringField := *typedInput.StringField aProperties.StringField = &stringField } + + // No error return nil } @@ -810,10 +872,14 @@ func (bProperties *BProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result BPropertiesARM + + // Set property ‘EnumField’: if bProperties.EnumField != nil { enumField := *bProperties.EnumField result.EnumField = &enumField } + + // Set property ‘RefField’: if bProperties.RefField != nil { refFieldARM, err := (*bProperties.RefField).ConvertToARM(name, resolvedReferences) if err != nil { @@ -836,10 +902,14 @@ func (bProperties *BProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected BPropertiesARM, got %T", armInput) } + + // Set property ‘EnumField’: if typedInput.EnumField != nil { enumField := *typedInput.EnumField bProperties.EnumField = &enumField } + + // Set property ‘RefField’: if typedInput.RefField != nil { var refField1 CResource err := refField1.PopulateFromARM(owner, *typedInput.RefField) @@ -849,6 +919,8 @@ func (bProperties *BProperties) PopulateFromARM(owner genruntime.KnownResourceRe refField := refField1 bProperties.RefField = &refField } + + // No error return nil } @@ -876,10 +948,14 @@ func (cProperties *CProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result CPropertiesARM + + // Set property ‘IntField’: if cProperties.IntField != nil { intField := *cProperties.IntField result.IntField = &intField } + + // Set property ‘StringField’: if cProperties.StringField != nil { stringField := *cProperties.StringField result.StringField = &stringField @@ -898,14 +974,20 @@ func (cProperties *CProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected CPropertiesARM, got %T", armInput) } + + // Set property ‘IntField’: if typedInput.IntField != nil { intField := *typedInput.IntField cProperties.IntField = &intField } + + // Set property ‘StringField’: if typedInput.StringField != nil { stringField := *typedInput.StringField cProperties.StringField = &stringField } + + // No error return nil } @@ -927,6 +1009,8 @@ func (bResource *BResource) ConvertToARM(name string, resolvedReferences genrunt return nil, nil } var result BResourceARM + + // Set property ‘Id’: if bResource.Reference != nil { referenceARMID, err := resolvedReferences.ARMIDOrErr(*bResource.Reference) if err != nil { @@ -945,6 +1029,10 @@ func (bResource *BResource) CreateEmptyARMValue() interface{} { // PopulateFromARM populates a Kubernetes CRD object from an Azure ARM object func (bResource *BResource) PopulateFromARM(owner genruntime.KnownResourceReference, armInput interface{}) error { + _, ok := armInput.(BResourceARM) + if !ok { + return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected BResourceARM, got %T", armInput) + } // No error return nil @@ -963,6 +1051,8 @@ func (cResource *CResource) ConvertToARM(name string, resolvedReferences genrunt return nil, nil } var result CResourceARM + + // Set property ‘Id’: if cResource.Reference != nil { referenceARMID, err := resolvedReferences.ARMIDOrErr(*cResource.Reference) if err != nil { @@ -981,6 +1071,10 @@ func (cResource *CResource) CreateEmptyARMValue() interface{} { // PopulateFromARM populates a Kubernetes CRD object from an Azure ARM object func (cResource *CResource) PopulateFromARM(owner genruntime.KnownResourceReference, armInput interface{}) error { + _, ok := armInput.(CResourceARM) + if !ok { + return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected CResourceARM, got %T", armInput) + } // No error return nil diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_multiple_contexts_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_multiple_contexts_azure.golden index 47a602c08f8..339161e594d 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_multiple_contexts_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_multiple_contexts_azure.golden @@ -210,8 +210,14 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result A_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = ASpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if aSpec.Properties != nil { propertiesARM, err := (*aSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -220,6 +226,8 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(APropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = ASpecTypeMicrosoftAzureA return result, nil } @@ -235,8 +243,14 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected A_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: aSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: aSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 AProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -246,6 +260,8 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 aSpec.Properties = &properties } + + // No error return nil } @@ -266,6 +282,8 @@ func (aProperties *AProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result APropertiesARM + + // Set property ‘Left’: if aProperties.Left != nil { leftARM, err := (*aProperties.Left).ConvertToARM(name, resolvedReferences) if err != nil { @@ -274,6 +292,8 @@ func (aProperties *AProperties) ConvertToARM(name string, resolvedReferences gen left := leftARM.(Left_SubResourceEmbeddedARM) result.Left = &left } + + // Set property ‘Right’: if aProperties.Right != nil { rightARM, err := (*aProperties.Right).ConvertToARM(name, resolvedReferences) if err != nil { @@ -296,6 +316,8 @@ func (aProperties *AProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected APropertiesARM, got %T", armInput) } + + // Set property ‘Left’: if typedInput.Left != nil { var left1 Left_SubResourceEmbedded err := left1.PopulateFromARM(owner, *typedInput.Left) @@ -305,6 +327,8 @@ func (aProperties *AProperties) PopulateFromARM(owner genruntime.KnownResourceRe left := left1 aProperties.Left = &left } + + // Set property ‘Right’: if typedInput.Right != nil { var right1 Right_SubResourceEmbedded_1 err := right1.PopulateFromARM(owner, *typedInput.Right) @@ -314,6 +338,8 @@ func (aProperties *AProperties) PopulateFromARM(owner genruntime.KnownResourceRe right := right1 aProperties.Right = &right } + + // No error return nil } @@ -363,10 +389,14 @@ func (leftSubResourceEmbedded *Left_SubResourceEmbedded) ConvertToARM(name strin return nil, nil } var result Left_SubResourceEmbeddedARM + + // Set property ‘Name’: if leftSubResourceEmbedded.Name != nil { name := *leftSubResourceEmbedded.Name result.Name = &name } + + // Set property ‘Properties’: if leftSubResourceEmbedded.Properties != nil { propertiesARM, err := (*leftSubResourceEmbedded.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -375,6 +405,8 @@ func (leftSubResourceEmbedded *Left_SubResourceEmbedded) ConvertToARM(name strin properties := propertiesARM.(LeftPropertiesARM) result.Properties = &properties } + + // Set property ‘RefField’: if leftSubResourceEmbedded.RefField != nil { refFieldARM, err := (*leftSubResourceEmbedded.RefField).ConvertToARM(name, resolvedReferences) if err != nil { @@ -397,10 +429,14 @@ func (leftSubResourceEmbedded *Left_SubResourceEmbedded) PopulateFromARM(owner g if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected Left_SubResourceEmbeddedARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name leftSubResourceEmbedded.Name = &name } + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 LeftProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -410,6 +446,8 @@ func (leftSubResourceEmbedded *Left_SubResourceEmbedded) PopulateFromARM(owner g properties := properties1 leftSubResourceEmbedded.Properties = &properties } + + // Set property ‘RefField’: if typedInput.RefField != nil { var refField1 FakeResource_SubResourceEmbedded err := refField1.PopulateFromARM(owner, *typedInput.RefField) @@ -419,6 +457,8 @@ func (leftSubResourceEmbedded *Left_SubResourceEmbedded) PopulateFromARM(owner g refField := refField1 leftSubResourceEmbedded.RefField = &refField } + + // No error return nil } @@ -442,10 +482,14 @@ func (rightSubResourceEmbedded1 *Right_SubResourceEmbedded_1) ConvertToARM(name return nil, nil } var result Right_SubResourceEmbedded_1ARM + + // Set property ‘Name’: if rightSubResourceEmbedded1.Name != nil { name := *rightSubResourceEmbedded1.Name result.Name = &name } + + // Set property ‘Properties’: if rightSubResourceEmbedded1.Properties != nil { propertiesARM, err := (*rightSubResourceEmbedded1.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -454,6 +498,8 @@ func (rightSubResourceEmbedded1 *Right_SubResourceEmbedded_1) ConvertToARM(name properties := propertiesARM.(RightPropertiesARM) result.Properties = &properties } + + // Set property ‘RefField’: if rightSubResourceEmbedded1.RefField != nil { refFieldARM, err := (*rightSubResourceEmbedded1.RefField).ConvertToARM(name, resolvedReferences) if err != nil { @@ -476,10 +522,14 @@ func (rightSubResourceEmbedded1 *Right_SubResourceEmbedded_1) PopulateFromARM(ow if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected Right_SubResourceEmbedded_1ARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name rightSubResourceEmbedded1.Name = &name } + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 RightProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -489,6 +539,8 @@ func (rightSubResourceEmbedded1 *Right_SubResourceEmbedded_1) PopulateFromARM(ow properties := properties1 rightSubResourceEmbedded1.Properties = &properties } + + // Set property ‘RefField’: if typedInput.RefField != nil { var refField1 FakeResource_SubResourceEmbedded_1 err := refField1.PopulateFromARM(owner, *typedInput.RefField) @@ -498,6 +550,8 @@ func (rightSubResourceEmbedded1 *Right_SubResourceEmbedded_1) PopulateFromARM(ow refField := refField1 rightSubResourceEmbedded1.RefField = &refField } + + // No error return nil } @@ -525,10 +579,14 @@ func (fakeResourceSubResourceEmbedded *FakeResource_SubResourceEmbedded) Convert return nil, nil } var result FakeResource_SubResourceEmbeddedARM + + // Set property ‘Name’: if fakeResourceSubResourceEmbedded.Name != nil { name := *fakeResourceSubResourceEmbedded.Name result.Name = &name } + + // Set property ‘Properties’: if fakeResourceSubResourceEmbedded.Properties != nil { propertiesARM, err := (*fakeResourceSubResourceEmbedded.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -551,10 +609,14 @@ func (fakeResourceSubResourceEmbedded *FakeResource_SubResourceEmbedded) Populat if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SubResourceEmbeddedARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name fakeResourceSubResourceEmbedded.Name = &name } + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 FakeResourceProperties_SubResourceEmbedded err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -564,6 +626,8 @@ func (fakeResourceSubResourceEmbedded *FakeResource_SubResourceEmbedded) Populat properties := properties1 fakeResourceSubResourceEmbedded.Properties = &properties } + + // No error return nil } @@ -581,10 +645,14 @@ func (fakeResourceSubResourceEmbedded1 *FakeResource_SubResourceEmbedded_1) Conv return nil, nil } var result FakeResource_SubResourceEmbedded_1ARM + + // Set property ‘Name’: if fakeResourceSubResourceEmbedded1.Name != nil { name := *fakeResourceSubResourceEmbedded1.Name result.Name = &name } + + // Set property ‘Properties’: if fakeResourceSubResourceEmbedded1.Properties != nil { propertiesARM, err := (*fakeResourceSubResourceEmbedded1.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -607,10 +675,14 @@ func (fakeResourceSubResourceEmbedded1 *FakeResource_SubResourceEmbedded_1) Popu if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SubResourceEmbedded_1ARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name fakeResourceSubResourceEmbedded1.Name = &name } + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 FakeResourceProperties_SubResourceEmbedded_1 err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -620,6 +692,8 @@ func (fakeResourceSubResourceEmbedded1 *FakeResource_SubResourceEmbedded_1) Popu properties := properties1 fakeResourceSubResourceEmbedded1.Properties = &properties } + + // No error return nil } @@ -636,6 +710,8 @@ func (leftProperties *LeftProperties) ConvertToARM(name string, resolvedReferenc return nil, nil } var result LeftPropertiesARM + + // Set property ‘StrField’: if leftProperties.StrField != nil { strField := *leftProperties.StrField result.StrField = &strField @@ -654,10 +730,14 @@ func (leftProperties *LeftProperties) PopulateFromARM(owner genruntime.KnownReso if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected LeftPropertiesARM, got %T", armInput) } + + // Set property ‘StrField’: if typedInput.StrField != nil { strField := *typedInput.StrField leftProperties.StrField = &strField } + + // No error return nil } @@ -674,6 +754,8 @@ func (rightProperties *RightProperties) ConvertToARM(name string, resolvedRefere return nil, nil } var result RightPropertiesARM + + // Set property ‘StrField’: if rightProperties.StrField != nil { strField := *rightProperties.StrField result.StrField = &strField @@ -692,10 +774,14 @@ func (rightProperties *RightProperties) PopulateFromARM(owner genruntime.KnownRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected RightPropertiesARM, got %T", armInput) } + + // Set property ‘StrField’: if typedInput.StrField != nil { strField := *typedInput.StrField rightProperties.StrField = &strField } + + // No error return nil } @@ -712,6 +798,8 @@ func (fakeResourcePropertiesSubResourceEmbedded *FakeResourceProperties_SubResou return nil, nil } var result FakeResourceProperties_SubResourceEmbeddedARM + + // Set property ‘Loop2’: if fakeResourcePropertiesSubResourceEmbedded.Loop2 != nil { loop2ARM, err := (*fakeResourcePropertiesSubResourceEmbedded.Loop2).ConvertToARM(name, resolvedReferences) if err != nil { @@ -734,6 +822,8 @@ func (fakeResourcePropertiesSubResourceEmbedded *FakeResourceProperties_SubResou if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResourceProperties_SubResourceEmbeddedARM, got %T", armInput) } + + // Set property ‘Loop2’: if typedInput.Loop2 != nil { var loop Right_SubResourceEmbedded err := loop.PopulateFromARM(owner, *typedInput.Loop2) @@ -743,6 +833,8 @@ func (fakeResourcePropertiesSubResourceEmbedded *FakeResourceProperties_SubResou loop2 := loop fakeResourcePropertiesSubResourceEmbedded.Loop2 = &loop2 } + + // No error return nil } @@ -759,6 +851,8 @@ func (fakeResourcePropertiesSubResourceEmbedded1 *FakeResourceProperties_SubReso return nil, nil } var result FakeResourceProperties_SubResourceEmbedded_1ARM + + // Set property ‘Loop1’: if fakeResourcePropertiesSubResourceEmbedded1.Loop1 != nil { loop1ARM, err := (*fakeResourcePropertiesSubResourceEmbedded1.Loop1).ConvertToARM(name, resolvedReferences) if err != nil { @@ -781,6 +875,8 @@ func (fakeResourcePropertiesSubResourceEmbedded1 *FakeResourceProperties_SubReso if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResourceProperties_SubResourceEmbedded_1ARM, got %T", armInput) } + + // Set property ‘Loop1’: if typedInput.Loop1 != nil { var loop Left_SubResourceEmbedded_1 err := loop.PopulateFromARM(owner, *typedInput.Loop1) @@ -790,6 +886,8 @@ func (fakeResourcePropertiesSubResourceEmbedded1 *FakeResourceProperties_SubReso loop1 := loop fakeResourcePropertiesSubResourceEmbedded1.Loop1 = &loop1 } + + // No error return nil } @@ -819,10 +917,14 @@ func (leftSubResourceEmbedded1 *Left_SubResourceEmbedded_1) ConvertToARM(name st return nil, nil } var result Left_SubResourceEmbedded_1ARM + + // Set property ‘Name’: if leftSubResourceEmbedded1.Name != nil { name := *leftSubResourceEmbedded1.Name result.Name = &name } + + // Set property ‘Properties’: if leftSubResourceEmbedded1.Properties != nil { propertiesARM, err := (*leftSubResourceEmbedded1.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -845,10 +947,14 @@ func (leftSubResourceEmbedded1 *Left_SubResourceEmbedded_1) PopulateFromARM(owne if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected Left_SubResourceEmbedded_1ARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name leftSubResourceEmbedded1.Name = &name } + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 LeftProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -858,6 +964,8 @@ func (leftSubResourceEmbedded1 *Left_SubResourceEmbedded_1) PopulateFromARM(owne properties := properties1 leftSubResourceEmbedded1.Properties = &properties } + + // No error return nil } @@ -875,10 +983,14 @@ func (rightSubResourceEmbedded *Right_SubResourceEmbedded) ConvertToARM(name str return nil, nil } var result Right_SubResourceEmbeddedARM + + // Set property ‘Name’: if rightSubResourceEmbedded.Name != nil { name := *rightSubResourceEmbedded.Name result.Name = &name } + + // Set property ‘Properties’: if rightSubResourceEmbedded.Properties != nil { propertiesARM, err := (*rightSubResourceEmbedded.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -901,10 +1013,14 @@ func (rightSubResourceEmbedded *Right_SubResourceEmbedded) PopulateFromARM(owner if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected Right_SubResourceEmbeddedARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name rightSubResourceEmbedded.Name = &name } + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 RightProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -914,6 +1030,8 @@ func (rightSubResourceEmbedded *Right_SubResourceEmbedded) PopulateFromARM(owner properties := properties1 rightSubResourceEmbedded.Properties = &properties } + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_removed_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_removed_azure.golden index 9f4e664ef26..2edfd2af6a4 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_removed_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_resource_removed_azure.golden @@ -374,8 +374,14 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result A_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = ASpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if aSpec.Properties != nil { propertiesARM, err := (*aSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -384,6 +390,8 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(APropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = ASpecTypeMicrosoftAzureA return result, nil } @@ -399,8 +407,14 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected A_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: aSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: aSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 AProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -410,6 +424,8 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 aSpec.Properties = &properties } + + // No error return nil } @@ -449,8 +465,14 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result B_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = BSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if bSpec.Properties != nil { propertiesARM, err := (*bSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -459,6 +481,8 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(BPropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = BSpecTypeMicrosoftAzureB return result, nil } @@ -474,8 +498,14 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected B_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: bSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: bSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 BProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -485,6 +515,8 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 bSpec.Properties = &properties } + + // No error return nil } @@ -506,10 +538,14 @@ func (aProperties *AProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result APropertiesARM + + // Set property ‘IntField’: if aProperties.IntField != nil { intField := *aProperties.IntField result.IntField = &intField } + + // Set property ‘RefField’: if aProperties.RefField != nil { refFieldARM, err := (*aProperties.RefField).ConvertToARM(name, resolvedReferences) if err != nil { @@ -518,6 +554,8 @@ func (aProperties *AProperties) ConvertToARM(name string, resolvedReferences gen refField := refFieldARM.(BResourceARM) result.RefField = &refField } + + // Set property ‘StringField’: if aProperties.StringField != nil { stringField := *aProperties.StringField result.StringField = &stringField @@ -536,10 +574,14 @@ func (aProperties *AProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected APropertiesARM, got %T", armInput) } + + // Set property ‘IntField’: if typedInput.IntField != nil { intField := *typedInput.IntField aProperties.IntField = &intField } + + // Set property ‘RefField’: if typedInput.RefField != nil { var refField1 BResource err := refField1.PopulateFromARM(owner, *typedInput.RefField) @@ -549,10 +591,14 @@ func (aProperties *AProperties) PopulateFromARM(owner genruntime.KnownResourceRe refField := refField1 aProperties.RefField = &refField } + + // Set property ‘StringField’: if typedInput.StringField != nil { stringField := *typedInput.StringField aProperties.StringField = &stringField } + + // No error return nil } @@ -569,6 +615,8 @@ func (bProperties *BProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result BPropertiesARM + + // Set property ‘EnumField’: if bProperties.EnumField != nil { enumField := *bProperties.EnumField result.EnumField = &enumField @@ -587,10 +635,14 @@ func (bProperties *BProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected BPropertiesARM, got %T", armInput) } + + // Set property ‘EnumField’: if typedInput.EnumField != nil { enumField := *typedInput.EnumField bProperties.EnumField = &enumField } + + // No error return nil } @@ -617,6 +669,8 @@ func (bResource *BResource) ConvertToARM(name string, resolvedReferences genrunt return nil, nil } var result BResourceARM + + // Set property ‘Id’: if bResource.Reference != nil { referenceARMID, err := resolvedReferences.ARMIDOrErr(*bResource.Reference) if err != nil { @@ -635,6 +689,10 @@ func (bResource *BResource) CreateEmptyARMValue() interface{} { // PopulateFromARM populates a Kubernetes CRD object from an Azure ARM object func (bResource *BResource) PopulateFromARM(owner genruntime.KnownResourceReference, armInput interface{}) error { + _, ok := armInput.(BResourceARM) + if !ok { + return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected BResourceARM, got %T", armInput) + } // No error return nil diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_subresource_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_subresource_azure.golden index 5f9a4a7f629..4d4030fd44c 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_subresource_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_subresource_azure.golden @@ -373,8 +373,14 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result A_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = ASpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if aSpec.Properties != nil { propertiesARM, err := (*aSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -383,6 +389,8 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(APropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = ASpecTypeMicrosoftAzureA return result, nil } @@ -398,8 +406,14 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected A_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: aSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: aSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 AProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -409,6 +423,8 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 aSpec.Properties = &properties } + + // No error return nil } @@ -448,8 +464,14 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result B_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = BSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if bSpec.Properties != nil { propertiesARM, err := (*bSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -458,6 +480,8 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(BPropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = BSpecTypeMicrosoftAzureB return result, nil } @@ -473,8 +497,14 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected B_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: bSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: bSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 BProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -484,6 +514,8 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 bSpec.Properties = &properties } + + // No error return nil } @@ -504,10 +536,14 @@ func (aProperties *AProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result APropertiesARM + + // Set property ‘IntField’: if aProperties.IntField != nil { intField := *aProperties.IntField result.IntField = &intField } + + // Set property ‘StringField’: if aProperties.StringField != nil { stringField := *aProperties.StringField result.StringField = &stringField @@ -526,14 +562,20 @@ func (aProperties *AProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected APropertiesARM, got %T", armInput) } + + // Set property ‘IntField’: if typedInput.IntField != nil { intField := *typedInput.IntField aProperties.IntField = &intField } + + // Set property ‘StringField’: if typedInput.StringField != nil { stringField := *typedInput.StringField aProperties.StringField = &stringField } + + // No error return nil } @@ -550,6 +592,8 @@ func (bProperties *BProperties) ConvertToARM(name string, resolvedReferences gen return nil, nil } var result BPropertiesARM + + // Set property ‘EnumField’: if bProperties.EnumField != nil { enumField := *bProperties.EnumField result.EnumField = &enumField @@ -568,10 +612,14 @@ func (bProperties *BProperties) PopulateFromARM(owner genruntime.KnownResourceRe if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected BPropertiesARM, got %T", armInput) } + + // Set property ‘EnumField’: if typedInput.EnumField != nil { enumField := *typedInput.EnumField bProperties.EnumField = &enumField } + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_subresource_same_properties_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_subresource_same_properties_azure.golden index d60122afb13..eebea11b6c7 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_subresource_same_properties_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_embedded_subresource_same_properties_azure.golden @@ -367,8 +367,14 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result A_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = ASpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if aSpec.Properties != nil { propertiesARM, err := (*aSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -377,6 +383,8 @@ func (aSpec *A_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(CommonPropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = ASpecTypeMicrosoftAzureA return result, nil } @@ -392,8 +400,14 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected A_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: aSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: aSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 CommonProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -403,6 +417,8 @@ func (aSpec *A_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 aSpec.Properties = &properties } + + // No error return nil } @@ -437,8 +453,14 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res return nil, nil } var result B_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = BSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if bSpec.Properties != nil { propertiesARM, err := (*bSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -447,6 +469,8 @@ func (bSpec *B_Spec) ConvertToARM(name string, resolvedReferences genruntime.Res properties := propertiesARM.(CommonPropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = BSpecTypeMicrosoftAzureB return result, nil } @@ -462,8 +486,14 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected B_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: bSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: bSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 CommonProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -473,6 +503,8 @@ func (bSpec *B_Spec) PopulateFromARM(owner genruntime.KnownResourceReference, ar properties := properties1 bSpec.Properties = &properties } + + // No error return nil } @@ -499,10 +531,14 @@ func (commonProperties *CommonProperties) ConvertToARM(name string, resolvedRefe return nil, nil } var result CommonPropertiesARM + + // Set property ‘IntField’: if commonProperties.IntField != nil { intField := *commonProperties.IntField result.IntField = &intField } + + // Set property ‘StringField’: if commonProperties.StringField != nil { stringField := *commonProperties.StringField result.StringField = &stringField @@ -521,14 +557,20 @@ func (commonProperties *CommonProperties) PopulateFromARM(owner genruntime.Known if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected CommonPropertiesARM, got %T", armInput) } + + // Set property ‘IntField’: if typedInput.IntField != nil { intField := *typedInput.IntField commonProperties.IntField = &intField } + + // Set property ‘StringField’: if typedInput.StringField != nil { stringField := *typedInput.StringField commonProperties.StringField = &stringField } + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_id_resource_reference_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_id_resource_reference_azure.golden index 5552b1b9e1f..01f62b4cd1f 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_id_resource_reference_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_id_resource_reference_azure.golden @@ -210,8 +210,14 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef return nil, nil } var result FakeResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = FakeResourceSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if fakeResourceSpec.Properties != nil { propertiesARM, err := (*fakeResourceSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -220,6 +226,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef properties := propertiesARM.(FakeResourcePropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = FakeResourceSpecTypeMicrosoftAzureFakeResource return result, nil } @@ -235,8 +243,14 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: fakeResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: fakeResourceSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 FakeResourceProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -246,6 +260,8 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know properties := properties1 fakeResourceSpec.Properties = &properties } + + // No error return nil } @@ -273,6 +289,8 @@ func (fakeResourceProperties *FakeResourceProperties) ConvertToARM(name string, return nil, nil } var result FakeResourcePropertiesARM + + // Set property ‘Id’: if fakeResourceProperties.Reference != nil { referenceARMID, err := resolvedReferences.ARMIDOrErr(*fakeResourceProperties.Reference) if err != nil { @@ -281,6 +299,8 @@ func (fakeResourceProperties *FakeResourceProperties) ConvertToARM(name string, reference := referenceARMID result.Id = &reference } + + // Set property ‘SubnetId’: if fakeResourceProperties.SubnetReference != nil { subnetReferenceARMID, err := resolvedReferences.ARMIDOrErr(*fakeResourceProperties.SubnetReference) if err != nil { @@ -299,6 +319,10 @@ func (fakeResourceProperties *FakeResourceProperties) CreateEmptyARMValue() inte // PopulateFromARM populates a Kubernetes CRD object from an Azure ARM object func (fakeResourceProperties *FakeResourceProperties) PopulateFromARM(owner genruntime.KnownResourceReference, armInput interface{}) error { + _, ok := armInput.(FakeResourcePropertiesARM) + if !ok { + return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResourcePropertiesARM, got %T", armInput) + } // No error return nil diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_required_and_optional_resource_references_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_required_and_optional_resource_references_azure.golden index a809ee77806..61760ab28d8 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_required_and_optional_resource_references_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_required_and_optional_resource_references_azure.golden @@ -210,8 +210,14 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef return nil, nil } var result FakeResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = FakeResourceSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Properties’: if fakeResourceSpec.Properties != nil { propertiesARM, err := (*fakeResourceSpec.Properties).ConvertToARM(name, resolvedReferences) if err != nil { @@ -220,6 +226,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef properties := propertiesARM.(FakeResourcePropertiesARM) result.Properties = &properties } + + // Set property ‘Type’: result.Type = FakeResourceSpecTypeMicrosoftAzureFakeResource return result, nil } @@ -235,8 +243,14 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: fakeResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: fakeResourceSpec.Owner = owner + + // Set property ‘Properties’: if typedInput.Properties != nil { var properties1 FakeResourceProperties err := properties1.PopulateFromARM(owner, *typedInput.Properties) @@ -246,6 +260,8 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know properties := properties1 fakeResourceSpec.Properties = &properties } + + // No error return nil } @@ -274,6 +290,8 @@ func (fakeResourceProperties *FakeResourceProperties) ConvertToARM(name string, return nil, nil } var result FakeResourcePropertiesARM + + // Set property ‘OptionalVNet’: if fakeResourceProperties.OptionalVNetReference != nil { optionalVNetReferenceARMID, err := resolvedReferences.ARMIDOrErr(*fakeResourceProperties.OptionalVNetReference) if err != nil { @@ -282,6 +300,8 @@ func (fakeResourceProperties *FakeResourceProperties) ConvertToARM(name string, optionalVNetReference := optionalVNetReferenceARMID result.OptionalVNet = &optionalVNetReference } + + // Set property ‘RequiredVNet’: requiredVNetReferenceARMID, err := resolvedReferences.ARMIDOrErr(fakeResourceProperties.RequiredVNetReference) if err != nil { return nil, err @@ -297,6 +317,10 @@ func (fakeResourceProperties *FakeResourceProperties) CreateEmptyARMValue() inte // PopulateFromARM populates a Kubernetes CRD object from an Azure ARM object func (fakeResourceProperties *FakeResourceProperties) PopulateFromARM(owner genruntime.KnownResourceReference, armInput interface{}) error { + _, ok := armInput.(FakeResourcePropertiesARM) + if !ok { + return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResourcePropertiesARM, got %T", armInput) + } // No error return nil diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_array_properties_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_array_properties_azure.golden index c7d2f8da11b..4284b988470 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_array_properties_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_array_properties_azure.golden @@ -224,7 +224,11 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef return nil, nil } var result FakeResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = FakeResourceSpecAPIVersion20200601 + + // Set property ‘ArrayFoo’: for _, item := range fakeResourceSpec.ArrayFoo { itemARM, err := item.ConvertToARM(name, resolvedReferences) if err != nil { @@ -232,6 +236,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef } result.ArrayFoo = append(result.ArrayFoo, itemARM.(FooARM)) } + + // Set property ‘ArrayOfArrays’: for _, item := range fakeResourceSpec.ArrayOfArrays { var itemTemp []FooARM for _, item1 := range item { @@ -243,6 +249,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef } result.ArrayOfArrays = append(result.ArrayOfArrays, itemTemp) } + + // Set property ‘ArrayOfArraysOfArrays’: for _, item := range fakeResourceSpec.ArrayOfArraysOfArrays { var itemTemp [][]FooARM for _, item1 := range item { @@ -258,9 +266,13 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef } result.ArrayOfArraysOfArrays = append(result.ArrayOfArraysOfArrays, itemTemp) } + + // Set property ‘ArrayOfEnums’: for _, item := range fakeResourceSpec.ArrayOfEnums { result.ArrayOfEnums = append(result.ArrayOfEnums, item) } + + // Set property ‘ArrayOfMaps’: for _, item := range fakeResourceSpec.ArrayOfMaps { if item != nil { itemTemp := make(map[string]FooARM) @@ -274,7 +286,11 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef result.ArrayOfMaps = append(result.ArrayOfMaps, itemTemp) } } + + // Set property ‘Name’: result.Name = name + + // Set property ‘Type’: result.Type = FakeResourceSpecTypeMicrosoftAzureFakeResource return result, nil } @@ -290,6 +306,8 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SpecARM, got %T", armInput) } + + // Set property ‘ArrayFoo’: for _, item := range typedInput.ArrayFoo { var item1 Foo err := item1.PopulateFromARM(owner, item) @@ -298,6 +316,8 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know } fakeResourceSpec.ArrayFoo = append(fakeResourceSpec.ArrayFoo, item1) } + + // Set property ‘ArrayOfArrays’: for _, item := range typedInput.ArrayOfArrays { var itemTemp []Foo for _, item1 := range item { @@ -310,6 +330,8 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know } fakeResourceSpec.ArrayOfArrays = append(fakeResourceSpec.ArrayOfArrays, itemTemp) } + + // Set property ‘ArrayOfArraysOfArrays’: for _, item := range typedInput.ArrayOfArraysOfArrays { var itemTemp [][]Foo for _, item1 := range item { @@ -326,9 +348,13 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know } fakeResourceSpec.ArrayOfArraysOfArrays = append(fakeResourceSpec.ArrayOfArraysOfArrays, itemTemp) } + + // Set property ‘ArrayOfEnums’: for _, item := range typedInput.ArrayOfEnums { fakeResourceSpec.ArrayOfEnums = append(fakeResourceSpec.ArrayOfEnums, item) } + + // Set property ‘ArrayOfMaps’: for _, item := range typedInput.ArrayOfMaps { if item != nil { itemTemp := make(map[string]Foo) @@ -343,8 +369,14 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know fakeResourceSpec.ArrayOfMaps = append(fakeResourceSpec.ArrayOfMaps, itemTemp) } } + + // Set property ‘AzureName’: fakeResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: fakeResourceSpec.Owner = owner + + // No error return nil } @@ -371,6 +403,8 @@ func (foo *Foo) ConvertToARM(name string, resolvedReferences genruntime.Resolved return nil, nil } var result FooARM + + // Set property ‘Name’: if foo.Name != nil { name := *foo.Name result.Name = &name @@ -389,10 +423,14 @@ func (foo *Foo) PopulateFromARM(owner genruntime.KnownResourceReference, armInpu if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FooARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name foo.Name = &name } + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_complex_properties_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_complex_properties_azure.golden index bd2600822c9..74a10a21c1f 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_complex_properties_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_complex_properties_azure.golden @@ -219,17 +219,27 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef return nil, nil } var result FakeResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = FakeResourceSpecAPIVersion20200601 + + // Set property ‘Color’: if fakeResourceSpec.Color != nil { color := *fakeResourceSpec.Color result.Color = &color } + + // Set property ‘Foo’: fooARM, err := fakeResourceSpec.Foo.ConvertToARM(name, resolvedReferences) if err != nil { return nil, err } result.Foo = fooARM.(FooARM) + + // Set property ‘Name’: result.Name = name + + // Set property ‘OptionalFoo’: if fakeResourceSpec.OptionalFoo != nil { optionalFooARM, err := (*fakeResourceSpec.OptionalFoo).ConvertToARM(name, resolvedReferences) if err != nil { @@ -238,6 +248,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef optionalFoo := optionalFooARM.(FooARM) result.OptionalFoo = &optionalFoo } + + // Set property ‘Type’: result.Type = FakeResourceSpecTypeMicrosoftAzureFakeResource return result, nil } @@ -253,17 +265,25 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: fakeResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Color’: if typedInput.Color != nil { color := *typedInput.Color fakeResourceSpec.Color = &color } + + // Set property ‘Foo’: var foo Foo err := foo.PopulateFromARM(owner, typedInput.Foo) if err != nil { return err } fakeResourceSpec.Foo = foo + + // Set property ‘OptionalFoo’: if typedInput.OptionalFoo != nil { var optionalFoo1 Foo err = optionalFoo1.PopulateFromARM(owner, *typedInput.OptionalFoo) @@ -273,7 +293,11 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know optionalFoo := optionalFoo1 fakeResourceSpec.OptionalFoo = &optionalFoo } + + // Set property ‘Owner’: fakeResourceSpec.Owner = owner + + // No error return nil } @@ -300,6 +324,8 @@ func (foo *Foo) ConvertToARM(name string, resolvedReferences genruntime.Resolved return nil, nil } var result FooARM + + // Set property ‘Name’: if foo.Name != nil { name := *foo.Name result.Name = &name @@ -318,10 +344,14 @@ func (foo *Foo) PopulateFromARM(owner genruntime.KnownResourceReference, armInpu if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FooARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name foo.Name = &name } + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_json_fields_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_json_fields_azure.golden index dc2c6c2e087..1522b4da405 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_json_fields_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_json_fields_azure.golden @@ -213,19 +213,31 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef return nil, nil } var result FakeResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = FakeResourceSpecAPIVersion20200601 + + // Set property ‘JsonObject’: if fakeResourceSpec.JsonObject != nil { result.JsonObject = make(map[string]v1.JSON) for key, value := range fakeResourceSpec.JsonObject { result.JsonObject[key] = *value.DeepCopy() } } + + // Set property ‘MandatoryJson’: result.MandatoryJson = *fakeResourceSpec.MandatoryJson.DeepCopy() + + // Set property ‘Name’: result.Name = name + + // Set property ‘OptionalJson’: if fakeResourceSpec.OptionalJson != nil { optionalJson := *(*fakeResourceSpec.OptionalJson).DeepCopy() result.OptionalJson = &optionalJson } + + // Set property ‘Type’: result.Type = FakeResourceSpecTypeMicrosoftAzureFakeResource return result, nil } @@ -241,19 +253,31 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: fakeResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘JsonObject’: if typedInput.JsonObject != nil { fakeResourceSpec.JsonObject = make(map[string]v1.JSON) for key, value := range typedInput.JsonObject { fakeResourceSpec.JsonObject[key] = *value.DeepCopy() } } + + // Set property ‘MandatoryJson’: fakeResourceSpec.MandatoryJson = *typedInput.MandatoryJson.DeepCopy() + + // Set property ‘OptionalJson’: if typedInput.OptionalJson != nil { optionalJson := *(*typedInput.OptionalJson).DeepCopy() fakeResourceSpec.OptionalJson = &optionalJson } + + // Set property ‘Owner’: fakeResourceSpec.Owner = owner + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_map_properties_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_map_properties_azure.golden index 7a44fb3fb9c..698360bccc9 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_map_properties_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_map_properties_azure.golden @@ -228,7 +228,11 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef return nil, nil } var result FakeResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = FakeResourceSpecAPIVersion20200601 + + // Set property ‘MapFoo’: if fakeResourceSpec.MapFoo != nil { result.MapFoo = make(map[string]FooARM) for key, value := range fakeResourceSpec.MapFoo { @@ -239,6 +243,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef result.MapFoo[key] = valueARM.(FooARM) } } + + // Set property ‘MapOfArrays’: if fakeResourceSpec.MapOfArrays != nil { result.MapOfArrays = make(map[string][]FooARM) for key, value := range fakeResourceSpec.MapOfArrays { @@ -253,12 +259,16 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef result.MapOfArrays[key] = valueTemp } } + + // Set property ‘MapOfEnums’: if fakeResourceSpec.MapOfEnums != nil { result.MapOfEnums = make(map[string]Color) for key, value := range fakeResourceSpec.MapOfEnums { result.MapOfEnums[key] = value } } + + // Set property ‘MapOfMaps’: if fakeResourceSpec.MapOfMaps != nil { result.MapOfMaps = make(map[string]map[string]FooARM) for key, value := range fakeResourceSpec.MapOfMaps { @@ -275,6 +285,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef } } } + + // Set property ‘MapOfMapsOfMaps’: if fakeResourceSpec.MapOfMapsOfMaps != nil { result.MapOfMapsOfMaps = make(map[string]map[string]map[string]FooARM) for key, value := range fakeResourceSpec.MapOfMapsOfMaps { @@ -297,6 +309,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef } } } + + // Set property ‘MapOfMapsOfMapsOfStrings’: if fakeResourceSpec.MapOfMapsOfMapsOfStrings != nil { result.MapOfMapsOfMapsOfStrings = make(map[string]map[string]map[string]string) for key, value := range fakeResourceSpec.MapOfMapsOfMapsOfStrings { @@ -315,13 +329,19 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef } } } + + // Set property ‘MapOfStrings’: if fakeResourceSpec.MapOfStrings != nil { result.MapOfStrings = make(map[string]string) for key, value := range fakeResourceSpec.MapOfStrings { result.MapOfStrings[key] = value } } + + // Set property ‘Name’: result.Name = name + + // Set property ‘Type’: result.Type = FakeResourceSpecTypeMicrosoftAzureFakeResource return result, nil } @@ -337,7 +357,11 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: fakeResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘MapFoo’: if typedInput.MapFoo != nil { fakeResourceSpec.MapFoo = make(map[string]Foo) for key, value := range typedInput.MapFoo { @@ -349,6 +373,8 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know fakeResourceSpec.MapFoo[key] = value1 } } + + // Set property ‘MapOfArrays’: if typedInput.MapOfArrays != nil { fakeResourceSpec.MapOfArrays = make(map[string][]Foo) for key, value := range typedInput.MapOfArrays { @@ -364,12 +390,16 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know fakeResourceSpec.MapOfArrays[key] = valueTemp } } + + // Set property ‘MapOfEnums’: if typedInput.MapOfEnums != nil { fakeResourceSpec.MapOfEnums = make(map[string]Color) for key, value := range typedInput.MapOfEnums { fakeResourceSpec.MapOfEnums[key] = value } } + + // Set property ‘MapOfMaps’: if typedInput.MapOfMaps != nil { fakeResourceSpec.MapOfMaps = make(map[string]map[string]Foo) for key, value := range typedInput.MapOfMaps { @@ -387,6 +417,8 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know } } } + + // Set property ‘MapOfMapsOfMaps’: if typedInput.MapOfMapsOfMaps != nil { fakeResourceSpec.MapOfMapsOfMaps = make(map[string]map[string]map[string]Foo) for key, value := range typedInput.MapOfMapsOfMaps { @@ -410,6 +442,8 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know } } } + + // Set property ‘MapOfMapsOfMapsOfStrings’: if typedInput.MapOfMapsOfMapsOfStrings != nil { fakeResourceSpec.MapOfMapsOfMapsOfStrings = make(map[string]map[string]map[string]string) for key, value := range typedInput.MapOfMapsOfMapsOfStrings { @@ -428,13 +462,19 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know } } } + + // Set property ‘MapOfStrings’: if typedInput.MapOfStrings != nil { fakeResourceSpec.MapOfStrings = make(map[string]string) for key, value := range typedInput.MapOfStrings { fakeResourceSpec.MapOfStrings[key] = value } } + + // Set property ‘Owner’: fakeResourceSpec.Owner = owner + + // No error return nil } @@ -461,6 +501,8 @@ func (foo *Foo) ConvertToARM(name string, resolvedReferences genruntime.Resolved return nil, nil } var result FooARM + + // Set property ‘FooName’: if foo.FooName != nil { fooName := *foo.FooName result.FooName = &fooName @@ -479,10 +521,14 @@ func (foo *Foo) PopulateFromARM(owner genruntime.KnownResourceReference, armInpu if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FooARM, got %T", armInput) } + + // Set property ‘FooName’: if typedInput.FooName != nil { fooName := *typedInput.FooName foo.FooName = &fooName } + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_renders_spec_azure.golden b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_renders_spec_azure.golden index fa385248700..7de1070b5be 100644 --- a/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_renders_spec_azure.golden +++ b/hack/generator/pkg/codegen/testdata/ArmResource/Arm_test_simple_resource_renders_spec_azure.golden @@ -202,8 +202,14 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef return nil, nil } var result FakeResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = FakeResourceSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Type’: result.Type = FakeResourceSpecTypeMicrosoftAzureFakeResource return result, nil } @@ -219,8 +225,14 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: fakeResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: fakeResourceSpec.Owner = owner + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/EmbeddedTypes/Embedded_type_simple_resource.golden b/hack/generator/pkg/codegen/testdata/EmbeddedTypes/Embedded_type_simple_resource.golden index 496ff2685de..e197671944f 100644 --- a/hack/generator/pkg/codegen/testdata/EmbeddedTypes/Embedded_type_simple_resource.golden +++ b/hack/generator/pkg/codegen/testdata/EmbeddedTypes/Embedded_type_simple_resource.golden @@ -195,6 +195,8 @@ func (embeddedTestType *EmbeddedTestType) ConvertToARM(name string, resolvedRefe return nil, nil } var result EmbeddedTestTypeARM + + // Set property ‘FancyProp’: result.FancyProp = embeddedTestType.FancyProp return result, nil } @@ -210,7 +212,11 @@ func (embeddedTestType *EmbeddedTestType) PopulateFromARM(owner genruntime.Known if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected EmbeddedTestTypeARM, got %T", armInput) } + + // Set property ‘FancyProp’: embeddedTestType.FancyProp = typedInput.FancyProp + + // No error return nil } @@ -257,17 +263,27 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef return nil, nil } var result FakeResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = FakeResourceSpecAPIVersion20200601 + + // Set property ‘Color’: if fakeResourceSpec.Color != nil { color := *fakeResourceSpec.Color result.Color = &color } + + // Set property ‘Foo’: fooARM, err := fakeResourceSpec.Foo.ConvertToARM(name, resolvedReferences) if err != nil { return nil, err } result.Foo = fooARM.(FooARM) + + // Set property ‘Name’: result.Name = name + + // Set property ‘OptionalFoo’: if fakeResourceSpec.OptionalFoo != nil { optionalFooARM, err := (*fakeResourceSpec.OptionalFoo).ConvertToARM(name, resolvedReferences) if err != nil { @@ -276,6 +292,8 @@ func (fakeResourceSpec *FakeResource_Spec) ConvertToARM(name string, resolvedRef optionalFoo := optionalFooARM.(FooARM) result.OptionalFoo = &optionalFoo } + + // Set property ‘Type’: result.Type = FakeResourceSpecTypeMicrosoftAzureFakeResource return result, nil } @@ -291,17 +309,25 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FakeResource_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: fakeResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Color’: if typedInput.Color != nil { color := *typedInput.Color fakeResourceSpec.Color = &color } + + // Set property ‘Foo’: var foo Foo err := foo.PopulateFromARM(owner, typedInput.Foo) if err != nil { return err } fakeResourceSpec.Foo = foo + + // Set property ‘OptionalFoo’: if typedInput.OptionalFoo != nil { var optionalFoo1 Foo err = optionalFoo1.PopulateFromARM(owner, *typedInput.OptionalFoo) @@ -311,7 +337,11 @@ func (fakeResourceSpec *FakeResource_Spec) PopulateFromARM(owner genruntime.Know optionalFoo := optionalFoo1 fakeResourceSpec.OptionalFoo = &optionalFoo } + + // Set property ‘Owner’: fakeResourceSpec.Owner = owner + + // No error return nil } @@ -340,6 +370,8 @@ func (foo *Foo) ConvertToARM(name string, resolvedReferences genruntime.Resolved return nil, nil } var result FooARM + + // Set property ‘Name’: if foo.Name != nil { name := *foo.Name result.Name = &name @@ -358,10 +390,14 @@ func (foo *Foo) PopulateFromARM(owner genruntime.KnownResourceReference, armInpu if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected FooARM, got %T", armInput) } + + // Set property ‘Name’: if typedInput.Name != nil { name := *typedInput.Name foo.Name = &name } + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/EnumNames/Multi_valued_enum_name.golden b/hack/generator/pkg/codegen/testdata/EnumNames/Multi_valued_enum_name.golden index 209a165f2d2..83d578d2c61 100644 --- a/hack/generator/pkg/codegen/testdata/EnumNames/Multi_valued_enum_name.golden +++ b/hack/generator/pkg/codegen/testdata/EnumNames/Multi_valued_enum_name.golden @@ -202,8 +202,14 @@ func (aResourceSpec *AResource_Spec) ConvertToARM(name string, resolvedReference return nil, nil } var result AResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = AResourceSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Type’: result.Type = AResourceSpecTypeMicrosoftAzureAResource return result, nil } @@ -219,8 +225,14 @@ func (aResourceSpec *AResource_Spec) PopulateFromARM(owner genruntime.KnownResou if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected AResource_SpecARM, got %T", armInput) } + + // Set property ‘AzureName’: aResourceSpec.SetAzureName(genruntime.ExtractKubernetesResourceNameFromARMName(typedInput.Name)) + + // Set property ‘Owner’: aResourceSpec.Owner = owner + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/EnumNames/Single_valued_enum_name.golden b/hack/generator/pkg/codegen/testdata/EnumNames/Single_valued_enum_name.golden index 3ac48a5e931..1feea088612 100644 --- a/hack/generator/pkg/codegen/testdata/EnumNames/Single_valued_enum_name.golden +++ b/hack/generator/pkg/codegen/testdata/EnumNames/Single_valued_enum_name.golden @@ -196,8 +196,14 @@ func (aResourceSpec *AResource_Spec) ConvertToARM(name string, resolvedReference return nil, nil } var result AResource_SpecARM + + // Set property ‘APIVersion’: result.APIVersion = AResourceSpecAPIVersion20200601 + + // Set property ‘Name’: result.Name = name + + // Set property ‘Type’: result.Type = AResourceSpecTypeMicrosoftAzureAResource return result, nil } @@ -213,7 +219,11 @@ func (aResourceSpec *AResource_Spec) PopulateFromARM(owner genruntime.KnownResou if !ok { return fmt.Errorf("unexpected type supplied for PopulateFromARM() function. Expected AResource_SpecARM, got %T", armInput) } + + // Set property ‘Owner’: aResourceSpec.Owner = owner + + // No error return nil } diff --git a/hack/generator/pkg/codegen/testdata/Flattening/FlattenedPropertiesAreFlattened.golden b/hack/generator/pkg/codegen/testdata/Flattening/FlattenedPropertiesAreFlattened.golden new file mode 100644 index 00000000000..71bd8c06348 --- /dev/null +++ b/hack/generator/pkg/codegen/testdata/Flattening/FlattenedPropertiesAreFlattened.golden @@ -0,0 +1,16 @@ +// Code generated by azure-service-operator-codegen. DO NOT EDIT. +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +package v1alpha1api20200101 + +//Generated from: https://test.test/schemas/2020-01-01/test.json +type Test struct { + InnerFlat *Inner `json:"inner_flat,omitempty"` + InnerNotFlat *Inner `json:"inner_not_flat,omitempty"` +} + +//Generated from: https://test.test/schemas/2020-01-01/test.json#/definitions/Inner +type Inner struct { + Color *string `json:"color,omitempty"` + Name *string `json:"name,omitempty"` +} diff --git a/hack/generator/pkg/codegen/testdata/Flattening/FlattenedPropertiesAreFlattened.json b/hack/generator/pkg/codegen/testdata/Flattening/FlattenedPropertiesAreFlattened.json new file mode 100644 index 00000000000..6dc30050c76 --- /dev/null +++ b/hack/generator/pkg/codegen/testdata/Flattening/FlattenedPropertiesAreFlattened.json @@ -0,0 +1,30 @@ +{ + "$comment": "Check that flattened definitions are inlined into parent type", + "$TODO": "This does not actually work yet (gojsonschema does not expose the 'x-ms-client-flatten' property), but I wrote the test anyway so I have less work to do in the future!", + "id": "https://test.test/schemas/2020-01-01/test.json", + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "object", + "properties": { + "inner_flat": { + "x-ms-client-flatten": true, + "$ref": "#/definitions/Inner" + }, + "inner_not_flat": { + "$ref": "#/definitions/Inner" + } + }, + "definitions": { + "Inner": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "color" :{ + "type": "string" + } + } + } + } +} diff --git a/hack/generator/pkg/codegen/testdata/TestCodeGeneratorPipeline.golden b/hack/generator/pkg/codegen/testdata/TestCodeGeneratorPipeline.golden index 3f6abaf36a6..bbf8ebb3a29 100644 --- a/hack/generator/pkg/codegen/testdata/TestCodeGeneratorPipeline.golden +++ b/hack/generator/pkg/codegen/testdata/TestCodeGeneratorPipeline.golden @@ -1,9 +1,10 @@ Expected Pipeline Stages for Test Code Generation ------------------------------------------------- loadTestSchema Load and walk schema (test) -augmentStatus Add information from Swagger specs for 'status' fields +addStatusFromSwagger Add information from Swagger specs for 'status' fields allof-anyof-objects Convert allOf and oneOf to object types flattenResources Flatten nested resource types +augmentSpecWithStatus Merges information from Status into Spec stripUnused Strip unused types for test nameTypes Name inner types for CRD propertyRewrites Modify property types using configured transforms @@ -17,6 +18,7 @@ stripUnused Strip unused types for test replaceAnyTypeWithJSON Replace properties using interface{} with arbitrary JSON addCrossResourceReferences azure Replace cross-resource references with genruntime.ResourceReference applyKubernetesResourceInterface azure Add the KubernetesResource interface to every resource +flattenProperties Apply flattening to properties marked for flattening simplifyDefinitions Flatten definitions by removing wrapper types jsonTestCases azure Add test cases to verify JSON serialization markStorageVersion Mark the latest version of each resource as the storage version diff --git a/hack/generator/pkg/conversions/property_assignment_function.go b/hack/generator/pkg/conversions/property_assignment_function.go index d3a550b565d..442c5ea426d 100644 --- a/hack/generator/pkg/conversions/property_assignment_function.go +++ b/hack/generator/pkg/conversions/property_assignment_function.go @@ -154,7 +154,6 @@ func (fn *PropertyAssignmentFunction) Equals(f astmodel.Function) bool { // AsFunc renders this function as an AST for serialization to a Go source file func (fn *PropertyAssignmentFunction) AsFunc(generationContext *astmodel.CodeGenerationContext, receiver astmodel.TypeName) *dst.FuncDecl { - var description string switch fn.direction { case ConvertFrom: @@ -269,7 +268,6 @@ func (fn *PropertyAssignmentFunction) generateAssignments( // createConversions iterates through the properties on our receiver type, matching them up with // our other type and generating conversions where possible func (fn *PropertyAssignmentFunction) createConversions(receiver astmodel.TypeDefinition) error { - var sourceEndpoints map[string]ReadableConversionEndpoint var destinationEndpoints map[string]WritableConversionEndpoint @@ -292,7 +290,7 @@ func (fn *PropertyAssignmentFunction) createConversions(receiver astmodel.TypeDe sourceEndpoint, ok := sourceEndpoints[destinationName] if !ok { - //TODO: Handle property renames + // TODO: Handle property renames continue } @@ -384,7 +382,6 @@ func (fn *PropertyAssignmentFunction) createConversion( destinationEndpoint WritableConversionEndpoint) (StoragePropertyConversion, error) { conversion, err := CreateTypeConversion(sourceEndpoint.endpoint, destinationEndpoint.endpoint, fn.conversionContext) - if err != nil { return nil, errors.Wrapf( err, diff --git a/hack/generator/pkg/conversions/property_conversions.go b/hack/generator/pkg/conversions/property_conversions.go index e11f9f3d431..55ec6617f07 100644 --- a/hack/generator/pkg/conversions/property_conversions.go +++ b/hack/generator/pkg/conversions/property_conversions.go @@ -229,7 +229,6 @@ func assignFromOptional( local := sourceEndpoint.CreateLocal("", "Read") return func(reader dst.Expr, writer func(dst.Expr) []dst.Stmt, generationContext *astmodel.CodeGenerationContext) []dst.Stmt { - var cacheOriginal dst.Stmt var actualReader dst.Expr @@ -251,7 +250,7 @@ func assignFromOptional( actualReader = dst.NewIdent(local) } - checkForNil := astbuilder.NotEqual(actualReader, dst.NewIdent("nil")) + checkForNil := astbuilder.NotEqual(actualReader, astbuilder.Nil()) // If we have a value, need to convert it to our destination type writeActualValue := conversion( @@ -447,7 +446,6 @@ func assignFromAliasedPrimitive( } return func(reader dst.Expr, writer func(dst.Expr) []dst.Stmt, generationContext *astmodel.CodeGenerationContext) []dst.Stmt { - actualReader := &dst.CallExpr{ Fun: sourcePrimitive.AsType(generationContext), Args: []dst.Expr{reader}, @@ -490,7 +488,6 @@ func assignToAliasedPrimitive( } return func(reader dst.Expr, writer func(dst.Expr) []dst.Stmt, generationContext *astmodel.CodeGenerationContext) []dst.Stmt { - actualWriter := func(expr dst.Expr) []dst.Stmt { castToAlias := &dst.CallExpr{ Fun: destinationName.AsType(generationContext), @@ -833,7 +830,6 @@ func assignObjectFromObject( copyVar := destinationEndpoint.CreateLocal() return func(reader dst.Expr, writer func(dst.Expr) []dst.Stmt, generationContext *astmodel.CodeGenerationContext) []dst.Stmt { - // We have to do this at render time in order to ensure the first conversion generated // declares 'err', not a later one tok := token.ASSIGN @@ -866,7 +862,6 @@ func assignObjectFromObject( errLocal, tok, astbuilder.CallExpr(localId, functionName, actualReader)) - } else { // Destination is another type conversion = astbuilder.SimpleAssignment( diff --git a/hack/generator/pkg/jsonast/jsonast.go b/hack/generator/pkg/jsonast/jsonast.go index 54ef1673337..0991ded5072 100644 --- a/hack/generator/pkg/jsonast/jsonast.go +++ b/hack/generator/pkg/jsonast/jsonast.go @@ -509,6 +509,9 @@ func getProperties( property = property.WithDescription(*propSchema.description()) } + // add flattening + property = property.SetFlatten(propSchema.extensions("x-ms-client-flatten") == true) + // add validations isRequired := false for _, required := range schema.requiredProperties() { diff --git a/hack/generator/pkg/jsonast/schema_abstraction.go b/hack/generator/pkg/jsonast/schema_abstraction.go index 35b58acacfb..8246d5c7aeb 100644 --- a/hack/generator/pkg/jsonast/schema_abstraction.go +++ b/hack/generator/pkg/jsonast/schema_abstraction.go @@ -23,7 +23,7 @@ type Schema interface { description() *string // for extensions like x-ms-... - extensions() map[string]interface{} + extensions(key string) interface{} hasType(schemaType SchemaType) bool diff --git a/hack/generator/pkg/jsonast/schema_abstraction_gojson.go b/hack/generator/pkg/jsonast/schema_abstraction_gojson.go index e37b241ddc4..b575f06ea01 100644 --- a/hack/generator/pkg/jsonast/schema_abstraction_gojson.go +++ b/hack/generator/pkg/jsonast/schema_abstraction_gojson.go @@ -44,7 +44,7 @@ func (schema GoJSONSchema) title() *string { return schema.inner.Title } -func (schema GoJSONSchema) extensions() map[string]interface{} { +func (schema GoJSONSchema) extensions(key string) interface{} { return nil } @@ -215,7 +215,7 @@ func groupOf(url *url.URL) (string, error) { file := pathParts[len(pathParts)-1] if !strings.HasSuffix(file, ".json") { - return "", errors.Errorf("Unexpected URL format (doesn't point to .json file)") + return "", errors.Errorf("unexpected URL format (doesn't point to .json file)") } return strings.TrimSuffix(file, ".json"), nil diff --git a/hack/generator/pkg/jsonast/schema_abstraction_openapi.go b/hack/generator/pkg/jsonast/schema_abstraction_openapi.go index bb7fe932eb3..17fc0cc266e 100644 --- a/hack/generator/pkg/jsonast/schema_abstraction_openapi.go +++ b/hack/generator/pkg/jsonast/schema_abstraction_openapi.go @@ -253,8 +253,13 @@ func (schema *OpenAPISchema) enumValues() []string { return enumValuesToLiterals(schema.inner.Enum) } -func (schema *OpenAPISchema) extensions() map[string]interface{} { - return schema.inner.Extensions +func (schema *OpenAPISchema) extensions(key string) interface{} { + exts := schema.inner.Extensions + if exts == nil { + return nil + } + + return exts[key] } func (schema *OpenAPISchema) isRef() bool { diff --git a/hack/generator/pkg/jsonast/swagger_type_extractor.go b/hack/generator/pkg/jsonast/swagger_type_extractor.go index afd55064576..aea2e1cf01b 100644 --- a/hack/generator/pkg/jsonast/swagger_type_extractor.go +++ b/hack/generator/pkg/jsonast/swagger_type_extractor.go @@ -186,7 +186,7 @@ func isMarkedAsARMResource(schema Schema) bool { var recurse func(schema Schema) bool recurse = func(schema Schema) bool { - if schema.extensions()["x-ms-azure-resource"] == true { + if schema.extensions("x-ms-azure-resource") == true { return true } diff --git a/hack/generator/pkg/testcases/object_type_serialization_test_case.go b/hack/generator/pkg/testcases/object_type_serialization_test_case.go index 2e4cfde1b82..8972d3c4cff 100644 --- a/hack/generator/pkg/testcases/object_type_serialization_test_case.go +++ b/hack/generator/pkg/testcases/object_type_serialization_test_case.go @@ -58,7 +58,6 @@ func (o ObjectSerializationTestCase) References() astmodel.TypeNameSet { // subject is the name of the type under test // codeGenerationContext contains reference material to use when generating func (o ObjectSerializationTestCase) AsFuncs(name astmodel.TypeName, genContext *astmodel.CodeGenerationContext) []dst.Decl { - var errs []error properties := o.makePropertyMap() @@ -78,14 +77,14 @@ func (o ObjectSerializationTestCase) AsFuncs(name astmodel.TypeName, genContext // Write errors for any properties we don't handle for _, p := range properties { - errs = append(errs, errors.Errorf("No generator created for %v (%v)", p.PropertyName(), p.PropertyType())) + errs = append(errs, errors.Errorf("no generator created for %v (%v)", p.PropertyName(), p.PropertyType())) } var result []dst.Decl if len(simpleGenerators) == 0 && len(relatedGenerators) == 0 { // No properties that we can generate to test - skip the testing completely - errs = append(errs, errors.Errorf("No property generators for %v", name)) + errs = append(errs, errors.Errorf("no property generators for %v", name)) } else { result = append(result, o.createTestRunner(genContext), @@ -154,7 +153,6 @@ func (o ObjectSerializationTestCase) Equals(_ astmodel.TestCase) bool { // createTestRunner generates the AST for the test runner itself func (o ObjectSerializationTestCase) createTestRunner(codegenContext *astmodel.CodeGenerationContext) dst.Decl { - const ( parametersLocal = "parameters" propertiesLocal = "properties" @@ -175,11 +173,9 @@ func (o ObjectSerializationTestCase) createTestRunner(codegenContext *astmodel.C astbuilder.CallQualifiedFunc(gopterPackage, "DefaultTestParameters")) // parameters.MaxSize = 10 - configureMaxSize := astbuilder.SimpleAssignment( - &dst.SelectorExpr{ - X: dst.NewIdent(parametersLocal), - Sel: dst.NewIdent("MaxSize"), - }, + configureMaxSize := astbuilder.QualifiedAssignment( + dst.NewIdent(parametersLocal), + "MaxSize", token.ASSIGN, astbuilder.IntLiteral(10)) @@ -354,7 +350,6 @@ func (o ObjectSerializationTestCase) createGeneratorDeclaration(genContext *astm // createGeneratorMethod generates the AST for a method used to populate our generator cache variable on demand func (o ObjectSerializationTestCase) createGeneratorMethod(ctx *astmodel.CodeGenerationContext, haveSimpleGenerators bool, haveRelatedGenerators bool) dst.Decl { - gopterPackage := ctx.MustGetImportedPackageName(astmodel.GopterReference) genPackage := ctx.MustGetImportedPackageName(astmodel.GopterGenReference) @@ -607,7 +602,7 @@ func (o ObjectSerializationTestCase) createRelatedGenerator( return astbuilder.CallQualifiedFunc(importName, o.idOfGeneratorMethod(t)) } - //TODO: Should we invoke a generator for stuff from our runtime package? + // TODO: Should we invoke a generator for stuff from our runtime package? return nil diff --git a/workspace.code-workspace b/workspace.code-workspace index c2c635747fc..df3e872839f 100644 --- a/workspace.code-workspace +++ b/workspace.code-workspace @@ -10,5 +10,9 @@ "path": "hack/generator" } ], - "settings": {} + "settings": { + "gopls": { + "formatting.local": "github.com/Azure/azure-service-operator" + } + } }