Skip to content
Open
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
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,13 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform

.PHONY: manifests
manifests: gowork controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases && \
$(CONTROLLER_GEN) crd webhook paths="./api/nova/..." paths="./api/placement/..." paths="./internal/webhook/nova/..." paths="./internal/webhook/placement/..." output:crd:artifacts:config=config/crd/bases output:webhook:artifacts:config=config/webhook && \
$(CONTROLLER_GEN) rbac:roleName=manager-role paths="./..." output:dir=config/rbac && \
rm -f api/bases/* && cp -a config/crd/bases api/

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./api/nova/..." paths="./api/placement/..."

.PHONY: fmt
fmt: ## Run go fmt against code.
Expand Down Expand Up @@ -147,10 +148,12 @@ PROCS?=$(shell expr $(shell nproc --ignore 2) / 2)
PROC_CMD = --procs ${PROCS}

.PHONY: test
# TODO: Currently runs all tests (Nova + Placement). In future, optimize CI to run only tests
# for the operator code that changed (e.g., skip Placement tests if only Nova code changed).
test: manifests generate fmt vet envtest ginkgo ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) -v debug --bin-dir $(LOCALBIN) use $(ENVTEST_K8S_VERSION) -p path)" \
OPERATOR_TEMPLATES="$(PWD)/templates" \
$(GINKGO) --trace --cover --coverpkg=../../internal/...,../../api/nova/v1beta1 --coverprofile cover.out --covermode=atomic --randomize-all ${PROC_CMD} $(GINKGO_ARGS) ./test/...
$(GINKGO) --trace --cover --coverpkg=../../internal/...,../../api/nova/v1beta1,../../api/placement/v1beta1 --coverprofile cover.out --covermode=atomic --randomize-all ${PROC_CMD} $(GINKGO_ARGS) ./test/...

##@ Build

Expand Down
502 changes: 502 additions & 0 deletions api/bases/placement.openstack.org_placementapis.yaml

Large diffs are not rendered by default.

259 changes: 259 additions & 0 deletions api/placement/v1beta1/api_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
/*
Copyright 2022.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1beta1

import (
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
"github.com/openstack-k8s-operators/lib-common/modules/common/service"
"github.com/openstack-k8s-operators/lib-common/modules/common/tls"
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
)

const (
// DbSyncHash hash
DbSyncHash = "dbsync"

// DeploymentHash hash used to detect changes
DeploymentHash = "deployment"

// Container image fall-back defaults

// PlacementAPIContainerImage is the fall-back container image for PlacementAPI
PlacementAPIContainerImage = "quay.io/podified-antelope-centos9/openstack-placement-api:current-podified"
)

// PlacementAPISpec defines the desired state of PlacementAPI
type PlacementAPISpec struct {
PlacementAPISpecCore `json:",inline"`

// +kubebuilder:validation:Required
// PlacementAPI Container Image URL (will be set to environmental default if empty)
ContainerImage string `json:"containerImage"`
}

// PlacementAPISpecCore -
type PlacementAPISpecCore struct {
// +kubebuilder:validation:Optional
// +kubebuilder:default=60
// +kubebuilder:validation:Minimum=10
// APITimeout for HAProxy, Apache
APITimeout int `json:"apiTimeout"`

// +kubebuilder:validation:Optional
// +kubebuilder:default=placement
// ServiceUser - optional username used for this service to register in keystone
ServiceUser string `json:"serviceUser"`

// +kubebuilder:validation:Required
// MariaDB instance name
// Right now required by the maridb-operator to get the credentials from the instance to create the DB
// Might not be required in future
DatabaseInstance string `json:"databaseInstance"`

// +kubebuilder:validation:Optional
// +kubebuilder:default=placement
// DatabaseAccount - name of MariaDBAccount which will be used to connect.
DatabaseAccount string `json:"databaseAccount"`

// +kubebuilder:validation:Optional
// +kubebuilder:default=1
// +kubebuilder:validation:Maximum=32
// +kubebuilder:validation:Minimum=0
// Replicas of placement API to run
Replicas *int32 `json:"replicas"`

// +kubebuilder:validation:Required
// Secret containing OpenStack password information for placement PlacementPassword
Secret string `json:"secret"`

// +kubebuilder:validation:Optional
// +kubebuilder:default={service: PlacementPassword}
// PasswordSelectors - Selectors to identify the DB and ServiceUser password from the Secret
PasswordSelectors PasswordSelector `json:"passwordSelectors"`

// +kubebuilder:validation:Optional
// NodeSelector to target subset of worker nodes running this service
NodeSelector *map[string]string `json:"nodeSelector,omitempty"`

// +kubebuilder:validation:Optional
// +kubebuilder:default=false
// PreserveJobs - do not delete jobs after they finished e.g. to check logs
PreserveJobs bool `json:"preserveJobs"`

// +kubebuilder:validation:Optional
// CustomServiceConfig - customize the service config using this parameter to change service defaults,
// or overwrite rendered information using raw OpenStack config format. The content gets added to
// to /etc/<service>/<service>.conf.d directory as custom.conf file.
CustomServiceConfig string `json:"customServiceConfig"`

// +kubebuilder:validation:Optional
// DefaultConfigOverwrite - interface to overwrite default config files like policy.yaml.
DefaultConfigOverwrite map[string]string `json:"defaultConfigOverwrite,omitempty"`

// +kubebuilder:validation:Optional
// Resources - Compute Resources required by this service (Limits/Requests).
// https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
Resources corev1.ResourceRequirements `json:"resources,omitempty"`

// +kubebuilder:validation:Optional
// NetworkAttachments is a list of NetworkAttachment resource names to expose the services to the given network
NetworkAttachments []string `json:"networkAttachments,omitempty"`

// +kubebuilder:validation:Optional
// Override, provides the ability to override the generated manifest of several child resources.
Override APIOverrideSpec `json:"override,omitempty"`

// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec
// TLS - Parameters related to the TLS
TLS tls.API `json:"tls,omitempty"`

// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec
// Auth - Parameters related to authentication
Auth AuthSpec `json:"auth,omitempty"`

// +kubebuilder:validation:Optional
// TopologyRef to apply the Topology defined by the associated CR referenced
// by name
TopologyRef *topologyv1.TopoRef `json:"topologyRef,omitempty"`
}

// APIOverrideSpec to override the generated manifest of several child resources.
type APIOverrideSpec struct {
// Override configuration for the Service created to serve traffic to the cluster.
// The key must be the endpoint type (public, internal)
Service map[service.Endpoint]service.RoutedOverrideSpec `json:"service,omitempty"`
}

// AuthSpec defines authentication parameters
type AuthSpec struct {
// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec
// ApplicationCredentialSecret - Secret containing Application Credential ID and Secret
ApplicationCredentialSecret string `json:"applicationCredentialSecret,omitempty"`
}

// PasswordSelector to identify the DB and AdminUser password from the Secret
type PasswordSelector struct {
// +kubebuilder:validation:Optional
// +kubebuilder:default="PlacementPassword"
// Service - Selector to get the service user password from the Secret
Service string `json:"service"`
}

// PlacementAPIStatus defines the observed state of PlacementAPI
type PlacementAPIStatus struct {
// ReadyCount of placement API instances
ReadyCount int32 `json:"readyCount,omitempty"`

// Map of hashes to track e.g. job status
Hash map[string]string `json:"hash,omitempty"`

// Conditions
Conditions condition.Conditions `json:"conditions,omitempty" optional:"true"`

// Placement Database Hostname
DatabaseHostname string `json:"databaseHostname,omitempty"`

// NetworkAttachments status of the deployment pods
NetworkAttachments map[string][]string `json:"networkAttachments,omitempty"`

//ObservedGeneration - the most recent generation observed for this service. If the observed generation is less than the spec generation, then the controller has not processed the latest changes.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`

// LastAppliedTopology - the last applied Topology
LastAppliedTopology *topologyv1.TopoRef `json:"lastAppliedTopology,omitempty"`
}

// PlacementAPI is the Schema for the placementapis API
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="NetworkAttachments",type="string",JSONPath=".spec.networkAttachments",description="NetworkAttachments"
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[0].status",description="Status"
// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[0].message",description="Message"
type PlacementAPI struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec PlacementAPISpec `json:"spec,omitempty"`
Status PlacementAPIStatus `json:"status,omitempty"`
}

// PlacementAPIList contains a list of PlacementAPI
// +kubebuilder:object:root=true
type PlacementAPIList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []PlacementAPI `json:"items"`
}

func init() {
SchemeBuilder.Register(&PlacementAPI{}, &PlacementAPIList{})
}

// IsReady - returns true if PlacementAPI is reconciled successfully
func (instance PlacementAPI) IsReady() bool {
return instance.Status.Conditions.IsTrue(condition.ReadyCondition)
}

// RbacConditionsSet - set the conditions for the rbac object
func (instance PlacementAPI) RbacConditionsSet(c *condition.Condition) {
instance.Status.Conditions.Set(c)
}

// RbacNamespace - return the namespace
func (instance PlacementAPI) RbacNamespace() string {
return instance.Namespace
}

// RbacResourceName - return the name to be used for rbac objects (serviceaccount, role, rolebinding)
func (instance PlacementAPI) RbacResourceName() string {
return "placement-" + instance.Name
}

// SetupDefaults - initializes any CRD field defaults based on environment variables (the defaulting mechanism itself is implemented via webhooks)
func SetupDefaults() {
// Acquire environmental defaults and initialize Placement defaults with them
placementDefaults := PlacementAPIDefaults{
ContainerImageURL: util.GetEnvVar("RELATED_IMAGE_PLACEMENT_API_IMAGE_URL_DEFAULT", PlacementAPIContainerImage),
APITimeout: 60,
}

SetupPlacementAPIDefaults(placementDefaults)
}

// GetSecret returns the value of the Nova.Spec.Secret
func (instance PlacementAPI) GetSecret() string {
return instance.Spec.Secret
}

// ValidateTopology -
func (instance *PlacementAPISpecCore) ValidateTopology(
basePath *field.Path,
namespace string,
) field.ErrorList {
var allErrs field.ErrorList
allErrs = append(allErrs, topologyv1.ValidateTopologyRef(
instance.TopologyRef,
*basePath.Child("topologyRef"), namespace)...)
return allErrs
}
Loading
Loading