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

Collect OCP OAuth route and additional facts #136

Merged
merged 4 commits into from
Nov 14, 2023
Merged
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
k8s.io/apimachinery v0.28.3
k8s.io/client-go v0.28.3
k8s.io/klog v1.0.0
sigs.k8s.io/controller-runtime v0.16.3
)

require (
Expand Down Expand Up @@ -118,7 +119,6 @@ require (
k8s.io/klog/v2 v2.110.1 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/controller-runtime v0.16.3 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
Expand Down Expand Up @@ -273,6 +275,8 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
Expand Down
18 changes: 18 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ func main() {
app.Flag("operator-namespace", "Namespace in which the ArgoCD operator will be running").Default("syn-argocd-operator").StringVar(&agent.OperatorNamespace)
app.Flag("argo-image", "Image to be used for the Argo CD deployments").Default(images.DefaultArgoCDImage).StringVar(&agent.ArgoCDImage)
app.Flag("redis-image", "Image to be used for the Argo CD Redis deployment").Default(images.DefaultRedisImage).StringVar(&agent.RedisImage)
app.
Flag(
"additional-facts-config-map",
"Additional facts added to the dynamic facts in the cluster object. Keys in the configmap's data field can't override existing keys.").
Default("additional-facts").
StringVar(&agent.AdditionalFactsConfigMap)
app.
Flag(
"ocp-oauth-route-namespace",
"Namespace for the OpenShift OAuth route").
Default("openshift-authentication").
StringVar(&agent.OCPOAuthRouteNamespace)
app.
Flag(
"ocp-oauth-route-name",
"Name of the OpenShift OAuth route").
Default("oauth-openshift").
StringVar(&agent.OCPOAuthRouteName)

kingpin.MustParse(app.Parse(os.Args[1:]))
}
Expand Down
24 changes: 19 additions & 5 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import (

"github.com/deepmap/oapi-codegen/v2/pkg/securityprovider"
"github.com/projectsyn/lieutenant-api/pkg/api"
"github.com/projectsyn/steward/pkg/argocd"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog"

"github.com/projectsyn/steward/pkg/agent/facts"
"github.com/projectsyn/steward/pkg/argocd"
)

// Agent configures the cluster agent
Expand All @@ -31,8 +33,14 @@ type Agent struct {
OperatorNamespace string
ArgoCDImage string
RedisImage string
// The configmap containing additional facts to be added to the dynamic facts
AdditionalFactsConfigMap string

facts factCollector
// Reference to the OpenShift OAuth route to be added to the dynamic facts
OCPOAuthRouteNamespace string
OCPOAuthRouteName string

facts facts.FactCollector
}

// Run starts the cluster agent
Expand All @@ -58,8 +66,14 @@ func (a *Agent) Run(ctx context.Context) error {
return err
}

a.facts = factCollector{
client: client,
a.facts = facts.FactCollector{
Client: client,

OAuthRouteNamespace: a.OCPOAuthRouteNamespace,
OAuthRouteName: a.OCPOAuthRouteName,

AdditionalFactsConfigMapNamespace: a.Namespace,
AdditionalFactsConfigMapName: a.AdditionalFactsConfigMap,
}

ticker := time.NewTicker(1 * time.Minute)
Expand Down Expand Up @@ -91,7 +105,7 @@ func (a *Agent) registerCluster(ctx context.Context, config *rest.Config, apiCli
DeployKey: &publicKey,
},
}
patchCluster.DynamicFacts, err = a.facts.fetchDynamicFacts(ctx)
patchCluster.DynamicFacts, err = a.facts.FetchDynamicFacts(ctx)
if err != nil {
klog.Errorf("Error fetching dynamic facts: %v", err)
}
Expand Down
47 changes: 41 additions & 6 deletions pkg/agent/facts.go → pkg/agent/facts/facts.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package agent
package facts

import (
"context"
Expand All @@ -7,17 +7,33 @@ import (
"unicode"

"github.com/projectsyn/lieutenant-api/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
)

type factCollector struct {
client *kubernetes.Clientset
type FactCollector struct {
Client *kubernetes.Clientset

OAuthRouteNamespace string
OAuthRouteName string

AdditionalFactsConfigMapNamespace string
AdditionalFactsConfigMapName string
}

func (col factCollector) fetchDynamicFacts(ctx context.Context) (*api.DynamicClusterFacts, error) {
func (col FactCollector) FetchDynamicFacts(ctx context.Context) (*api.DynamicClusterFacts, error) {
facts := api.DynamicClusterFacts{}

additionalFacts, err := col.fetchAdditionalFacts(ctx)
if err != nil {
klog.Errorf("Error fetching additional facts: %v", err)
}
for k, v := range additionalFacts {
facts[k] = v
}

kubeVersion, err := col.fetchKubernetesVersion(ctx)
if err != nil {
klog.Errorf("Error fetching kubernetes version: %v", err)
Expand All @@ -34,12 +50,20 @@ func (col factCollector) fetchDynamicFacts(ctx context.Context) (*api.DynamicClu
facts["openshiftVersion"] = ocpVersion
}

ocpOAuthRoute, err := col.fetchOpenshiftOAuthRoute(ctx)
if err != nil {
klog.Errorf("Error fetching openshift oauth route: %v", err)
}
if ocpOAuthRoute != "" {
facts["openshiftOAuthRoute"] = ocpOAuthRoute
}

return &facts, nil
}

func (col factCollector) fetchKubernetesVersion(ctx context.Context) (*version.Info, error) {
func (col FactCollector) fetchKubernetesVersion(ctx context.Context) (*version.Info, error) {
// We are not using `col.client.ServerVersion()` to get context support
body, err := col.client.RESTClient().Get().AbsPath("/version").Do(ctx).Raw()
body, err := col.Client.RESTClient().Get().AbsPath("/version").Do(ctx).Raw()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -70,6 +94,17 @@ func processKubernetesVersion(v version.Info) (version.Info, error) {
return v, nil
}

func (col FactCollector) fetchAdditionalFacts(ctx context.Context) (map[string]string, error) {
if col.AdditionalFactsConfigMapName == "" {
return nil, nil
}
cm, err := col.Client.CoreV1().ConfigMaps(col.AdditionalFactsConfigMapNamespace).Get(ctx, col.AdditionalFactsConfigMapName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("unable to fetch the additional facts config map: %w", err)
}
return cm.Data, nil
}

func trimVersion(v string) string {
res := []rune{}
for _, r := range v {
Expand Down
2 changes: 1 addition & 1 deletion pkg/agent/facts_test.go → pkg/agent/facts/facts_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package agent
package facts

import (
"testing"
Expand Down
34 changes: 31 additions & 3 deletions pkg/agent/factsopenshift.go → pkg/agent/facts/factsopenshift.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package agent
package facts

import (
"context"
"encoding/json"
"fmt"
"path"
"strings"
"time"

Expand All @@ -30,8 +31,14 @@ type OpenshiftVersion struct {
Status OpenshiftVersionStatus
}

func (col factCollector) fetchOpenshiftVersion(ctx context.Context) (*SemanticVersion, error) {
body, err := col.client.RESTClient().Get().AbsPath("/apis/config.openshift.io/v1/clusterversions/version").Do(ctx).Raw()
type OpenshiftRoute struct {
Spec struct {
Host string
}
}

func (col FactCollector) fetchOpenshiftVersion(ctx context.Context) (*SemanticVersion, error) {
body, err := col.Client.RESTClient().Get().AbsPath("/apis/config.openshift.io/v1/clusterversions/version").Do(ctx).Raw()
if err != nil {
if errors.IsNotFound(err) {
// API server doesn't know `clusterversions` or there is no resource, so we are not running on openshift.
Expand All @@ -48,6 +55,27 @@ func (col factCollector) fetchOpenshiftVersion(ctx context.Context) (*SemanticVe
return processOpenshiftVersion(version)
}

func (col FactCollector) fetchOpenshiftOAuthRoute(ctx context.Context) (string, error) {
body, err := col.Client.RESTClient().Get().
AbsPath(
path.Join("/apis/route.openshift.io/v1/namespaces", col.OAuthRouteNamespace, "routes", col.OAuthRouteName),
).Do(ctx).Raw()
if err != nil {
if errors.IsNotFound(err) {
// API server doesn't know `routes` or there is no resource, so we are not running on openshift.
return "", nil
}
return "", fmt.Errorf("unable to fetch the openshift route: %w", err)
}
var route OpenshiftRoute
err = json.Unmarshal(body, &route)
if err != nil {
return "", fmt.Errorf("unable to parse the openshift route: %w", err)
}

return route.Spec.Host, nil
}

type SemanticVersion struct {
Major string
Minor string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package agent
package facts

import (
"testing"
Expand Down
49 changes: 49 additions & 0 deletions tools/dynamic_fact_collector/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package main

import (
"context"
"encoding/json"
"flag"
"fmt"

"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client/config"

"github.com/projectsyn/steward/pkg/agent/facts"
)

func main() {
ns := flag.String("namespace", "syn", "namespace in which steward is running")
additionalFactsConfigMap := flag.String("additional-facts-config-map", "additional-facts", "configmap containing additional facts to be added to the dynamic facts")
ocpOAuthRouteNamespace := flag.String("ocp-oauth-route-namespace", "openshift-authentication", "Namespace for the OpenShift OAuth route")
ocpOAuthRouteName := flag.String("ocp-oauth-route-name", "oauth-openshift", "Name of the OpenShift OAuth route")

flag.Parse()

cfg := config.GetConfigOrDie()

client, err := kubernetes.NewForConfig(cfg)
if err != nil {
panic(err)
}

c := facts.FactCollector{
Client: client,

OAuthRouteNamespace: *ocpOAuthRouteNamespace,
OAuthRouteName: *ocpOAuthRouteName,

AdditionalFactsConfigMapNamespace: *ns,
AdditionalFactsConfigMapName: *additionalFactsConfigMap,
}

fcts, err := c.FetchDynamicFacts(context.Background())
if err != nil {
panic(err)
}
out, err := json.MarshalIndent(fcts, "", "\t")
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
Loading