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

[release-4.5] Bug 1835090: Collect certificates #70

Merged
merged 4 commits into from
Feb 19, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/*.pprof
main
.vscode/
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ test-e2e:
go test ./test/integration $(TEST_OPTIONS)
.PHONY: test-e2e

vet:
go vet $$(go list ./... | grep -v /vendor/)

lint:
golint $$(go list ./... | grep -v /vendor/)

vendor:
go mod tidy
go mod vendor
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func (s *Support) Run(ctx context.Context, controller *controllercmd.ControllerC

// the gatherers periodically check the state of the cluster and report any
// config to the recorder
configPeriodic := clusterconfig.New(gatherConfigClient, gatherKubeClient.CoreV1(), metricsClient)
configPeriodic := clusterconfig.New(gatherConfigClient, gatherKubeClient.CoreV1(), gatherKubeClient.CertificatesV1beta1(), metricsClient)
periodic := periodic.New(configObserver, recorder, map[string]gather.Interface{
"config": configPeriodic,
})
Expand Down
63 changes: 55 additions & 8 deletions pkg/gather/clusterconfig/clusterconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import (
"sync"
"time"

configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/client-go/config/clientset/versioned/scheme"
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
certificatesv1beta1 "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -20,10 +25,6 @@ import (
"k8s.io/client-go/rest"
"k8s.io/klog"

configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/client-go/config/clientset/versioned/scheme"
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"

"github.com/openshift/insights-operator/pkg/record"
)

Expand All @@ -36,25 +37,29 @@ var (
maxEventTimeInterval = 1 * time.Hour
)

// Gatherer is a driving instance invoking collection of data
type Gatherer struct {
client configv1client.ConfigV1Interface
coreClient corev1client.CoreV1Interface
metricsClient rest.Interface

lock sync.Mutex
lastVersion *configv1.ClusterVersion
certClient certificatesv1beta1.CertificatesV1beta1Interface
lock sync.Mutex
lastVersion *configv1.ClusterVersion
}

func New(client configv1client.ConfigV1Interface, coreClient corev1client.CoreV1Interface, metricsClient rest.Interface) *Gatherer {
// New creates new Gatherer
func New(client configv1client.ConfigV1Interface, coreClient corev1client.CoreV1Interface, certClient certificatesv1beta1.CertificatesV1beta1Interface, metricsClient rest.Interface) *Gatherer {
return &Gatherer{
client: client,
coreClient: coreClient,
certClient: certClient,
metricsClient: metricsClient,
}
}

var reInvalidUIDCharacter = regexp.MustCompile(`[^a-z0-9\-]`)

// Gather is hosting and calling all the recording functions
func (i *Gatherer) Gather(ctx context.Context, recorder record.Interface) error {
return record.Collect(ctx, recorder,
func() ([]record.Record, []error) {
Expand Down Expand Up @@ -223,6 +228,20 @@ func (i *Gatherer) Gather(ctx context.Context, recorder record.Interface) error
}
return []record.Record{{Name: "config/proxy", Item: ProxyAnonymizer{config}}}, nil
},
func() ([]record.Record, []error) {
requests, err := i.certClient.CertificateSigningRequests().List(metav1.ListOptions{})
if errors.IsNotFound(err) {
return nil, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

I know this is used in previous gathering functions, but is the nil handled properly later?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fortunately returning nil in a slice will return empty slice and wont fail. It looks even empty Record wont fail as its just a structure. I have just verified both.

}
if err != nil {
return nil, []error{err}
}
records := make([]record.Record, len(requests.Items))
for i, sr := range requests.Items {
records[i] = record.Record{Name: fmt.Sprintf("config/certificatesigningrequests/%s", sr.Name), Item: CSRAnonymizer{&sr}}
}
return records, nil
},
)
}

Expand Down Expand Up @@ -260,26 +279,34 @@ func (i *Gatherer) gatherNamespaceEvents(namespace string) ([]record.Record, []e
return []record.Record{{Name: fmt.Sprintf("events/%s", namespace), Item: EventAnonymizer{&compactedEvents}}}, nil
}

// RawByte is skipping Marshalling which accepts byte slice
type RawByte []byte

// Marshal just returns bytes
func (r RawByte) Marshal(_ context.Context) ([]byte, error) {
return r, nil
}

// Raw is another simplification of marshalling which accepts string
type Raw struct{ string }

// Marshal returns raw bytes
func (r Raw) Marshal(_ context.Context) ([]byte, error) {
return []byte(r.string), nil
}

// Anonymizer seems to return serialized runtime.Object without change
type Anonymizer struct{ runtime.Object }

// Marshal serializes with OpenShift client-go serializer
func (a Anonymizer) Marshal(_ context.Context) ([]byte, error) {
return runtime.Encode(serializer, a.Object)
}

// InfrastructureAnonymizer anonymizes infrastructure
type InfrastructureAnonymizer struct{ *configv1.Infrastructure }

// Marshal serializes Infrastructure with anonymization
func (a InfrastructureAnonymizer) Marshal(_ context.Context) ([]byte, error) {
return runtime.Encode(serializer, anonymizeInfrastructure(a.Infrastructure))
}
Expand All @@ -292,44 +319,57 @@ func anonymizeInfrastructure(config *configv1.Infrastructure) *configv1.Infrastr
return config
}

// ClusterVersionAnonymizer is serializing ClusterVersion with anonymization
type ClusterVersionAnonymizer struct{ *configv1.ClusterVersion }

// Marshal serializes ClusterVersion with anonymization
func (a ClusterVersionAnonymizer) Marshal(_ context.Context) ([]byte, error) {
a.ClusterVersion.Spec.Upstream = configv1.URL(anonymizeURL(string(a.ClusterVersion.Spec.Upstream)))
return runtime.Encode(serializer, a.ClusterVersion)
}

// FeatureGateAnonymizer implements serializaton of FeatureGate with anonymization
type FeatureGateAnonymizer struct{ *configv1.FeatureGate }

// Marshal serializes FeatureGate with anonymization
func (a FeatureGateAnonymizer) Marshal(_ context.Context) ([]byte, error) {
return runtime.Encode(serializer, a.FeatureGate)
}

// IngressAnonymizer implements serialization with marshalling
type IngressAnonymizer struct{ *configv1.Ingress }

// Marshal implements serialization of Ingres.Spec.Domain with anonymization
func (a IngressAnonymizer) Marshal(_ context.Context) ([]byte, error) {
a.Ingress.Spec.Domain = anonymizeURL(a.Ingress.Spec.Domain)
return runtime.Encode(serializer, a.Ingress)
}

// CompactedEvent holds one Namespace Event
type CompactedEvent struct {
Namespace string `json:"namespace"`
LastTimestamp time.Time `json:"lastTimestamp"`
Reason string `json:"reason"`
Message string `json:"message"`
}

// CompactedEventList is collection of events
type CompactedEventList struct {
Items []CompactedEvent `json:"items"`
}

// EventAnonymizer implements serializaion of Events with anonymization
type EventAnonymizer struct{ *CompactedEventList }

// Marshal serializes Events with anonymization
func (a EventAnonymizer) Marshal(_ context.Context) ([]byte, error) {
return json.Marshal(a.CompactedEventList)
}

// ProxyAnonymizer implements serialization of HttpProxy/NoProxy with anonymization
type ProxyAnonymizer struct{ *configv1.Proxy }

// Marshal implements Proxy serialization with anonymization
func (a ProxyAnonymizer) Marshal(_ context.Context) ([]byte, error) {
a.Proxy.Spec.HTTPProxy = anonymizeURLCSV(a.Proxy.Spec.HTTPProxy)
a.Proxy.Spec.HTTPSProxy = anonymizeURLCSV(a.Proxy.Spec.HTTPSProxy)
Expand Down Expand Up @@ -359,8 +399,10 @@ var reURL = regexp.MustCompile(`[^\.\-/\:]`)

func anonymizeURL(s string) string { return reURL.ReplaceAllString(s, "x") }

// ClusterOperatorAnonymizer implements serialization of ClusterOperator without change
type ClusterOperatorAnonymizer struct{ *configv1.ClusterOperator }

// Marshal serializes ClusterOperator
func (a ClusterOperatorAnonymizer) Marshal(_ context.Context) ([]byte, error) {
return runtime.Encode(serializer, a.ClusterOperator)
}
Expand All @@ -386,8 +428,10 @@ func namespacesForOperator(operator *configv1.ClusterOperator) []string {
return ns
}

// NodeAnonymizer implements serialization of Node with anonymization
type NodeAnonymizer struct{ *corev1.Node }

// Marshal implements serialization of Node with anonymization
func (a NodeAnonymizer) Marshal(_ context.Context) ([]byte, error) {
return runtime.Encode(kubeSerializer, anonymizeNode(a.Node))
}
Expand Down Expand Up @@ -432,8 +476,10 @@ func isHealthyNode(node *corev1.Node) bool {
return true
}

// PodAnonymizer implements serialization with anonymization for a Pod
type PodAnonymizer struct{ *corev1.Pod }

// Marshal implements serialization of a Pod with anonymization
func (a PodAnonymizer) Marshal(_ context.Context) ([]byte, error) {
return runtime.Encode(kubeSerializer, anonymizePod(a.Pod))
}
Expand Down Expand Up @@ -487,6 +533,7 @@ func (i *Gatherer) setClusterVersion(version *configv1.ClusterVersion) {
i.lastVersion = version.DeepCopy()
}

// ClusterVersion returns Version for this cluster, which is set by running version during Gathering
func (i *Gatherer) ClusterVersion() *configv1.ClusterVersion {
i.lock.Lock()
defer i.lock.Unlock()
Expand Down