diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index da07b7eee..7a2b155ed 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -36,7 +36,9 @@ jobs:
with:
enable_workaround_docker_io: 'false'
branch: ${{ matrix.openstack_version }}
- enabled_services: "openstack-cli-server"
+ enabled_services: "openstack-cli-server,neutron-uplink-status-propagation"
+ conf_overrides: |
+ enable_plugin neutron https://opendev.org/openstack/neutron.git ${{ matrix.openstack_version }}
- name: Deploy a Kind Cluster
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
diff --git a/api/v1alpha1/port_types.go b/api/v1alpha1/port_types.go
index 9e51d0153..055e1855e 100644
--- a/api/v1alpha1/port_types.go
+++ b/api/v1alpha1/port_types.go
@@ -185,6 +185,12 @@ type PortResourceSpec struct {
// +kubebuilder:validation:MaxLength=36
// +optional
HostID string `json:"hostID,omitempty"`
+
+ // propagateUplinkStatus represents the uplink status propagation of
+ // the port.
+ // +optional
+ // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="propagateUplinkStatus is immutable"
+ PropagateUplinkStatus *bool `json:"propagateUplinkStatus,omitempty"`
}
type PortResourceStatus struct {
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 74fd9dcdf..28a9f0c77 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -2529,6 +2529,11 @@ func (in *PortResourceSpec) DeepCopyInto(out *PortResourceSpec) {
*out = new(KubernetesNameRef)
**out = **in
}
+ if in.PropagateUplinkStatus != nil {
+ in, out := &in.PropagateUplinkStatus, &out.PropagateUplinkStatus
+ *out = new(bool)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortResourceSpec.
diff --git a/cmd/models-schema/zz_generated.openapi.go b/cmd/models-schema/zz_generated.openapi.go
index 3b90d275e..1beb237d8 100644
--- a/cmd/models-schema/zz_generated.openapi.go
+++ b/cmd/models-schema/zz_generated.openapi.go
@@ -4918,6 +4918,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref c
Format: "",
},
},
+ "propagateUplinkStatus": {
+ SchemaProps: spec.SchemaProps{
+ Description: "propagateUplinkStatus represents the uplink status propagation of the port.",
+ Type: []string{"boolean"},
+ Format: "",
+ },
+ },
},
Required: []string{"networkRef"},
},
diff --git a/config/crd/bases/openstack.k-orc.cloud_ports.yaml b/config/crd/bases/openstack.k-orc.cloud_ports.yaml
index c14173d71..1bc2ea45c 100644
--- a/config/crd/bases/openstack.k-orc.cloud_ports.yaml
+++ b/config/crd/bases/openstack.k-orc.cloud_ports.yaml
@@ -347,6 +347,14 @@ spec:
x-kubernetes-validations:
- message: projectRef is immutable
rule: self == oldSelf
+ propagateUplinkStatus:
+ description: |-
+ propagateUplinkStatus represents the uplink status propagation of
+ the port.
+ type: boolean
+ x-kubernetes-validations:
+ - message: propagateUplinkStatus is immutable
+ rule: self == oldSelf
securityGroupRefs:
description: |-
securityGroupRefs are the names of the security groups associated
diff --git a/internal/controllers/port/actuator.go b/internal/controllers/port/actuator.go
index 822f6a5be..cc26b393a 100644
--- a/internal/controllers/port/actuator.go
+++ b/internal/controllers/port/actuator.go
@@ -171,12 +171,13 @@ func (actuator portActuator) CreateResource(ctx context.Context, obj *orcv1alpha
}
createOpts := ports.CreateOpts{
- NetworkID: *network.Status.ID,
- Name: getResourceName(obj),
- Description: string(ptr.Deref(resource.Description, "")),
- ProjectID: projectID,
- AdminStateUp: resource.AdminStateUp,
- MACAddress: resource.MACAddress,
+ NetworkID: *network.Status.ID,
+ Name: getResourceName(obj),
+ Description: string(ptr.Deref(resource.Description, "")),
+ ProjectID: projectID,
+ AdminStateUp: resource.AdminStateUp,
+ MACAddress: resource.MACAddress,
+ PropagateUplinkStatus: resource.PropagateUplinkStatus,
}
if len(resource.AllowedAddressPairs) > 0 {
diff --git a/internal/controllers/port/status.go b/internal/controllers/port/status.go
index 379e91e70..221f0dcf0 100644
--- a/internal/controllers/port/status.go
+++ b/internal/controllers/port/status.go
@@ -67,7 +67,6 @@ func (portStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResou
WithNetworkID(osResource.NetworkID).
WithTags(osResource.Tags...).
WithSecurityGroups(osResource.SecurityGroups...).
- WithPropagateUplinkStatus(osResource.PropagateUplinkStatus).
WithVNICType(osResource.VNICType).
WithPortSecurityEnabled(osResource.PortSecurityEnabled).
WithRevisionNumber(int64(osResource.RevisionNumber)).
@@ -104,5 +103,9 @@ func (portStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResou
resourceStatus.WithFixedIPs(fixedIPs...)
}
+ if osResource.PropagateUplinkStatusPtr != nil {
+ resourceStatus.WithPropagateUplinkStatus(*osResource.PropagateUplinkStatusPtr)
+ }
+
statusApply.WithResource(resourceStatus)
}
diff --git a/internal/controllers/port/tests/port-create-full/00-create-resource.yaml b/internal/controllers/port/tests/port-create-full/00-create-resource.yaml
index bbb52641d..22c97ca52 100644
--- a/internal/controllers/port/tests/port-create-full/00-create-resource.yaml
+++ b/internal/controllers/port/tests/port-create-full/00-create-resource.yaml
@@ -86,3 +86,4 @@ spec:
projectRef: port-create-full
macAddress: fa:16:3e:23:fd:d7
hostID: devstack
+ propagateUplinkStatus: false
diff --git a/internal/controllers/port/tests/port-create-minimal/00-assert.yaml b/internal/controllers/port/tests/port-create-minimal/00-assert.yaml
index 9c6d861fc..ba68844fe 100644
--- a/internal/controllers/port/tests/port-create-minimal/00-assert.yaml
+++ b/internal/controllers/port/tests/port-create-minimal/00-assert.yaml
@@ -8,7 +8,7 @@ status:
name: port-create-minimal
adminStateUp: true
portSecurityEnabled: true
- propagateUplinkStatus: false
+ propagateUplinkStatus: true
revisionNumber: 1
status: DOWN
vnicType: normal
diff --git a/internal/controllers/port/tests/port-create-sriov/00-assert.yaml b/internal/controllers/port/tests/port-create-sriov/00-assert.yaml
index 3277dfaea..180f4a512 100644
--- a/internal/controllers/port/tests/port-create-sriov/00-assert.yaml
+++ b/internal/controllers/port/tests/port-create-sriov/00-assert.yaml
@@ -9,7 +9,7 @@ status:
description: Port from "create sriov" test
adminStateUp: true
portSecurityEnabled: false
- propagateUplinkStatus: false
+ propagateUplinkStatus: true
status: DOWN
vnicType: direct
tags:
@@ -35,4 +35,4 @@ assertAll:
- celExpr: "port.status.resource.fixedIPs[0].subnetID == subnet.status.id"
- celExpr: "port.status.resource.fixedIPs[0].ip == '192.168.155.122'"
- celExpr: "!has(port.status.resource.allowedAddressPairs)"
- - celExpr: "!has(port.status.resource.securityGroups)"
\ No newline at end of file
+ - celExpr: "!has(port.status.resource.securityGroups)"
diff --git a/internal/controllers/port/tests/port-update/00-assert.yaml b/internal/controllers/port/tests/port-update/00-assert.yaml
index 6ec7e451d..836189292 100644
--- a/internal/controllers/port/tests/port-update/00-assert.yaml
+++ b/internal/controllers/port/tests/port-update/00-assert.yaml
@@ -30,7 +30,7 @@ status:
name: port-update
adminStateUp: true
portSecurityEnabled: false
- propagateUplinkStatus: false
+ propagateUplinkStatus: true
revisionNumber: 1
status: DOWN
vnicType: normal
@@ -53,7 +53,7 @@ status:
name: port-update-admin
adminStateUp: true
portSecurityEnabled: true
- propagateUplinkStatus: false
+ propagateUplinkStatus: true
revisionNumber: 1
status: DOWN
vnicType: normal
diff --git a/internal/controllers/port/tests/port-update/01-assert.yaml b/internal/controllers/port/tests/port-update/01-assert.yaml
index 1bcaf2d7f..a751a1cdd 100644
--- a/internal/controllers/port/tests/port-update/01-assert.yaml
+++ b/internal/controllers/port/tests/port-update/01-assert.yaml
@@ -34,7 +34,6 @@ status:
description: port-update-updated
adminStateUp: true
portSecurityEnabled: true
- propagateUplinkStatus: false
status: DOWN
vnicType: direct
allowedAddressPairs:
@@ -63,4 +62,4 @@ status:
reason: Success
- type: Progressing
status: "False"
- reason: Success
+ reason: Success
diff --git a/internal/controllers/port/tests/port-update/02-assert.yaml b/internal/controllers/port/tests/port-update/02-assert.yaml
index 314caa5b0..ec19a5fd8 100644
--- a/internal/controllers/port/tests/port-update/02-assert.yaml
+++ b/internal/controllers/port/tests/port-update/02-assert.yaml
@@ -24,7 +24,7 @@ status:
name: port-update
adminStateUp: true
portSecurityEnabled: false
- propagateUplinkStatus: false
+ propagateUplinkStatus: true
status: DOWN
vnicType: normal
conditions:
@@ -35,4 +35,4 @@ status:
- type: Progressing
message: OpenStack resource is up to date
status: "False"
- reason: Success
\ No newline at end of file
+ reason: Success
diff --git a/internal/osclients/networking.go b/internal/osclients/networking.go
index 99156d64e..69b6cf753 100644
--- a/internal/osclients/networking.go
+++ b/internal/osclients/networking.go
@@ -52,10 +52,19 @@ type NetworkExt struct {
provider.NetworkProviderExt
}
+// NOTE(winiciusallan): This is a temporary extension struct to
+// workaround a missing pointer on Gophercloud and must be
+// removed in future releases.
+// See https://github.com/gophercloud/gophercloud/issues/3605
+type PortTmpExt struct {
+ PropagateUplinkStatusPtr *bool `json:"propagate_uplink_status,omitempty"`
+}
+
type PortExt struct {
ports.Port
portsecurity.PortSecurityExt
portsbinding.PortsBindingExt
+ PortTmpExt //nolint:govet
}
type NetworkClient interface {
diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/portresourcespec.go
index aab07d8bc..a157e70ff 100644
--- a/pkg/clients/applyconfiguration/api/v1alpha1/portresourcespec.go
+++ b/pkg/clients/applyconfiguration/api/v1alpha1/portresourcespec.go
@@ -25,19 +25,20 @@ import (
// PortResourceSpecApplyConfiguration represents a declarative configuration of the PortResourceSpec type for use
// with apply.
type PortResourceSpecApplyConfiguration struct {
- Name *apiv1alpha1.OpenStackName `json:"name,omitempty"`
- Description *apiv1alpha1.NeutronDescription `json:"description,omitempty"`
- NetworkRef *apiv1alpha1.KubernetesNameRef `json:"networkRef,omitempty"`
- Tags []apiv1alpha1.NeutronTag `json:"tags,omitempty"`
- AllowedAddressPairs []AllowedAddressPairApplyConfiguration `json:"allowedAddressPairs,omitempty"`
- Addresses []AddressApplyConfiguration `json:"addresses,omitempty"`
- AdminStateUp *bool `json:"adminStateUp,omitempty"`
- SecurityGroupRefs []apiv1alpha1.OpenStackName `json:"securityGroupRefs,omitempty"`
- VNICType *string `json:"vnicType,omitempty"`
- PortSecurity *apiv1alpha1.PortSecurityState `json:"portSecurity,omitempty"`
- ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"`
- MACAddress *string `json:"macAddress,omitempty"`
- HostID *string `json:"hostID,omitempty"`
+ Name *apiv1alpha1.OpenStackName `json:"name,omitempty"`
+ Description *apiv1alpha1.NeutronDescription `json:"description,omitempty"`
+ NetworkRef *apiv1alpha1.KubernetesNameRef `json:"networkRef,omitempty"`
+ Tags []apiv1alpha1.NeutronTag `json:"tags,omitempty"`
+ AllowedAddressPairs []AllowedAddressPairApplyConfiguration `json:"allowedAddressPairs,omitempty"`
+ Addresses []AddressApplyConfiguration `json:"addresses,omitempty"`
+ AdminStateUp *bool `json:"adminStateUp,omitempty"`
+ SecurityGroupRefs []apiv1alpha1.OpenStackName `json:"securityGroupRefs,omitempty"`
+ VNICType *string `json:"vnicType,omitempty"`
+ PortSecurity *apiv1alpha1.PortSecurityState `json:"portSecurity,omitempty"`
+ ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"`
+ MACAddress *string `json:"macAddress,omitempty"`
+ HostID *string `json:"hostID,omitempty"`
+ PropagateUplinkStatus *bool `json:"propagateUplinkStatus,omitempty"`
}
// PortResourceSpecApplyConfiguration constructs a declarative configuration of the PortResourceSpec type for use with
@@ -163,3 +164,11 @@ func (b *PortResourceSpecApplyConfiguration) WithHostID(value string) *PortResou
b.HostID = &value
return b
}
+
+// WithPropagateUplinkStatus sets the PropagateUplinkStatus field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the PropagateUplinkStatus field is set to the value of the last call.
+func (b *PortResourceSpecApplyConfiguration) WithPropagateUplinkStatus(value bool) *PortResourceSpecApplyConfiguration {
+ b.PropagateUplinkStatus = &value
+ return b
+}
diff --git a/pkg/clients/applyconfiguration/internal/internal.go b/pkg/clients/applyconfiguration/internal/internal.go
index abaeca27f..b6805275f 100644
--- a/pkg/clients/applyconfiguration/internal/internal.go
+++ b/pkg/clients/applyconfiguration/internal/internal.go
@@ -1351,6 +1351,9 @@ var schemaYAML = typed.YAMLObject(`types:
- name: projectRef
type:
scalar: string
+ - name: propagateUplinkStatus
+ type:
+ scalar: boolean
- name: securityGroupRefs
type:
list:
diff --git a/website/docs/crd-reference.md b/website/docs/crd-reference.md
index 32018f962..ae1df1118 100644
--- a/website/docs/crd-reference.md
+++ b/website/docs/crd-reference.md
@@ -2172,6 +2172,7 @@ _Appears in:_
| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
|
| `macAddress` _string_ | macAddress is the MAC address of the port. | | MaxLength: 32
|
| `hostID` _string_ | hostID is the ID of host where the port resides. | | MaxLength: 36
|
+| `propagateUplinkStatus` _boolean_ | propagateUplinkStatus represents the uplink status propagation of
the port. | | |
#### PortResourceStatus