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

feat: Implement config pod status #3544

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
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
4 changes: 4 additions & 0 deletions apis/config/v1alpha1/config_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.
package v1alpha1

import (
status "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
"github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -82,6 +83,7 @@ type ReadinessSpec struct {

// ConfigStatus defines the observed state of Config.
type ConfigStatus struct { // Important: Run "make" to regenerate code after modifying this file
ByPod []status.ConfigPodStatusStatus `json:"byPod,omitempty"`
}

type GVK struct {
Expand All @@ -92,6 +94,8 @@ type GVK struct {

// +kubebuilder:resource:scope=Namespaced
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:storageversion

// Config is the Schema for the configs API.
type Config struct {
Expand Down
10 changes: 9 additions & 1 deletion apis/config/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 86 additions & 0 deletions apis/status/v1beta1/configpodstatus_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package v1beta1

import (
"github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
"github.com/open-policy-agent/gatekeeper/v3/pkg/util"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

// ConfigPodStatusStatus defines the observed state of ConfigPodStatus.

// +kubebuilder:object:generate=true

type ConfigPodStatusStatus struct {
ID string `json:"id,omitempty"`
ConfigUID types.UID `json:"configUID,omitempty"`
Operations []string `json:"operations,omitempty"`
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
Errors []*ConfigError `json:"errors,omitempty"`
}

// +kubebuilder:object:generate=true

type ConfigError struct {
Type string `json:"type,omitempty"`
Message string `json:"message"`
}

// ConfigPodStatus is the Schema for the configpodstatuses API.

// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Namespaced

type ConfigPodStatus struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Status ConfigPodStatusStatus `json:"status,omitempty"`
}

// ConfigPodStatusList contains a list of ConfigPodStatus.

// +kubebuilder:object:root=true
type ConfigPodStatusList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ConfigPodStatus `json:"items"`
}

func init() {
SchemeBuilder.Register(&ConfigPodStatus{}, &ConfigPodStatusList{})
}

// NewConfigStatusForPod returns an config status object
// that has been initialized with the bare minimum of fields to make it functional
// with the config status controller.
func NewConfigStatusForPod(pod *corev1.Pod, configName string, scheme *runtime.Scheme) (*ConfigPodStatus, error) {
obj := &ConfigPodStatus{}
name, err := KeyForConfig(pod.Name, configName)
if err != nil {
return nil, err
}
obj.SetName(name)
obj.SetNamespace(util.GetNamespace())
obj.Status.ID = pod.Name
obj.Status.Operations = operations.AssignedStringList()
obj.SetLabels(map[string]string{
ConfigNameLabel: configName,
PodLabel: pod.Name,
})

if err := controllerutil.SetOwnerReference(pod, obj, scheme); err != nil {
return nil, err
}

return obj, nil
}

// KeyForConfig returns a unique status object name given the Pod ID and
// a config object.
func KeyForConfig(id string, configName string) (string, error) {
return DashPacker(id, configName)
}
68 changes: 68 additions & 0 deletions apis/status/v1beta1/configpodstatus_types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package v1beta1_test

import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
"github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
"github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
"github.com/open-policy-agent/gatekeeper/v3/test/testutils"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

func TestNewConfigStatusForPod(t *testing.T) {
const podName = "some-gk-pod"
const podNS = "a-gk-namespace"
const configName = "a-config"

testutils.Setenv(t, "POD_NAMESPACE", podNS)

scheme := runtime.NewScheme()
err := v1beta1.AddToScheme(scheme)
if err != nil {
t.Fatal(err)
}

err = corev1.AddToScheme(scheme)
if err != nil {
t.Fatal(err)
}

pod := fakes.Pod(
fakes.WithNamespace(podNS),
fakes.WithName(podName),
)

expectedStatus := &v1beta1.ConfigPodStatus{}
expectedStatus.SetName("some--gk--pod-a--config")
expectedStatus.SetNamespace(podNS)
expectedStatus.Status.ID = podName
expectedStatus.Status.Operations = operations.AssignedStringList()
expectedStatus.SetLabels(map[string]string{
v1beta1.ConfigNameLabel: configName,
v1beta1.PodLabel: podName,
})

err = controllerutil.SetOwnerReference(pod, expectedStatus, scheme)
if err != nil {
t.Fatal(err)
}

status, err := v1beta1.NewConfigStatusForPod(pod, configName, scheme)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(expectedStatus, status); diff != "" {
t.Fatal(diff)
}
n, err := v1beta1.KeyForConfig(podName, configName)
if err != nil {
t.Fatal(err)
}
if status.Name != n {
t.Fatal("got status.Name != n, want equal")
}
}
1 change: 1 addition & 0 deletions apis/status/v1beta1/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package v1beta1

// Label keys used for internal gatekeeper operations.
const (
ConfigNameLabel = "internal.gatekeeper.sh/config-name"
ExpansionTemplateNameLabel = "internal.gatekeeper.sh/expansiontemplate-name"
ConstraintNameLabel = "internal.gatekeeper.sh/constraint-name"
ConstraintKindLabel = "internal.gatekeeper.sh/constraint-kind"
Expand Down
104 changes: 104 additions & 0 deletions apis/status/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions cmd/build/helmify/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ patchesJson6902:
kind: CustomResourceDefinition
name: expansiontemplatepodstatuses.status.gatekeeper.sh
path: labels_patch.yaml
- target:
group: apiextensions.k8s.io
version: v1
kind: CustomResourceDefinition
name: configpodstatuses.status.gatekeeper.sh
path: labels_patch.yaml
- target:
group: apiextensions.k8s.io
version: v1
Expand Down
34 changes: 34 additions & 0 deletions config/crd/bases/config.gatekeeper.sh_configs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,41 @@ spec:
type: object
status:
description: ConfigStatus defines the observed state of Config.
properties:
byPod:
items:
properties:
configUID:
description: |-
UID is a type that holds unique ID values, including UUIDs. Because we
don't ONLY use UUIDs, this is an alias to string. Being a type captures
intent and helps make sure that UIDs and names do not get conflated.
type: string
errors:
items:
properties:
message:
type: string
type:
type: string
required:
- message
type: object
type: array
id:
type: string
observedGeneration:
format: int64
type: integer
operations:
items:
type: string
type: array
type: object
type: array
type: object
type: object
served: true
storage: true
subresources:
status: {}
Loading
Loading