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

[fusion-hci-4.14] added creation of job template #2347

Merged
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: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ ARG LDFLAGS

RUN GOOS=linux GOARCH=amd64 go build -ldflags "$LDFLAGS" -tags netgo,osusergo -o ocs-operator main.go
RUN GOOS=linux GOARCH=amd64 go build -tags netgo,osusergo -o provider-api services/provider/main.go
RUN GOOS=linux GOARCH=amd64 go build -tags netgo,osusergo -o onboarding-secret-generator onboarding/main.go

# Build stage 2

FROM registry.access.redhat.com/ubi9/ubi-minimal

COPY --from=builder workspace/ocs-operator /usr/local/bin/ocs-operator
COPY --from=builder workspace/provider-api /usr/local/bin/provider-api
COPY --from=builder workspace/onboarding-secret-generator /usr/local/bin/onboarding-secret-generator
COPY --from=builder workspace/metrics/deploy/*rules*.yaml /ocs-prometheus-rules/

RUN chmod +x /usr/local/bin/ocs-operator /usr/local/bin/provider-api
Expand Down
73 changes: 71 additions & 2 deletions controllers/storagecluster/provider_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import (

"go.uber.org/multierr"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
Expand All @@ -24,8 +26,11 @@ import (
)

const (
ocsProviderServerName = "ocs-provider-server"
providerAPIServerImage = "PROVIDER_API_SERVER_IMAGE"
ocsProviderServerName = "ocs-provider-server"
providerAPIServerImage = "PROVIDER_API_SERVER_IMAGE"
onboardingSecretGeneratorImage = "ONBOARDING_SECRET_GENERATOR_IMAGE"
onboardingJobName = "onboarding-secret-generator"
onboardingTicketPublicKeySecretName = "onboarding-ticket-key"

ocsProviderServicePort = int32(50051)
ocsProviderServiceNodePort = int32(31659)
Expand Down Expand Up @@ -63,6 +68,12 @@ func (o *ocsProviderServer) ensureCreated(r *StorageClusterReconciler, instance
return res, nil
}

if res, err := o.createJob(r, instance); err != nil {
return reconcile.Result{}, err
} else if !res.IsZero() {
return res, nil
}

return reconcile.Result{}, nil
}

Expand Down Expand Up @@ -434,3 +445,61 @@ func RandomString(l int) string {

return string(bytes)
}

func getOnboardingJobObject(instance *ocsv1.StorageCluster) *batchv1.Job {

return &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: onboardingJobName,
Namespace: instance.Namespace,
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
RestartPolicy: corev1.RestartPolicyOnFailure,
ServiceAccountName: onboardingJobName,
Containers: []corev1.Container{
{
Name: onboardingJobName,
Image: os.Getenv(onboardingSecretGeneratorImage),
Command: []string{"/usr/local/bin/onboarding-secret-generator"},
Env: []corev1.EnvVar{
{
Name: util.OperatorNamespaceEnvVar,
Value: os.Getenv(util.OperatorNamespaceEnvVar),
},
},
},
},
},
},
},
}
}

func (o *ocsProviderServer) createJob(r *StorageClusterReconciler, instance *ocsv1.StorageCluster) (reconcile.Result, error) {
var err error
if os.Getenv(onboardingSecretGeneratorImage) == "" {
err = fmt.Errorf("OnboardingSecretGeneratorImage env var is not set")
r.Log.Error(err, "No value set for env variable")

return reconcile.Result{}, err
}

actualSecret := &corev1.Secret{}
// Creating the job only if public is not found
err = r.Client.Get(context.Background(), types.NamespacedName{Name: onboardingTicketPublicKeySecretName,
Namespace: instance.Namespace}, actualSecret)

if errors.IsNotFound(err) {
onboardingSecretGeneratorJob := getOnboardingJobObject(instance)
err = r.Client.Create(context.Background(), onboardingSecretGeneratorJob)
}
if err != nil {
r.Log.Error(err, "failed to create/ensure secret")
return reconcile.Result{}, err
}

r.Log.Info("Job is running as desired")
return reconcile.Result{}, nil
}
1 change: 1 addition & 0 deletions controllers/storagecluster/provider_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ func createSetupForOcsProviderTest(t *testing.T, allowRemoteStorageConsumers boo
}

os.Setenv(providerAPIServerImage, "fake-image")
os.Setenv(onboardingSecretGeneratorImage, "fake-image")
os.Setenv(util.WatchNamespaceEnvVar, "openshift-storage")

return r, instance
Expand Down
11 changes: 10 additions & 1 deletion controllers/storagecluster/storagecluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,14 @@ func (r *StorageClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
},
)

onboardingSecretPredicates := builder.WithPredicates(
predicate.NewPredicateFuncs(
func(client client.Object) bool {
return client.GetName() == onboardingTicketPublicKeySecretName
},
),
)

builder := ctrl.NewControllerManagedBy(mgr).
For(&ocsv1.StorageCluster{}, builder.WithPredicates(scPredicate)).
Owns(&cephv1.CephCluster{}).
Expand All @@ -201,7 +209,8 @@ func (r *StorageClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
},
},
enqueueStorageClusterRequest,
)
).
Watches(&corev1.Secret{}, enqueueStorageClusterRequest, onboardingSecretPredicates)
if os.Getenv("SKIP_NOOBAA_CRD_WATCH") != "true" {
builder.Owns(&nbv1.NooBaa{})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3074,6 +3074,8 @@ spec:
value: docker.io/centos/postgresql-12-centos8
- name: PROVIDER_API_SERVER_IMAGE
value: quay.io/ocs-dev/ocs-operator:latest
- name: ONBOARDING_SECRET_GENERATOR_IMAGE
value: quay.io/ocs-dev/ocs-operator:latest
- name: OPERATOR_NAMESPACE
valueFrom:
fieldRef:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: onboarding-secret-generator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: onboarding-secret-generator
subjects:
- kind: ServiceAccount
name: onboarding-secret-generator
namespace: openshift-storage
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: onboarding-secret-generator
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- create
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: ServiceAccount
apiVersion: v1
metadata:
name: onboarding-secret-generator
type: kubernetes.io/service-account-token
124 changes: 124 additions & 0 deletions onboarding/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package main

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"os"

"github.com/red-hat-storage/ocs-operator/v4/controllers/util"
"golang.org/x/net/context"
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
runtime "sigs.k8s.io/controller-runtime/pkg/client/config"
)

const (
onboardingTicketPublicKeySecretName = "onboarding-ticket-key" //Name of existing public key which is used ocs-operator
onboardingTicketPrivateKeySecretName = "onboarding-ticket-private-key"
serviceAccountName = "onboarding-secret-generator"
)

func main() {
clientset, err := newClient()
if err != nil {
klog.Error(err, "failed to create controller-runtime client")
return
}

operatorNamespace, err := util.GetOperatorNamespace()
if err != nil {
klog.Error(err, "unable to get operator namespace")
os.Exit(1)
}

// 1. Check public key secret exist or not
_, err = clientset.CoreV1().Secrets(operatorNamespace).Get(context.TODO(), onboardingTicketPublicKeySecretName, metav1.GetOptions{})

if err != nil && kerrors.IsNotFound(err) {
// Generate RSA key.
var err error
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
klog.Error(err, "unable to generate private")
os.Exit(1)
}

publicKey := &privateKey.PublicKey
// Export the keys to pem string
privatePem := convertRsaPrivateKeyAsPemStr(privateKey)
publicPem, err := convertRsaPublicKeyAsPemStr(publicKey)

if err != nil {
klog.Error(err, "failed to convert public key to pem str")
os.Exit(1)
}

privateSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: onboardingTicketPrivateKeySecretName,
Namespace: operatorNamespace,
Annotations: map[string]string{"kubernetes.io/service-account.name": serviceAccountName},
},
Type: "kubernetes.io/service-account-token",
StringData: map[string]string{
"key": privatePem,
},
}

_, err = clientset.CoreV1().Secrets(operatorNamespace).Create(context.Background(), privateSecret, metav1.CreateOptions{})

if err != nil {
klog.Error(err, "Failed to create private secret.")
os.Exit(1)
}
publicSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: onboardingTicketPublicKeySecretName,
Namespace: operatorNamespace,
},
StringData: map[string]string{
"key": publicPem,
},
}

_, err = clientset.CoreV1().Secrets(operatorNamespace).Create(context.Background(), publicSecret, metav1.CreateOptions{})
if err != nil {
klog.Error(err, "Failed to create public secret.")
os.Exit(1)
}

}

}

func newClient() (*kubernetes.Clientset, error) {
config := runtime.GetConfigOrDie()
clientset, err := kubernetes.NewForConfig(config)

if err != nil {
klog.Error(err, "failed to get clientset")
}

return clientset, nil
}

func convertRsaPrivateKeyAsPemStr(privateKey *rsa.PrivateKey) string {
privteKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privateKeyPem := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privteKeyBytes})
return string(privateKeyPem)
}

func convertRsaPublicKeyAsPemStr(publicKey *rsa.PublicKey) (string, error) {
publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return "", err
}
publicKeyPem := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: publicKeyBytes})

return string(publicKeyPem), nil
}
12 changes: 12 additions & 0 deletions rbac/onboarding-secret-generator-binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: onboarding-secret-generator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: onboarding-secret-generator
subjects:
- kind: ServiceAccount
name: onboarding-secret-generator
namespace: openshift-storage
13 changes: 13 additions & 0 deletions rbac/onboarding-secret-generator-role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: onboarding-secret-generator
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- create
5 changes: 5 additions & 0 deletions rbac/onboarding-secret-generator-sa.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: ServiceAccount
apiVersion: v1
metadata:
name: onboarding-secret-generator
type: kubernetes.io/service-account-token
4 changes: 4 additions & 0 deletions tools/csv-merger/csv-merger.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ func unmarshalCSV(filePath string) *csvv1.ClusterServiceVersion {
Name: "PROVIDER_API_SERVER_IMAGE",
Value: *ocsContainerImage,
},
{
Name: "ONBOARDING_SECRET_GENERATOR_IMAGE",
Value: *ocsContainerImage,
},
{
Name: util.OperatorNamespaceEnvVar,
ValueFrom: &corev1.EnvVarSource{
Expand Down