Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update OAM Network using oam API #305

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 172 additions & 11 deletions controllers/platformnetwork_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/starlingx/inventory/v1/addresspools"
"github.com/gophercloud/gophercloud/starlingx/inventory/v1/networks"
"github.com/gophercloud/gophercloud/starlingx/inventory/v1/oamNetworks"
perrors "github.com/pkg/errors"
starlingxv1 "github.com/wind-river/cloud-platform-deployment-manager/api/v1"
utils "github.com/wind-river/cloud-platform-deployment-manager/common"
Expand All @@ -30,6 +31,8 @@ import (

var logPlatformNetwork = log.Log.WithName("controller").WithName("platformnetwork")

var SUBCLOUD_WRITABLE_NETWORK_TYPES = []string{"admin"}

const PlatformNetworkControllerName = "platformnetwork-controller"

const PlatformNetworkFinalizerName = "platformnetwork.finalizers.windriver.com"
Expand Down Expand Up @@ -84,6 +87,62 @@ func compareRangeArrays(x, y [][]string) bool {
return len(x) == count
}

// oamUpdateRequired determines whether a oam network resource must
// be updated to align with the stored value. Only the updated fields are
// include in the request options to minimum churn and to ease debugging.
func oamUpdateRequired(instance *starlingxv1.PlatformNetwork, p *oamNetworks.OAMNetwork, r *PlatformNetworkReconciler) (opts oamNetworks.OAMNetworkOpts, result bool) {
var delta strings.Builder

spec := instance.Spec
instance_subnet := fmt.Sprintf("%s/%d", spec.Subnet, spec.Prefix)
if instance_subnet != p.OAMSubnet {
opts.OAMSubnet = &instance_subnet
delta.WriteString(fmt.Sprintf("\t+Subnet: %s\n", *opts.OAMSubnet))
result = true
}

if instance.Spec.Type != networks.NetworkTypeOther {
// TODO(alegacy): There is a sysinv bug in how the gateway address
// gets registered in the database. It doesn't have a "name" and
// so causes an exception when a related route is added.
if spec.Gateway != nil && (p.OAMGatewayIP == nil || !strings.EqualFold(*spec.Gateway, *p.OAMGatewayIP)) {
opts.OAMGatewayIP = spec.Gateway
delta.WriteString(fmt.Sprintf("\t+Gateway: %s\n", *opts.OAMGatewayIP))
result = true
}
}

if spec.FloatingAddress != "" && spec.FloatingAddress != p.OAMFloatingIP {
opts.OAMFloatingIP = &spec.FloatingAddress
delta.WriteString(fmt.Sprintf("\t+Floating Address: %s\n", *opts.OAMFloatingIP))
result = true
}

tempRange := [][]string{{p.OAMStartIP, p.OAMEndIP}}
if len(spec.Allocation.Ranges) > 0 {
ranges := makeRangeArray(spec.Allocation.Ranges)
if !compareRangeArrays(ranges, tempRange) {
opts.OAMStartIP = &ranges[0][0]
opts.OAMEndIP = &ranges[0][1]
delta.WriteString(fmt.Sprintf("\t+Start IP: %s\n", *opts.OAMStartIP))
delta.WriteString(fmt.Sprintf("\t+End IP: %s\n", *opts.OAMEndIP))
result = true
}
}
deltaString := delta.String()
if deltaString != "" {
deltaString = "\n" + strings.TrimSuffix(deltaString, "\n")
logPlatformNetwork.Info(fmt.Sprintf("delta configuration:%s\n", deltaString))
}

instance.Status.Delta = deltaString
err := r.Client.Status().Update(context.TODO(), instance)
if err != nil {
logPlatformNetwork.Info(fmt.Sprintf("failed to update oam status: %s\n", err))
}
return opts, result
}

// poolUpdateRequired determines whether a system address pool resource must
// be updated to align with the stored value. Only the updated fields are
// include in the request options to minimum churn and to ease debugging.
Expand All @@ -108,6 +167,12 @@ func poolUpdateRequired(instance *starlingxv1.PlatformNetwork, p *addresspools.A
result = true
}

if spec.FloatingAddress != "" && spec.FloatingAddress != p.FloatingAddress {
opts.FloatingAddress = &spec.FloatingAddress
delta.WriteString(fmt.Sprintf("\t+Floating Address: %s\n", *opts.FloatingAddress))
result = true
}

if instance.Spec.Type != networks.NetworkTypeOther {
// TODO(alegacy): There is a sysinv bug in how the gateway address
// gets registered in the database. It doesn't have a "name" and
Expand Down Expand Up @@ -148,6 +213,26 @@ func poolUpdateRequired(instance *starlingxv1.PlatformNetwork, p *addresspools.A
return opts, result
}

func poolOptsCreation(instance *starlingxv1.PlatformNetwork) (opts addresspools.AddressPoolOpts) {
opts.Name = &instance.Name

spec := instance.Spec
opts.Network = &spec.Subnet
opts.Prefix = &spec.Prefix
opts.FloatingAddress = &spec.FloatingAddress
opts.Gateway = spec.Gateway
if spec.Allocation.Order != nil {
opts.Order = spec.Allocation.Order
}

if len(spec.Allocation.Ranges) > 0 {
ranges := makeRangeArray(spec.Allocation.Ranges)
opts.Ranges = &ranges
}

return opts
}

// ReconcileNew is a method which handles reconciling a new data resource and
// creates the corresponding system resource thru the system API.
func (r *PlatformNetworkReconciler) ReconcileNewAddressPool(client *gophercloud.ServiceClient, instance *starlingxv1.PlatformNetwork) (*addresspools.AddressPool, error) {
Expand Down Expand Up @@ -200,8 +285,8 @@ func (r *PlatformNetworkReconciler) ReconcileNewAddressPool(client *gophercloud.
// ReconcileUpdated is a method which handles reconciling an existing data
Copy link
Collaborator

@yjian118 yjian118 Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description need to be allocated at the right function, expecting description to the new function as well

// resource and updates the corresponding system resource thru the system API to
// match the desired state of the resource.
func (r *PlatformNetworkReconciler) ReconcileUpdatedAddressPool(client *gophercloud.ServiceClient, instance *starlingxv1.PlatformNetwork, pool *addresspools.AddressPool) error {
if opts, ok := poolUpdateRequired(instance, pool, r); ok {
func (r *PlatformNetworkReconciler) ReconcileUpdatedOAMNetwork(client *gophercloud.ServiceClient, instance *starlingxv1.PlatformNetwork, oam *oamNetworks.OAMNetwork) error {
if opts, ok := oamUpdateRequired(instance, oam, r); ok {
if instance.Status.Reconciled && r.StopAfterInSync() {
// Do not process any further changes once we have reached a
// synchronized state unless there is an annotation on the resource.
Expand All @@ -214,24 +299,88 @@ func (r *PlatformNetworkReconciler) ReconcileUpdatedAddressPool(client *gophercl
}
}

// Update existing pool
logPlatformNetwork.Info("updating address pool", "uuid", pool.ID, "opts", opts)
// Update existing oam network
logPlatformNetwork.Info("updating oam network", "uuid", oam.UUID, "opts", opts)

result, err := addresspools.Update(client, pool.ID, opts).Extract()
result, err := oamNetworks.Update(client, oam.UUID, opts).Extract()
if err != nil {
err = perrors.Wrapf(err, "failed to update pool: %+v", opts)
err = perrors.Wrapf(err, "failed to update oam network: %+v", opts)
return err
}

*pool = *result
*oam = *result

r.ReconcilerEventLogger.NormalEvent(instance, common.ResourceUpdated,
"address pool has been updated")
"oam network has been updated")

}

return nil
}

func (r *PlatformNetworkReconciler) ReconcileUpdatedAddressPool(client *gophercloud.ServiceClient, instance *starlingxv1.PlatformNetwork, pool *addresspools.AddressPool) (*addresspools.AddressPool, error) {
if opts, ok := poolUpdateRequired(instance, pool, r); ok {
if instance.Status.Reconciled && r.StopAfterInSync() {
// Do not process any further changes once we have reached a
// synchronized state unless there is an annotation on the resource.
if _, present := instance.Annotations[cloudManager.ReconcileAfterInSync]; !present {
msg := common.NoChangesAfterReconciled
r.ReconcilerEventLogger.NormalEvent(instance, common.ResourceUpdated, msg)
return pool, common.NewChangeAfterInSync(msg)
} else {
logPlatformNetwork.Info(common.ChangedAllowedAfterReconciled)
}
}

createAddressPool := false
for _, t := range SUBCLOUD_WRITABLE_NETWORK_TYPES {
if t == instance.Spec.Type {
createAddressPool = true
break
}
}

if createAddressPool {
newOpts := poolOptsCreation(instance)

// Update existing pool
logPlatformNetwork.Info("Deleting address pool", "uuid", pool.ID, "opts", opts)
err := addresspools.Delete(client, pool.ID).ExtractErr()

if err != nil {
err = perrors.Wrapf(err, "failed to delete pool: %+v", opts)
return pool, err
}

logPlatformNetwork.Info("Creating address pool", "opts", opts)

result, err := addresspools.Create(client, newOpts).Extract()
if err != nil {
err = perrors.Wrapf(err, "failed to create pool: %+v", opts)
return pool, err
}
*pool = *result
r.ReconcilerEventLogger.NormalEvent(instance, common.ResourceUpdated,
"address pool has been created")
} else {
// Update existing pool
logPlatformNetwork.Info("updating address pool", "uuid", pool.ID, "opts", opts)

result, err := addresspools.Update(client, pool.ID, opts).Extract()
if err != nil {
err = perrors.Wrapf(err, "failed to update pool: %+v", opts)
return pool, err
}
*pool = *result
r.ReconcilerEventLogger.NormalEvent(instance, common.ResourceUpdated,
"address pool has been updated")
}

}

return pool, nil
}

// ReconcileNew is a method which handles reconciling a new data resource and
// creates the corresponding system resource thru the system API.
func (r *PlatformNetworkReconciler) ReconciledDeletedAddressPool(client *gophercloud.ServiceClient, instance *starlingxv1.PlatformNetwork, pool *addresspools.AddressPool) error {
Expand Down Expand Up @@ -276,7 +425,7 @@ func (r *PlatformNetworkReconciler) FindExistingAddressPool(client *gophercloud.

// The resource may have been deleted by the system or operator
// therefore continue and attempt to recreate it.
logPlatformNetwork.Info("resource no longer exists", "id", *id)
logPlatformNetwork.Info("address pool no longer exists", "id", *id)
return nil, nil
}

Expand Down Expand Up @@ -317,8 +466,20 @@ func (r *PlatformNetworkReconciler) ReconcileAddressPool(client *gophercloud.Ser
} else {
if pool == nil {
pool, err = r.ReconcileNewAddressPool(client, instance)
} else if instance.Spec.Type == "oam" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I prefer to use Constant for "oam" but not mandatory

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll handle this in a follow-up commit when we create and manage the other networks (admin, mgmt). Is that okay?

oamNetworkList, err := oamNetworks.ListNetworks(client)
if err != nil {
err = perrors.Wrapf(err, "failed to get oam network")
return err
}
oamNetwork := &oamNetworkList[0]
err = r.ReconcileUpdatedOAMNetwork(client, instance, oamNetwork)

if err != nil {
return err
}
} else {
err = r.ReconcileUpdatedAddressPool(client, instance, pool)
pool, err = r.ReconcileUpdatedAddressPool(client, instance, pool)
}

if err == nil && pool != nil {
Expand Down Expand Up @@ -484,7 +645,7 @@ func (r *PlatformNetworkReconciler) FindExistingNetwork(client *gophercloud.Serv

// The resource may have been deleted by the system or operator
// therefore continue and attempt to recreate it.
logPlatformNetwork.Info("resource no longer exists", "id", *id)
logPlatformNetwork.Info("network no longer exists", "id", *id)
return nil, nil
}

Expand Down
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ require (
github.com/fsnotify/fsnotify v1.5.1
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v1.2.0
github.com/google/go-cmp v0.5.9
github.com/gophercloud/gophercloud v0.0.0-20230605171524-742ad279b1e1
github.com/google/go-cmp v0.6.0
github.com/gophercloud/gophercloud v1.8.0
github.com/imdario/mergo v0.3.12
github.com/mitchellh/go-homedir v1.1.0
github.com/onsi/ginkgo v1.16.5
Expand Down Expand Up @@ -92,4 +92,5 @@ require (
)

// replace github.com/gophercloud/gophercloud => ./external/gophercloud
replace github.com/gophercloud/gophercloud => github.com/Wind-River/gophercloud v0.0.0-20231201194816-936d2409d43d

replace github.com/gophercloud/gophercloud => github.com/Wind-River/gophercloud v0.0.0-20231207152242-d06bd3ca4f52
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMo
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Wind-River/gophercloud v0.0.0-20231201194816-936d2409d43d h1:RR0Kb4wIXRqMGGO2KulSlkQynEKzz7hOlvpUDbxC3CY=
github.com/Wind-River/gophercloud v0.0.0-20231201194816-936d2409d43d/go.mod h1:KIxeLfVGmfRky0V1QAj7pJqsM3/UI7xLQEpDgXZWh4I=
github.com/Wind-River/gophercloud v0.0.0-20231207152242-d06bd3ca4f52 h1:2iH3Zf7+cIvhkDtHqenBaM44YHtmoaHwpItcPNtF790=
github.com/Wind-River/gophercloud v0.0.0-20231207152242-d06bd3ca4f52/go.mod h1:vVDhU9TrWNFfORJV7Tvx7UXsu/ImDlVeHhQCdrbzLEA=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
Expand Down Expand Up @@ -229,8 +229,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand Down