Skip to content

Commit

Permalink
Merge pull request #515 from stuggi/v1.2.x_backports
Browse files Browse the repository at this point in the history
v1.2.x - various backports
  • Loading branch information
stuggi authored Feb 22, 2022
2 parents cc15a6e + 0f7e680 commit 6a5a0f3
Show file tree
Hide file tree
Showing 111 changed files with 6,058 additions and 732 deletions.
22 changes: 10 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,15 @@ Create a base RHEL data volume prior to deploying OpenStack. This will be used
- macPrefix: fa:16:3b
name: datacentre2
# optional: configure static mapping for the networks per nodes. If there is none, a random gets created
staticReservations:
controller-0:
reservations:
datacentre: fa:16:3a:aa:aa:aa
datacentre2: fa:16:3b:aa:aa:aa
compute-0:
reservations:
datacentre: fa:16:3a:bb:bb:bb
datacentre2: fa:16:3b:bb:bb:bb
reservations:
controller-0:
macReservations:
datacentre: fa:16:3a:aa:aa:aa
datacentre2: fa:16:3b:aa:aa:aa
compute-0:
macReservations:
datacentre: fa:16:3a:bb:bb:bb
datacentre2: fa:16:3b:bb:bb:bb
```

If you write the above YAML into a file called networkconfig.yaml you can create the OpenStackNetConfig via this command:
Expand Down Expand Up @@ -842,7 +842,6 @@ oc patch osbms computehci --type=merge --patch '{"spec":{"count":1}}'
```

As a result:
* the corresponding OSIPSet for the node gets deleted
* the IPreservation entry in the OSNet resources gets flagged as deleted

```bash
Expand Down Expand Up @@ -915,7 +914,6 @@ oc patch osctlplane overcloud --type=merge --patch '{"spec":{"virtualMachineRole
```

As a result:
* the corresponding OSIPSet for the node got deleted
* the IPreservation entry in the OSNet resources is flagged as deleted

This results in the following behavior
Expand Down Expand Up @@ -1559,7 +1557,7 @@ If required it is possible to change CPU/RAM of an openstackvmset configured via

* change/patch the virtualMachineRole within the virtualMachineRoles list of the openstackcontrolplane CR

E.g. to change the controller virtualMachineRole to have 8 cores and 21GB of RAM:
E.g. to change the controller virtualMachineRole to have 8 cores and 22GB of RAM:

```bash
oc patch -n openstack osctlplane overcloud --type='json' -p='[{"op": "add", "path": "/spec/virtualMachineRoles/controller/cores", "value": 8 }]'
Expand Down
2 changes: 1 addition & 1 deletion api/v1beta1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ func (conditions ConditionList) InitCondition() *Condition {
}
}

return cond
return cond.DeepCopy()
}

// GetCurrentCondition - Get current condition with status == corev1.ConditionTrue
Expand Down
28 changes: 28 additions & 0 deletions api/v1beta1/openstackephemeralheat_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,36 @@ type OpenStackEphemeralHeatSpec struct {
type OpenStackEphemeralHeatStatus struct {
// Active hash
Active bool `json:"active"`

// Conditions - conditions to display in the OpenShift GUI, which reflect CurrentState
Conditions ConditionList `json:"conditions,omitempty" optional:"true"`
}

const (
//
// condition reasons
//

// EphemeralHeatCondGenPassSecretError - error generating password secret
EphemeralHeatCondGenPassSecretError ConditionReason = "EphemeralHeatCondGenPassSecretError"
// EphemeralHeatCondWaitOnPassSecret - waiting for the generated password secret to populate
EphemeralHeatCondWaitOnPassSecret ConditionReason = "EphemeralHeatCondWaitOnPassSecret"
// EphemeralHeatCondMariaDBError - error creating/updating MariaDB pod or service
EphemeralHeatCondMariaDBError ConditionReason = "EphemeralHeatCondMariaDBError"
// EphemeralHeatCondWaitOnMariaDB - waiting for MariaDB pod to be ready
EphemeralHeatCondWaitOnMariaDB ConditionReason = "EphemeralHeatCondWaitOnMariaDB"
// EphemeralHeatCondRabbitMQError - error creating/updating RabbitMQ pod or service
EphemeralHeatCondRabbitMQError ConditionReason = "EphemeralHeatCondRabbitMQError"
// EphemeralHeatCondWaitOnRabbitMQ - waiting for RabbitMQ pod to be ready
EphemeralHeatCondWaitOnRabbitMQ ConditionReason = "EphemeralHeatCondWaitOnRabbitMQ"
// EphemeralHeatCondHeatError - error creating/updating Heat pod or service
EphemeralHeatCondHeatError ConditionReason = "EphemeralHeatCondHeatError"
// EphemeralHeatCondWaitOnHeat - waiting for Heat pod to be ready
EphemeralHeatCondWaitOnHeat ConditionReason = "EphemeralHeatCondWaitOnHeat"
// EphemeralHeatReady - Heat is available for use
EphemeralHeatReady ConditionReason = "EphemeralHeatReady"
)

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:shortName=osephemeralheat;osephemeralheats
Expand Down
25 changes: 15 additions & 10 deletions api/v1beta1/openstacknetconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,6 @@ type Network struct {
// +kubebuilder:default=true
// VIP create virtual ip on the network
VIP bool `json:"vip"`

/*
// +kubebuilder:validation:Optional
// StaticReservations, manual/static IP address reservations per node
StaticReservations map[string]OpenStackMACNodeReservation `json:"staticReservations"`
*/
}

// OpenStackNetConfigSpec defines the desired state of OpenStackNetConfig
Expand Down Expand Up @@ -151,17 +145,28 @@ type OpenStackNetConfigSpec struct {
// but the role itself is not deleted. The reservations of all nodes in the role get deleted when the full node
// role is being deleted. (default: true)
PreserveReservations *bool `json:"preserveReservations"`

// +kubebuilder:validation:Optional
// Reservations, manual/static MAC/IP address reservations per node
Reservations map[string]OpenStackNetStaticNodeReservations `json:"reservations"`
}

// OpenStackNetStaticNodeReservations defines the static reservations of the nodes
type OpenStackNetStaticNodeReservations struct {
// +kubebuilder:validation:Optional
// IPReservations, manual/static IP address reservations per network
IPReservations map[string]string `json:"ipReservations"`

// +kubebuilder:validation:Optional
// MACReservations, manual/static MAC address reservations per physnet
MACReservations map[string]string `json:"macReservations"`
}

// OVNBridgeMacMappingConfig defines the desired state of OpenStackMACAddress
type OVNBridgeMacMappingConfig struct {
// +kubebuilder:validation:MinItems=1
// PhysNetworks - physical networks list to create MAC addresses per physnet per node to create OVNStaticBridgeMacMappings
PhysNetworks []Physnet `json:"physNetworks"`

// +kubebuilder:validation:Optional
// StaticReservations, manual/static MAC address reservations per node
StaticReservations map[string]OpenStackMACNodeReservation `json:"staticReservations"`
}

// OpenStackNetConfigStatus defines the observed state of OpenStackNetConfig
Expand Down
146 changes: 140 additions & 6 deletions api/v1beta1/openstacknetconfig_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ limitations under the License.
package v1beta1

import (
"context"
"fmt"
"net"

nmstate "github.com/openstack-k8s-operators/osp-director-operator/pkg/nmstate"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)
Expand All @@ -32,6 +34,11 @@ var openstacknetconfiglog = logf.Log.WithName("openstacknetconfig-resource")

// SetupWebhookWithManager - register this webhook with the controller manager
func (r *OpenStackNetConfig) SetupWebhookWithManager(mgr ctrl.Manager) error {

if webhookClient == nil {
webhookClient = mgr.GetClient()
}

return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
Expand Down Expand Up @@ -78,8 +85,20 @@ func (r *OpenStackNetConfig) Default() {
},
}
}
if r.Spec.OVNBridgeMacMappings.StaticReservations == nil {
r.Spec.OVNBridgeMacMappings.StaticReservations = map[string]OpenStackMACNodeReservation{}

if r.Spec.Reservations == nil {
r.Spec.Reservations = map[string]OpenStackNetStaticNodeReservations{}
} else {
for node, res := range r.Spec.Reservations {
if res.IPReservations == nil {
res.IPReservations = map[string]string{}
}
if res.MACReservations == nil {
res.MACReservations = map[string]string{}
}

r.Spec.Reservations[node] = res
}
}

if r.Spec.PreserveReservations == nil {
Expand Down Expand Up @@ -126,6 +145,14 @@ func (r *OpenStackNetConfig) ValidateCreate() error {
return err
}

//
// Validate static IP address reservations
//
err = r.validateStaticIPReservations()
if err != nil {
return err
}

//
// Validate static MAC address reservations
//
Expand All @@ -149,6 +176,14 @@ func (r *OpenStackNetConfig) ValidateUpdate(old runtime.Object) error {
return err
}

//
// Validate static IP address reservations
//
err = r.validateStaticIPReservations()
if err != nil {
return err
}

//
// Validate static MAC address reservations
//
Expand Down Expand Up @@ -222,8 +257,8 @@ func (r *OpenStackNetConfig) validateStaticMacReservations(old runtime.Object) e
// fill an empty reservations map to check for uniq MAC reservations
reservations := map[string]OpenStackMACNodeReservation{}

for node, res := range r.Spec.OVNBridgeMacMappings.StaticReservations {
for physnet, mac := range res.Reservations {
for node, res := range r.Spec.Reservations {
for physnet, mac := range res.MACReservations {
//
// check if the MAC address has a valid format
//
Expand All @@ -247,14 +282,113 @@ func (r *OpenStackNetConfig) validateStaticMacReservations(old runtime.Object) e
if oldInstance, ok = old.(*OpenStackNetConfig); !ok {
return fmt.Errorf("runtime object is not an OpenStackNetConfig")
}
if currentMAC, ok := oldInstance.Spec.OVNBridgeMacMappings.StaticReservations[node].Reservations[physnet]; ok && currentMAC != mac {
if currentMAC, ok := oldInstance.Spec.Reservations[node].MACReservations[physnet]; ok && currentMAC != mac {
return fmt.Errorf("MAC address %s of node %s must not change - new MAC address %s", currentMAC, node, mac)
}
}
}

// if all tests pass add to reservations
reservations[node] = res
reservations[node] = OpenStackMACNodeReservation{
Reservations: res.MACReservations,
}
}

return nil
}

// validateStaticIPReservations - validate static IP address reservations
func (r *OpenStackNetConfig) validateStaticIPReservations() error {
// fill an empty reservations map to check for uniq IP reservations
reservations := map[string]string{}

//
// Create nested map with per net, ip -> node name reservations
//
osNetList := &OpenStackNetList{}

listOpts := []client.ListOption{
client.InNamespace(r.Namespace),
}

if err := webhookClient.List(context.TODO(), osNetList, listOpts...); err != nil {
return err
}

netReservations := map[string]map[string]string{}
for _, osNet := range osNetList.Items {
if netReservations[osNet.Spec.NameLower] == nil {
netReservations[osNet.Spec.NameLower] = map[string]string{}
}
for node, res := range osNet.Status.Reservations {
netReservations[osNet.Spec.NameLower][res.IP] = node
}
}

//
// verify all the Spec.Reservations provided
//
for node, res := range r.Spec.Reservations {
for netName, resIP := range res.IPReservations {
//
// check if the IP address has a valid format
//
ip := net.ParseIP(resIP)
if ip == nil {
return fmt.Errorf("IP address %s of node %s has an invalid format", resIP, node)
}

//
// check if IP matches osnet spec
//
for _, osNet := range r.Spec.Networks {
for _, subnet := range osNet.Subnets {
if subnet.Name == netName {
var ipnet *net.IPNet
if subnet.IPv4.Cidr != "" {
_, ipnet, _ = net.ParseCIDR(subnet.IPv4.Cidr)
} else {
_, ipnet, _ = net.ParseCIDR(subnet.IPv6.Cidr)
}

if !ipnet.Contains(ip) {
return fmt.Errorf("IP address %s of node %s conflicts with subnet %s definition %s",
resIP,
node,
netName,
ipnet.Network(),
)
}
}
}
}

//
// check for duplicate reservations on static reservations
//
if resNode, ok := reservations[resIP]; ok && resNode != node {
return fmt.Errorf("IP address %s of node %s is not uniq. Already used by %s",
resIP,
node,
resNode,
)
}

//
// check for duplicate reservations on all active reservations
//
if resNode, ok := netReservations[netName][resIP]; ok && resNode != node {
return fmt.Errorf("IP address %s of node %s is not uniq. Already used by %s",
resIP,
node,
resNode,
)
}

// if all tests pass add to reservations
reservations[resIP] = node
}
}

return nil
}
22 changes: 17 additions & 5 deletions api/v1beta1/openstackprovisionserver_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,29 @@ const (
ProvisionServerCondTypeError ProvisioningState = "Error"

//
// condition reasones
// condition reasons
//

// OpenStackProvisionServerCondReasonListError - osprovserver list objects error
OpenStackProvisionServerCondReasonListError ConditionReason = "OpenStackProvisionServerListError"
// OpenStackProvisionServerCondReasonGetError - osprovserver list objects error
OpenStackProvisionServerCondReasonGetError ConditionReason = "OpenStackProvisionServerCondReasonGetError"
// OpenStackProvisionServerCondReasonNotFound - osprovserver object not found
OpenStackProvisionServerCondReasonNotFound ConditionReason = "OpenStackProvisionServerNotFound"
// OpenStackProvisionServerCondReasonNotReady - osprovserver not yet ready
OpenStackProvisionServerCondReasonNotReady ConditionReason = "OpenStackProvisionServerNotReady"
// OpenStackProvisionServerCondReasonReady - osprovserver ready
OpenStackProvisionServerCondReasonReady ConditionReason = "OpenStackProvisionServerReady"
// OpenStackProvisionServerCondReasonInterfaceAcquireError - osprovserver hit an error while finding provisioning interface name
OpenStackProvisionServerCondReasonInterfaceAcquireError ConditionReason = "OpenStackProvisionServerCondReasonInterfaceAcquireError"
// OpenStackProvisionServerCondReasonInterfaceNotFound - osprovserver unable to find provisioning interface name
OpenStackProvisionServerCondReasonInterfaceNotFound ConditionReason = "OpenStackProvisionServerCondReasonInterfaceNotFound"
// OpenStackProvisionServerCondReasonDeploymentError - osprovserver associated deployment failed to create/update
OpenStackProvisionServerCondReasonDeploymentError ConditionReason = "OpenStackProvisionServerCondReasonDeploymentError"
// OpenStackProvisionServerCondReasonDeploymentCreated - osprovserver associated deployment has been created/update
OpenStackProvisionServerCondReasonDeploymentCreated ConditionReason = "OpenStackProvisionServerCondReasonDeploymentCreated"
// OpenStackProvisionServerCondReasonProvisioning - osprovserver associated pod is provisioning
OpenStackProvisionServerCondReasonProvisioning ConditionReason = "OpenStackProvisionServerCondReasonProvisioning"
// OpenStackProvisionServerCondReasonLocalImageURLParseError - osprovserver was unable to parse its received local image URL
OpenStackProvisionServerCondReasonLocalImageURLParseError ConditionReason = "OpenStackProvisionServerCondReasonLocalImageURLParseError"
// OpenStackProvisionServerCondReasonProvisioned - osprovserver associated pod is provisioned
OpenStackProvisionServerCondReasonProvisioned ConditionReason = "OpenStackProvisionServerCondReasonProvisioned"
// OpenStackProvisionServerCondReasonCreateError - error creating osprov server object
OpenStackProvisionServerCondReasonCreateError ConditionReason = "OpenStackProvisionServerCreateError"
// OpenStackProvisionServerCondReasonCreated - osprov server object created
Expand Down
2 changes: 1 addition & 1 deletion api/v1beta1/openstackvmset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ const (
// VMSetCondReasonVirtualMachineDeprovisioning - virtual machine deprovisioning in progress
VMSetCondReasonVirtualMachineDeprovisioning ConditionReason = "VirtualMachineDeprovisioning"
// VMSetCondReasonVirtualMachineProvisioned - virtual machines provisioned
VMSetCondReasonVirtualMachineProvisioned ConditionReason = "VirtualMachineProvisioed"
VMSetCondReasonVirtualMachineProvisioned ConditionReason = "VirtualMachineProvisioned"
// VMSetCondReasonVirtualMachineCountZero - no virtual machines requested
VMSetCondReasonVirtualMachineCountZero ConditionReason = "VirtualMachineCountZero"

Expand Down
Loading

0 comments on commit 6a5a0f3

Please sign in to comment.