diff options
35 files changed, 792 insertions, 226 deletions
diff --git a/certService/pom.xml b/certService/pom.xml index 9cff262b..2c7b5d44 100644 --- a/certService/pom.xml +++ b/certService/pom.xml @@ -18,10 +18,10 @@ <parent> <groupId>org.onap.oom.platform.cert-service</groupId> <artifactId>oom-certservice</artifactId> - <version>2.1.1-SNAPSHOT</version> + <version>2.2.0-SNAPSHOT</version> </parent> <artifactId>oom-certservice-api</artifactId> - <version>2.1.1-SNAPSHOT</version> + <version>2.2.0-SNAPSHOT</version> <name>oom-certservice-api</name> <description>OOM Certification Service Api</description> <packaging>jar</packaging> diff --git a/certService/version.properties b/certService/version.properties index 00ef5645..3ad2137c 100644 --- a/certService/version.properties +++ b/certService/version.properties @@ -1,4 +1,4 @@ -major=1 +major=2 minor=2 patch=0 base_version=${major}.${minor}.${patch} diff --git a/certServiceClient/pom.xml b/certServiceClient/pom.xml index 4c2bae90..9201b813 100644 --- a/certServiceClient/pom.xml +++ b/certServiceClient/pom.xml @@ -18,12 +18,12 @@ <parent> <artifactId>oom-certservice</artifactId> <groupId>org.onap.oom.platform.cert-service</groupId> - <version>2.1.1-SNAPSHOT</version> + <version>2.2.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>oom-certservice-client</artifactId> - <version>2.1.1-SNAPSHOT</version> + <version>2.2.0-SNAPSHOT</version> <name>oom-certservice-client</name> <description>OOM Certification Service Api Client</description> <packaging>jar</packaging> diff --git a/certServiceClient/version.properties b/certServiceClient/version.properties index 00ef5645..3ad2137c 100644 --- a/certServiceClient/version.properties +++ b/certServiceClient/version.properties @@ -1,4 +1,4 @@ -major=1 +major=2 minor=2 patch=0 base_version=${major}.${minor}.${patch} diff --git a/certServiceK8sExternalProvider/README.md b/certServiceK8sExternalProvider/README.md index bb3e0b8c..ee739a3f 100644 --- a/certServiceK8sExternalProvider/README.md +++ b/certServiceK8sExternalProvider/README.md @@ -1,21 +1,32 @@ -## Cert Service k8s external cert signing provider +## Cert Service K8s external provider + +### General description + +Cert Service K8s external provider ia a part of certificate distribution infrastructure in ONAP. +The main functionality of the provider is to forward Certificate Signing Requests (CSRs) created by cert-mananger (https://cert-manager.io) to CertServiceAPI. + +More information can found on a dedicated page: https://wiki.onap.org/display/DW/CertService+and+K8s+Cert-Manager+integration. ### Build project There are two methods for building the project: - - mvn clean install - - make + - mvn clean install (used by CI) + - make (used by DEV) ### Installation +#### Providing K8s secret containing TLS certificates + Create secret with certificates for communication between CMPv2Issuer and Cert Service API: ``` kubectl create secret generic -n onap cmpv2-issuer-secret --from-file=<project-base-dir>/certs/cmpv2Issuer-key.pem --from-file=<project-base-dir>/certs/cmpv2Issuer-cert.pem --from-file=<project-base-dir>/certs/cacert.pem ``` -Apply k8s files from 'deploy' directory in following order: +#### Deployment of the application + +Apply K8s files from 'deploy' directory in following order: - crd.yaml - roles.yaml @@ -25,18 +36,32 @@ Apply k8s files from 'deploy' directory in following order: **Note:** Files and installation are currently examples, which should be used as a guide for OOM Helm Charts implementation +#### Log level adjustment + +Log level can be set during deployment as docker container argument --> see deployment.yaml file. +Here is an interesting part from the deployment.yaml file: + + - args: + - --metrics-addr=127.0.0.1:8080 + - --log-level=debug + command: + - /oom-certservice-cmpv2issuer + image: onap/oom-certservice-cmpv2issuer:1.0.0 + +Supported values of log-level flag (case-sensitive): debug, info, warn, error + ### Usage -To issue a certificate adjust and apply following k8s file: +To issue a certificate adjust and apply following K8s file: - certificate_example.yaml #### Unsupported Certificate fields -Some of the fields present in Cert Manager Certificate are not currently supported by CertService API, because of that they are -filtered from the Certificate Signing Request. +Some fields present in Cert-Manager Certificate are currently not supported by CertService API and because of that they are +filtered out from the Certificate Signing Request. -**Filtered fields:** +**Fields that are filtered out:** - subjectDN fields: - serialNumber - streetAddresses @@ -48,3 +73,12 @@ filtered from the Certificate Signing Request. - duration - usages + #### Overridden Certificate fields + +Some fields present in a Cert-Manager Certificate will be overridden by a CMPv2 server. + +**Overridden fields:** + - duration + - usages + + diff --git a/certServiceK8sExternalProvider/deploy/deployment.yaml b/certServiceK8sExternalProvider/deploy/deployment.yaml index 20dd65a8..e7073cf6 100644 --- a/certServiceK8sExternalProvider/deploy/deployment.yaml +++ b/certServiceK8sExternalProvider/deploy/deployment.yaml @@ -72,6 +72,7 @@ spec: name: https - args: - --metrics-addr=127.0.0.1:8080 + - --log-level=debug command: - /oom-certservice-cmpv2issuer image: onap/oom-certservice-cmpv2issuer:1.0.0 diff --git a/certServiceK8sExternalProvider/go.mod b/certServiceK8sExternalProvider/go.mod index f4626d81..93fe45c2 100644 --- a/certServiceK8sExternalProvider/go.mod +++ b/certServiceK8sExternalProvider/go.mod @@ -28,14 +28,14 @@ go 1.15 require ( github.com/go-logr/logr v0.2.1 - github.com/go-logr/zapr v0.2.0 // indirect + github.com/go-logr/zapr v0.2.0 github.com/jetstack/cert-manager v1.0.3 github.com/stretchr/testify v1.6.1 + go.uber.org/zap v1.10.0 gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e // indirect k8s.io/api v0.19.0 k8s.io/apimachinery v0.19.0 k8s.io/client-go v0.19.0 - k8s.io/klog/v2 v2.3.0 k8s.io/utils v0.0.0-20200729134348-d5654de09c73 sigs.k8s.io/controller-runtime v0.6.2 ) diff --git a/certServiceK8sExternalProvider/main.go b/certServiceK8sExternalProvider/main.go index 430d4020..c649e3fc 100644 --- a/certServiceK8sExternalProvider/main.go +++ b/certServiceK8sExternalProvider/main.go @@ -36,32 +36,35 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" "k8s.io/utils/clock" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/manager" app "onap.org/oom-certservice/k8s-external-provider/src" certserviceapi "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" controllers "onap.org/oom-certservice/k8s-external-provider/src/cmpv2controller" "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner" + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" ) var ( scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("setup") + setupLog leveledlogger.Logger ) func init() { _ = clientgoscheme.AddToScheme(scheme) _ = certmanager.AddToScheme(scheme) _ = certserviceapi.AddToScheme(scheme) + setupLog = leveledlogger.GetLogger() - ctrl.SetLogger(zap.New(zap.UseDevMode(true))) + ctrl.SetLogger(setupLog.Log) } func main() { printVersionInfo() - metricsAddr, enableLeaderElection := parseInputArguments() + metricsAddr, logLevel, enableLeaderElection := parseInputArguments() + + leveledlogger.SetLogLevel(logLevel) manager := createControllerManager(metricsAddr, enableLeaderElection) @@ -79,15 +82,17 @@ func printVersionInfo() { fmt.Println() } -func parseInputArguments() (string, bool) { +func parseInputArguments() (string, string, bool) { setupLog.Info("Parsing input arguments...") var metricsAddr string + var logLevel string var enableLeaderElection bool flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") + flag.StringVar(&logLevel, "log-level", "debug", "Min. level for logs visibility. One of: debug, info, warn, error") flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.") flag.Parse() - return metricsAddr, enableLeaderElection + return metricsAddr, logLevel, enableLeaderElection } func startControllerManager(manager manager.Manager) { @@ -115,7 +120,7 @@ func registerCMPv2IssuerController(manager manager.Manager) { err := (&controllers.CMPv2IssuerController{ Client: manager.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("CMPv2Issuer"), + Log: leveledlogger.GetLoggerWithValues("controllers", "CMPv2Issuer"), Clock: clock.RealClock{}, Recorder: manager.GetEventRecorderFor("cmpv2-issuer-controller"), ProvisionerFactory: &cmpv2provisioner.ProvisionerFactoryImpl{}, @@ -131,7 +136,7 @@ func registerCertificateRequestController(manager manager.Manager) { err := (&controllers.CertificateRequestController{ Client: manager.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("CertificateRequest"), + Log: leveledlogger.GetLoggerWithValues("controllers", "CertificateRequest"), Recorder: manager.GetEventRecorderFor("certificate-requests-controller"), }).SetupWithManager(manager) diff --git a/certServiceK8sExternalProvider/main_test.go b/certServiceK8sExternalProvider/main_test.go index 0ad70246..83420d6f 100644 --- a/certServiceK8sExternalProvider/main_test.go +++ b/certServiceK8sExternalProvider/main_test.go @@ -33,9 +33,10 @@ func Test_shouldParseArguments_defaultValues(t *testing.T) { "first-arg-is-omitted-by-method-parse-arguments-so-this-only-a-placeholder"} flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) - metricsAddr, enableLeaderElection := parseInputArguments() + metricsAddr, logLevel, enableLeaderElection := parseInputArguments() assert.Equal(t, ":8080", metricsAddr) + assert.Equal(t, "debug", logLevel) assert.False(t, enableLeaderElection) } @@ -43,12 +44,13 @@ func Test_shouldParseArguments_valuesFromCLI(t *testing.T) { os.Args = []string{ "first-arg-is-omitted-by-method-parse-arguments-so-this-only-a-placeholder", "--metrics-addr=127.0.0.1:555", + "--log-level=error", "--enable-leader-election=true"} flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) - metricsAddr, enableLeaderElection := parseInputArguments() + metricsAddr, logLevel, enableLeaderElection := parseInputArguments() assert.Equal(t, "127.0.0.1:555", metricsAddr) + assert.Equal(t, "error", logLevel) assert.True(t, enableLeaderElection) - } diff --git a/certServiceK8sExternalProvider/pom.xml b/certServiceK8sExternalProvider/pom.xml index 0347db60..a34ffc3f 100644 --- a/certServiceK8sExternalProvider/pom.xml +++ b/certServiceK8sExternalProvider/pom.xml @@ -5,7 +5,7 @@ <parent> <artifactId>oom-certservice</artifactId> <groupId>org.onap.oom.platform.cert-service</groupId> - <version>2.1.1-SNAPSHOT</version> + <version>2.2.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller.go b/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller.go index e5dc4d1c..cb667bd6 100644 --- a/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller.go +++ b/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller.go @@ -29,10 +29,7 @@ import ( "context" "fmt" - "github.com/go-logr/logr" - apiutil "github.com/jetstack/cert-manager/pkg/api/util" cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" - cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" core "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" @@ -42,20 +39,22 @@ import ( "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" "onap.org/oom-certservice/k8s-external-provider/src/cmpv2controller/logger" + "onap.org/oom-certservice/k8s-external-provider/src/cmpv2controller/updater" provisioners "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner" + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" x509utils "onap.org/oom-certservice/k8s-external-provider/src/x509" ) const ( privateKeySecretNameAnnotation = "cert-manager.io/private-key-secret-name" - privateKeySecretKey = "tls.key" + privateKeySecretKey = "tls.key" ) // CertificateRequestController reconciles a CMPv2Issuer object. type CertificateRequestController struct { - client.Client - Log logr.Logger + Client client.Client Recorder record.EventRecorder + Log leveledlogger.Logger } // Reconcile will read and validate a CMPv2Issuer resource associated to the @@ -63,10 +62,12 @@ type CertificateRequestController struct { // provisioner in the CMPv2Issuer. func (controller *CertificateRequestController) Reconcile(k8sRequest ctrl.Request) (ctrl.Result, error) { ctx := context.Background() - log := controller.Log.WithValues("certificate-request-controller", k8sRequest.NamespacedName) + log := leveledlogger.GetLoggerWithValues("certificate-request-controller", k8sRequest.NamespacedName) // 1. Fetch the CertificateRequest resource being reconciled. certificateRequest := new(cmapi.CertificateRequest) + certUpdater := updater.NewCertificateRequestUpdater(controller.Client, controller.Recorder, certificateRequest, ctx, log) + log.Info("Registered new certificate sign request: ", "cert-name", certificateRequest.Name) if err := controller.Client.Get(ctx, k8sRequest.NamespacedName, certificateRequest); err != nil { err = handleErrorResourceNotFound(log, err) @@ -95,20 +96,20 @@ func (controller *CertificateRequestController) Reconcile(k8sRequest ctrl.Reques Name: certificateRequest.Spec.IssuerRef.Name, } if err := controller.Client.Get(ctx, issuerNamespaceName, &issuer); err != nil { - controller.handleErrorGettingCMPv2Issuer(ctx, log, err, certificateRequest, issuerNamespaceName, k8sRequest) + controller.handleErrorGettingCMPv2Issuer(certUpdater, log, err, certificateRequest, issuerNamespaceName, k8sRequest) return ctrl.Result{}, err } // 5. Check if CMPv2Issuer is ready to sing certificates if !isCMPv2IssuerReady(issuer) { - err := controller.handleErrorCMPv2IssuerIsNotReady(ctx, log, issuerNamespaceName, certificateRequest, k8sRequest) + err := controller.handleErrorCMPv2IssuerIsNotReady(certUpdater, log, issuerNamespaceName, certificateRequest, k8sRequest) return ctrl.Result{}, err } // 6. Load the provisioner that will sign the CertificateRequest provisioner, ok := provisioners.Load(issuerNamespaceName) if !ok { - err := controller.handleErrorCouldNotLoadCMPv2Provisioner(ctx, log, issuerNamespaceName, certificateRequest) + err := controller.handleErrorCouldNotLoadCMPv2Provisioner(certUpdater, log, issuerNamespaceName) return ctrl.Result{}, err } @@ -120,7 +121,7 @@ func (controller *CertificateRequestController) Reconcile(k8sRequest ctrl.Reques } var privateKeySecret core.Secret if err := controller.Client.Get(ctx, privateKeySecretNamespaceName, &privateKeySecret); err != nil { - controller.handleErrorGettingPrivateKey(ctx, log, err, certificateRequest, privateKeySecretNamespaceName) + controller.handleErrorGettingPrivateKey(certUpdater, log, err, privateKeySecretNamespaceName) return ctrl.Result{}, err } privateKeyBytes := privateKeySecret.Data[privateKeySecretKey] @@ -129,54 +130,36 @@ func (controller *CertificateRequestController) Reconcile(k8sRequest ctrl.Reques log.Info("Decoding CSR...") csr, err := x509utils.DecodeCSR(certificateRequest.Spec.Request) if err != nil { - controller.handleErrorFailedToDecodeCSR(ctx, log, err, certificateRequest) + controller.handleErrorFailedToDecodeCSR(certUpdater, log, err) return ctrl.Result{}, err } // 9. Log Certificate Request properties not supported or overridden by CertService API - logger.LogCertRequestProperties(ctrl.Log.WithName("CSR details"), certificateRequest, csr) + logger.LogCertRequestProperties(leveledlogger.GetLoggerWithName("CSR details:"), certificateRequest, csr) // 10. Sign CertificateRequest signedPEM, trustedCAs, err := provisioner.Sign(ctx, certificateRequest, privateKeyBytes) if err != nil { - controller.handleErrorFailedToSignCertificate(ctx, log, err, certificateRequest) + controller.handleErrorFailedToSignCertificate(certUpdater, log, err) return ctrl.Result{}, nil } // 11. Store signed certificates in CertificateRequest certificateRequest.Status.Certificate = signedPEM certificateRequest.Status.CA = trustedCAs - if err := controller.updateCertificateRequestWithSignedCerficates(ctx, certificateRequest); err != nil { + if err := certUpdater.UpdateCertificateRequestWithSignedCertificates(); err != nil { return ctrl.Result{}, err } return ctrl.Result{}, nil } -func (controller *CertificateRequestController) updateCertificateRequestWithSignedCerficates(ctx context.Context, certificateRequest *cmapi.CertificateRequest) error { - return controller.setStatus(ctx, certificateRequest, cmmeta.ConditionTrue, cmapi.CertificateRequestReasonIssued, "Certificate issued") -} - func (controller *CertificateRequestController) SetupWithManager(manager ctrl.Manager) error { return ctrl.NewControllerManagedBy(manager). For(&cmapi.CertificateRequest{}). Complete(controller) } -func (controller *CertificateRequestController) setStatus(ctx context.Context, certificateRequest *cmapi.CertificateRequest, status cmmeta.ConditionStatus, reason, message string, args ...interface{}) error { - completeMessage := fmt.Sprintf(message, args...) - apiutil.SetCertificateRequestCondition(certificateRequest, cmapi.CertificateRequestConditionReady, status, reason, completeMessage) - - // Fire an Event to additionally inform users of the change - eventType := core.EventTypeNormal - if status == cmmeta.ConditionFalse { - eventType = core.EventTypeWarning - } - controller.Recorder.Event(certificateRequest, eventType, reason, completeMessage) - - return controller.Client.Status().Update(ctx, certificateRequest) -} - func isCMPv2IssuerReady(issuer cmpv2api.CMPv2Issuer) bool { condition := cmpv2api.CMPv2IssuerCondition{Type: cmpv2api.ConditionReady, Status: cmpv2api.ConditionTrue} return hasCondition(issuer, condition) @@ -201,42 +184,41 @@ func isCMPv2CertificateRequest(certificateRequest *cmapi.CertificateRequest) boo // Error handling -func (controller *CertificateRequestController) handleErrorCouldNotLoadCMPv2Provisioner(ctx context.Context, log logr.Logger, issuerNamespaceName types.NamespacedName, certificateRequest *cmapi.CertificateRequest) error { +func (controller *CertificateRequestController) handleErrorCouldNotLoadCMPv2Provisioner(updater *updater.CertificateRequestStatusUpdater, log leveledlogger.Logger, issuerNamespaceName types.NamespacedName) error { err := fmt.Errorf("provisioner %s not found", issuerNamespaceName) log.Error(err, "Failed to load CMPv2 Provisioner resource") - _ = controller.setStatus(ctx, certificateRequest, cmmeta.ConditionFalse, cmapi.CertificateRequestReasonPending, "Failed to load provisioner for CMPv2Issuer resource %s", issuerNamespaceName) + _ = updater.UpdateStatusWithEventTypeWarning(cmapi.CertificateRequestReasonPending, "Failed to load provisioner for CMPv2Issuer resource %s", issuerNamespaceName) return err } -func (controller *CertificateRequestController) handleErrorCMPv2IssuerIsNotReady(ctx context.Context, log logr.Logger, issuerNamespaceName types.NamespacedName, certificateRequest *cmapi.CertificateRequest, req ctrl.Request) error { +func (controller *CertificateRequestController) handleErrorCMPv2IssuerIsNotReady(updater *updater.CertificateRequestStatusUpdater, log leveledlogger.Logger, issuerNamespaceName types.NamespacedName, certificateRequest *cmapi.CertificateRequest, req ctrl.Request) error { err := fmt.Errorf("resource %s is not ready", issuerNamespaceName) log.Error(err, "CMPv2Issuer not ready", "namespace", req.Namespace, "name", certificateRequest.Spec.IssuerRef.Name) - _ = controller.setStatus(ctx, certificateRequest, cmmeta.ConditionFalse, cmapi.CertificateRequestReasonPending, "CMPv2Issuer resource %s is not Ready", issuerNamespaceName) + _ = updater.UpdateStatusWithEventTypeWarning(cmapi.CertificateRequestReasonPending, "CMPv2Issuer resource %s is not Ready", issuerNamespaceName) return err } -func (controller *CertificateRequestController) handleErrorGettingCMPv2Issuer(ctx context.Context, log logr.Logger, err error, certificateRequest *cmapi.CertificateRequest, issuerNamespaceName types.NamespacedName, req ctrl.Request) { +func (controller *CertificateRequestController) handleErrorGettingCMPv2Issuer(updater *updater.CertificateRequestStatusUpdater, log leveledlogger.Logger, err error, certificateRequest *cmapi.CertificateRequest, issuerNamespaceName types.NamespacedName, req ctrl.Request) { log.Error(err, "Failed to retrieve CMPv2Issuer resource", "namespace", req.Namespace, "name", certificateRequest.Spec.IssuerRef.Name) - _ = controller.setStatus(ctx, certificateRequest, cmmeta.ConditionFalse, cmapi.CertificateRequestReasonPending, "Failed to retrieve CMPv2Issuer resource %s: %v", issuerNamespaceName, err) + _ = updater.UpdateStatusWithEventTypeWarning(cmapi.CertificateRequestReasonPending, "Failed to retrieve CMPv2Issuer resource %s: %v", issuerNamespaceName, err) } -func (controller *CertificateRequestController) handleErrorGettingPrivateKey(ctx context.Context, log logr.Logger, err error, certificateRequest *cmapi.CertificateRequest, pkSecretNamespacedName types.NamespacedName) { +func (controller *CertificateRequestController) handleErrorGettingPrivateKey(updater *updater.CertificateRequestStatusUpdater, log leveledlogger.Logger, err error, pkSecretNamespacedName types.NamespacedName) { log.Error(err, "Failed to retrieve private key secret for certificate request", "namespace", pkSecretNamespacedName.Namespace, "name", pkSecretNamespacedName.Name) - _ = controller.setStatus(ctx, certificateRequest, cmmeta.ConditionFalse, cmapi.CertificateRequestReasonPending, "Failed to retrieve private key secret: %v", err) + _ = updater.UpdateStatusWithEventTypeWarning(cmapi.CertificateRequestReasonPending, "Failed to retrieve private key secret: %v", err) } -func (controller *CertificateRequestController) handleErrorFailedToSignCertificate(ctx context.Context, log logr.Logger, err error, certificateRequest *cmapi.CertificateRequest) { +func (controller *CertificateRequestController) handleErrorFailedToSignCertificate(updater *updater.CertificateRequestStatusUpdater, log leveledlogger.Logger, err error) { log.Error(err, "Failed to sign certificate request") - _ = controller.setStatus(ctx, certificateRequest, cmmeta.ConditionFalse, cmapi.CertificateRequestReasonFailed, "Failed to sign certificate request: %v", err) + _ = updater.UpdateStatusWithEventTypeWarning(cmapi.CertificateRequestReasonFailed, "Failed to sign certificate request: %v", err) } -func (controller *CertificateRequestController) handleErrorFailedToDecodeCSR(ctx context.Context, log logr.Logger, err error, certificateRequest *cmapi.CertificateRequest) { +func (controller *CertificateRequestController) handleErrorFailedToDecodeCSR(updater *updater.CertificateRequestStatusUpdater, log leveledlogger.Logger, err error) { log.Error(err, "Failed to decode certificate sign request") - _ = controller.setStatus(ctx, certificateRequest, cmmeta.ConditionFalse, cmapi.CertificateRequestReasonFailed, "Failed to decode CSR: %v", err) + _ = updater.UpdateStatusWithEventTypeWarning(cmapi.CertificateRequestReasonFailed, "Failed to decode CSR: %v", err) } - -func handleErrorResourceNotFound(log logr.Logger, err error) error { +func handleErrorResourceNotFound(log leveledlogger.Logger, err error) error { if apierrors.IsNotFound(err) { log.Error(err, "CertificateRequest resource not found") } else { diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller_test.go b/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller_test.go index f5869ea2..24b6b89e 100644 --- a/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller_test.go +++ b/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller_test.go @@ -31,13 +31,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" - ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" provisioners "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner" provisionersdata "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner/csr/testdata" + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" "onap.org/oom-certservice/k8s-external-provider/src/testdata" x509 "onap.org/oom-certservice/k8s-external-provider/src/x509/testdata" ) @@ -141,7 +141,7 @@ func getValidCertificateRequest() *cmapi.CertificateRequest { func getCertRequestController(fakeRecorder *record.FakeRecorder, fakeClient client.Client) CertificateRequestController { controller := CertificateRequestController{ Client: fakeClient, - Log: ctrl.Log.WithName("controllers").WithName("CertificateRequest"), + Log: leveledlogger.GetLoggerWithValues("controllers", "CertificateRequest"), Recorder: fakeRecorder, } return controller diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_controller.go b/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_controller.go index 9bc41e7f..3f3a4651 100644 --- a/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_controller.go +++ b/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_controller.go @@ -29,7 +29,6 @@ import ( "context" "fmt" - "github.com/go-logr/logr" core "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -40,15 +39,17 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" + "onap.org/oom-certservice/k8s-external-provider/src/cmpv2controller/updater" provisioners "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner" + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" ) // CMPv2IssuerController reconciles a CMPv2Issuer object type CMPv2IssuerController struct { - client.Client - Log logr.Logger - Clock clock.Clock - Recorder record.EventRecorder + Client client.Client + Log leveledlogger.Logger + Clock clock.Clock + Recorder record.EventRecorder ProvisionerFactory provisioners.ProvisionerFactory } @@ -56,7 +57,7 @@ type CMPv2IssuerController struct { // status condition ready to true if everything is right. func (controller *CMPv2IssuerController) Reconcile(req ctrl.Request) (ctrl.Result, error) { ctx := context.Background() - log := controller.Log.WithValues("cmpv2-issuer-controller", req.NamespacedName) + log := leveledlogger.GetLoggerWithValues("cmpv2-issuer-controller", req.NamespacedName) // 1. Load CMPv2Issuer issuer := new(cmpv2api.CMPv2Issuer) @@ -67,8 +68,8 @@ func (controller *CMPv2IssuerController) Reconcile(req ctrl.Request) (ctrl.Resul log.Info("CMPv2Issuer loaded: ", "issuer", issuer) // 2. Validate CMPv2Issuer - statusUpdater := newStatusUpdater(controller, issuer, log) - if err := validateCMPv2IssuerSpec(issuer.Spec, log); err != nil { + statusUpdater := updater.NewCMPv2IssuerStatusUpdater(controller.Client, controller.Recorder, issuer, controller.Clock, log) + if err := validateCMPv2IssuerSpec(issuer.Spec); err != nil { handleErrorCMPv2IssuerValidation(ctx, log, err, statusUpdater) return ctrl.Result{}, err } @@ -118,7 +119,7 @@ func (controller *CMPv2IssuerController) loadResource(ctx context.Context, key c return controller.Client.Get(ctx, key, obj) } -func validateCMPv2IssuerSpec(issuerSpec cmpv2api.CMPv2IssuerSpec, log logr.Logger) error { +func validateCMPv2IssuerSpec(issuerSpec cmpv2api.CMPv2IssuerSpec) error { switch { case issuerSpec.URL == "": return fmt.Errorf("spec.url cannot be empty") @@ -137,36 +138,36 @@ func validateCMPv2IssuerSpec(issuerSpec cmpv2api.CMPv2IssuerSpec, log logr.Logge } } -func updateCMPv2IssuerStatusToVerified(statusUpdater *CMPv2IssuerStatusUpdater, ctx context.Context, log logr.Logger) error { +func updateCMPv2IssuerStatusToVerified(statusUpdater *updater.CMPv2IssuerStatusUpdater, ctx context.Context, log leveledlogger.Logger) error { log.Info("CMPv2 provisioner created -> updating status to of CMPv2Issuer resource to: Verified") - return statusUpdater.Update(ctx, cmpv2api.ConditionTrue, Verified, "CMPv2Issuer verified and ready to sign certificates") + return statusUpdater.Update(ctx, cmpv2api.ConditionTrue, updater.Verified, "CMPv2Issuer verified and ready to sign certificates") } // Error handling -func handleErrorUpdatingCMPv2IssuerStatus(log logr.Logger, err error) { +func handleErrorUpdatingCMPv2IssuerStatus(log leveledlogger.Logger, err error) { log.Error(err, "Failed to update CMPv2Issuer status") } -func handleErrorLoadingCMPv2Issuer(log logr.Logger, err error) { +func handleErrorLoadingCMPv2Issuer(log leveledlogger.Logger, err error) { log.Error(err, "Failed to retrieve CMPv2Issuer resource") } -func handleErrorProvisionerInitialization(ctx context.Context, log logr.Logger, err error, statusUpdater *CMPv2IssuerStatusUpdater) { +func handleErrorProvisionerInitialization(ctx context.Context, log leveledlogger.Logger, err error, statusUpdater *updater.CMPv2IssuerStatusUpdater) { log.Error(err, "Failed to initialize provisioner") - statusUpdater.UpdateNoError(ctx, cmpv2api.ConditionFalse, Error, "Failed to initialize provisioner: %v", err) + statusUpdater.UpdateNoError(ctx, cmpv2api.ConditionFalse, updater.Error, "Failed to initialize provisioner: %v", err) } -func handleErrorCMPv2IssuerValidation(ctx context.Context, log logr.Logger, err error, statusUpdater *CMPv2IssuerStatusUpdater) { +func handleErrorCMPv2IssuerValidation(ctx context.Context, log leveledlogger.Logger, err error, statusUpdater *updater.CMPv2IssuerStatusUpdater) { log.Error(err, "Failed to validate CMPv2Issuer resource") - statusUpdater.UpdateNoError(ctx, cmpv2api.ConditionFalse, ValidationFailed, "Failed to validate resource: %v", err) + statusUpdater.UpdateNoError(ctx, cmpv2api.ConditionFalse, updater.ValidationFailed, "Failed to validate resource: %v", err) } -func handleErrorInvalidSecret(ctx context.Context, log logr.Logger, err error, statusUpdater *CMPv2IssuerStatusUpdater, secretNamespaceName types.NamespacedName) { +func handleErrorInvalidSecret(ctx context.Context, log leveledlogger.Logger, err error, statusUpdater *updater.CMPv2IssuerStatusUpdater, secretNamespaceName types.NamespacedName) { log.Error(err, "Failed to retrieve CMPv2Issuer provisioner secret", "namespace", secretNamespaceName.Namespace, "name", secretNamespaceName.Name) if apierrors.IsNotFound(err) { - statusUpdater.UpdateNoError(ctx, cmpv2api.ConditionFalse, NotFound, "Failed to retrieve provisioner secret: %v", err) + statusUpdater.UpdateNoError(ctx, cmpv2api.ConditionFalse, updater.NotFound, "Failed to retrieve provisioner secret: %v", err) } else { - statusUpdater.UpdateNoError(ctx, cmpv2api.ConditionFalse, Error, "Failed to retrieve provisioner secret: %v", err) + statusUpdater.UpdateNoError(ctx, cmpv2api.ConditionFalse, updater.Error, "Failed to retrieve provisioner secret: %v", err) } } diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_controller_test.go b/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_controller_test.go index f4cb6944..cc3ba9f5 100644 --- a/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_controller_test.go +++ b/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_controller_test.go @@ -23,17 +23,15 @@ package cmpv2controller import ( "testing" - "github.com/go-logr/logr" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" "k8s.io/client-go/tools/record" "k8s.io/utils/clock" - ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" provisioners "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner" + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" "onap.org/oom-certservice/k8s-external-provider/src/testdata" ) @@ -60,13 +58,13 @@ func Test_shouldPrepareAndVerifyCMPv2Issuer_whenRequestReceived(t *testing.T) { func Test_shouldBeValidCMPv2IssuerSpec_whenAllFieldsAreSet(t *testing.T) { spec := testdata.GetValidCMPv2IssuerSpec() - err := validateCMPv2IssuerSpec(spec, &MockLogger{}) + err := validateCMPv2IssuerSpec(spec) assert.Nil(t, err) } func Test_shouldBeInvalidCMPv2IssuerSpec_whenSpecIsEmpty(t *testing.T) { spec := cmpv2api.CMPv2IssuerSpec{} - err := validateCMPv2IssuerSpec(spec, nil) + err := validateCMPv2IssuerSpec(spec) assert.NotNil(t, err) } @@ -90,13 +88,13 @@ func Test_shouldBeInvalidCMPv2IssuerSpec_whenNotAllFieldsAreSet(t *testing.T) { func test_shouldBeInvalidCMPv2IssuerSpec_whenFunctionApplied(t *testing.T, transformSpec func(spec *cmpv2api.CMPv2IssuerSpec)) { spec := testdata.GetValidCMPv2IssuerSpec() transformSpec(&spec) - err := validateCMPv2IssuerSpec(spec, nil) + err := validateCMPv2IssuerSpec(spec) assert.NotNil(t, err) } func getCMPv2IssuerController(fakeRecorder *record.FakeRecorder, mockClient client.Client) CMPv2IssuerController { controller := CMPv2IssuerController{ - Log: ctrl.Log.WithName("controllers").WithName("CertificateRequest"), + Log: leveledlogger.GetLoggerWithValues("controllers", "CMPv2Issuer"), Clock: clock.RealClock{}, Recorder: fakeRecorder, Client: mockClient, @@ -104,14 +102,3 @@ func getCMPv2IssuerController(fakeRecorder *record.FakeRecorder, mockClient clie } return controller } - -type MockLogger struct { - mock.Mock -} - -func (m *MockLogger) Info(msg string, keysAndValues ...interface{}) {} -func (m *MockLogger) Error(err error, msg string, keysAndValues ...interface{}) {} -func (m *MockLogger) Enabled() bool { return false } -func (m *MockLogger) V(level int) logr.Logger { return m } -func (m *MockLogger) WithValues(keysAndValues ...interface{}) logr.Logger { return m } -func (m *MockLogger) WithName(name string) logr.Logger { return m } diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger.go b/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger.go index 0aaf48d3..649ce47f 100644 --- a/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger.go +++ b/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger.go @@ -26,8 +26,9 @@ import ( "net/url" "strconv" - "github.com/go-logr/logr" cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" + + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" ) const ( @@ -35,28 +36,33 @@ const ( CMPv2ServerName = "CMPv2 Server" ) -func LogCertRequestProperties(log logr.Logger, request *cmapi.CertificateRequest, csr *x509.CertificateRequest) { - logSupportedProperties(log, request, csr) +func LogCertRequestProperties(log leveledlogger.Logger, request *cmapi.CertificateRequest, csr *x509.CertificateRequest) { + logSupportedProperties(log, csr) logPropertiesNotSupportedByCertService(log, request, csr) logPropertiesOverriddenByCMPv2Server(log, request) } -func logSupportedProperties(log logr.Logger, request *cmapi.CertificateRequest, csr *x509.CertificateRequest) { - logSupportedProperty(log, csr.Subject.Organization, "organization") - logSupportedProperty(log, csr.Subject.OrganizationalUnit, "organization unit") - logSupportedProperty(log, csr.Subject.Country, "country") - logSupportedProperty(log, csr.Subject.Province, "state") - logSupportedProperty(log, csr.Subject.Locality, "location") - logSupportedProperty(log, csr.DNSNames, "dns names") +func logSupportedProperties(log leveledlogger.Logger, csr *x509.CertificateRequest) { + logSupportedSingleValueProperty(log, csr.Subject.CommonName, "common name") + logSupportedMultiValueProperty(log, csr.Subject.Organization, "organization") + logSupportedMultiValueProperty(log, csr.Subject.OrganizationalUnit, "organization unit") + logSupportedMultiValueProperty(log, csr.Subject.Country, "country") + logSupportedMultiValueProperty(log, csr.Subject.Province, "state") + logSupportedMultiValueProperty(log, csr.Subject.Locality, "location") + logSupportedMultiValueProperty(log, csr.DNSNames, "dns names") } -func logSupportedProperty(log logr.Logger, values []string, propertyName string) { +func logSupportedMultiValueProperty(log leveledlogger.Logger, values []string, propertyName string) { if len(values) > 0 { log.Info(getSupportedMessage(propertyName, extractStringArray(values))) } } -func logPropertiesOverriddenByCMPv2Server(log logr.Logger, request *cmapi.CertificateRequest) { +func logSupportedSingleValueProperty(log leveledlogger.Logger, value string, propertyName string) { + log.Info(getSupportedMessage(propertyName, value)) +} + +func logPropertiesOverriddenByCMPv2Server(log leveledlogger.Logger, request *cmapi.CertificateRequest) { if request.Spec.Duration != nil && len(request.Spec.Duration.String()) > 0 { log.Info(getOverriddenMessage("duration", request.Spec.Duration.Duration.String())) } @@ -73,36 +79,36 @@ func extractUsages(usages []cmapi.KeyUsage) string { return values } -func logPropertiesNotSupportedByCertService(log logr.Logger, request *cmapi.CertificateRequest, csr *x509.CertificateRequest) { +func logPropertiesNotSupportedByCertService(log leveledlogger.Logger, request *cmapi.CertificateRequest, csr *x509.CertificateRequest) { //IP addresses in SANs if len(csr.IPAddresses) > 0 { - log.Info(getNotSupportedMessage("ipAddresses", extractIPAddresses(csr.IPAddresses))) + log.Warning(getNotSupportedMessage("ipAddresses", extractIPAddresses(csr.IPAddresses))) } //URIs in SANs if len(csr.URIs) > 0 { - log.Info(getNotSupportedMessage("uris", extractURIs(csr.URIs))) + log.Warning(getNotSupportedMessage("uris", extractURIs(csr.URIs))) } //Email addresses in SANs if len(csr.EmailAddresses) > 0 { - log.Info(getNotSupportedMessage("emailAddresses", extractStringArray(csr.EmailAddresses))) + log.Warning(getNotSupportedMessage("emailAddresses", extractStringArray(csr.EmailAddresses))) } if request.Spec.IsCA == true { - log.Info(getNotSupportedMessage("isCA", strconv.FormatBool(request.Spec.IsCA))) + log.Warning(getNotSupportedMessage("isCA", strconv.FormatBool(request.Spec.IsCA))) } if len(csr.Subject.StreetAddress) > 0 { - log.Info(getNotSupportedMessage("subject.streetAddress", extractStringArray(csr.Subject.StreetAddress))) + log.Warning(getNotSupportedMessage("subject.streetAddress", extractStringArray(csr.Subject.StreetAddress))) } if len(csr.Subject.PostalCode) > 0 { - log.Info(getNotSupportedMessage("subject.postalCodes", extractStringArray(csr.Subject.PostalCode))) + log.Warning(getNotSupportedMessage("subject.postalCodes", extractStringArray(csr.Subject.PostalCode))) } if len(csr.Subject.SerialNumber) > 0 { - log.Info(getNotSupportedMessage("subject.serialNumber", csr.Subject.SerialNumber)) + log.Warning(getNotSupportedMessage("subject.serialNumber", csr.Subject.SerialNumber)) } } @@ -131,14 +137,14 @@ func extractIPAddresses(addresses []net.IP) string { return values } -func getNotSupportedMessage(property string, value string) string { - return "WARNING: Property '" + property + "' with value: " + value + " is not supported by " + CertServiceName +func getSupportedMessage(property string, value string) string { + return "+ property '" + property + "' with value '" + value + "' will be sent in certificate signing request to " + CMPv2ServerName } -func getSupportedMessage(property string, value string) string { - return "Property '" + property + "' with value: " + value + " will be sent in certificate signing request to " + CMPv2ServerName +func getNotSupportedMessage(property string, value string) string { + return "- property '" + property + "' with value '" + value + "' is not supported by " + CertServiceName } func getOverriddenMessage(property string, values string) string { - return "Property '" + property + "' with value: " + values + " will be overridden by " + CMPv2ServerName + return "* property '" + property + "' with value '" + values + "' will be overridden by " + CMPv2ServerName } diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger_test.go b/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger_test.go index ea1076dc..250fab8b 100644 --- a/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger_test.go +++ b/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger_test.go @@ -22,7 +22,8 @@ package logger import ( "bytes" - "flag" + "io/ioutil" + "log" "os" "strings" "testing" @@ -31,35 +32,40 @@ import ( cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog/v2" - "k8s.io/klog/v2/klogr" + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" x509utils "onap.org/oom-certservice/k8s-external-provider/src/x509" ) -var checkedLogMessages = [7]string{"Property 'duration'", "Property 'usages'", "Property 'ipAddresses'", - "Property 'isCA'", "Property 'subject.streetAddress'", "Property 'subject.postalCodes'", - "Property 'subject.serialNumber'"} - -var supportedProperties = [7]string{"Property 'organization'", "Property 'organization unit'", "Property 'country'", - "Property 'state'", "Property 'location'", "Property 'dns names'"} - +var unsupportedProperties = []string{ + "* property 'duration'", + "* property 'usages'", + "- property 'ipAddresses'", + "- property 'isCA'", + "- property 'subject.streetAddress'", + "- property 'subject.postalCodes'", + "- property 'subject.serialNumber'"} + +var supportedProperties = []string{ + "+ property 'common name'", + "+ property 'organization'", + "+ property 'organization unit'", + "+ property 'country'", + "+ property 'state'", + "+ property 'location'", + "+ property 'dns names'"} + +const RESULT_LOG = "testdata/test_result.log" func TestMain(m *testing.M) { - klog.InitFlags(nil) - flag.CommandLine.Set("v", "10") - flag.CommandLine.Set("skip_headers", "true") - flag.CommandLine.Set("logtostderr", "false") - flag.CommandLine.Set("alsologtostderr", "false") - flag.Parse() + leveledlogger.SetConfigFileName("testdata/test_logger_config.json") os.Exit(m.Run()) } func TestLogShouldNotProvideInformationAboutSkippedPropertiesIfNotExistInCSR(t *testing.T) { //given - logger := klogr.New() + logger := leveledlogger.GetLoggerWithName("test") request := getCertificateRequestWithoutSkippedProperties() - tmpWriteBuffer := getLogBuffer() csr, err := x509utils.DecodeCSR(request.Spec.Request) if err != nil { @@ -68,19 +74,19 @@ func TestLogShouldNotProvideInformationAboutSkippedPropertiesIfNotExistInCSR(t * //when LogCertRequestProperties(logger, request, csr) - closeLogBuffer() - logsArray := convertBufferToStringArray(tmpWriteBuffer) + logsArray := convertLogFileToStringArray(RESULT_LOG) + //then - for _, logMsg := range checkedLogMessages { - assert.False(t, logsContainExpectedMessage(logsArray, logMsg), "Logs contain: "+logMsg+", but should not") + for _, logMsg := range unsupportedProperties { + assert.False(t, logsContainExpectedMessage(logsArray, logMsg), "Logs should not contain: ["+logMsg+"]") } + removeTemporaryFile(RESULT_LOG) } func TestLogShouldProvideInformationAboutSkippedPropertiesIfExistInCSR(t *testing.T) { //given - logger := klogr.New() + logger := leveledlogger.GetLoggerWithName("test") request := getCertificateRequestWithSkippedProperties() - tmpWriteBuffer := getLogBuffer() csr, err := x509utils.DecodeCSR(request.Spec.Request) if err != nil { @@ -89,20 +95,19 @@ func TestLogShouldProvideInformationAboutSkippedPropertiesIfExistInCSR(t *testin //when LogCertRequestProperties(logger, request, csr) - closeLogBuffer() - logsArray := convertBufferToStringArray(tmpWriteBuffer) + logsArray := convertLogFileToStringArray(RESULT_LOG) //then - for _, logMsg := range checkedLogMessages { - assert.True(t, logsContainExpectedMessage(logsArray, logMsg), "Logs not contain: "+logMsg) + for _, logMsg := range unsupportedProperties { + assert.True(t, logsContainExpectedMessage(logsArray, logMsg), "Logs should contain: ["+logMsg+"]") } + removeTemporaryFile(RESULT_LOG) } func TestLogShouldListSupportedProperties(t *testing.T) { //given - logger := klogr.New() + logger := leveledlogger.GetLoggerWithName("test") request := getCertificateRequestWithoutSkippedProperties() - tmpWriteBuffer := getLogBuffer() csr, err := x509utils.DecodeCSR(request.Spec.Request) if err != nil { @@ -111,13 +116,13 @@ func TestLogShouldListSupportedProperties(t *testing.T) { //when LogCertRequestProperties(logger, request, csr) - closeLogBuffer() - logsArray := convertBufferToStringArray(tmpWriteBuffer) + logsArray := convertLogFileToStringArray(RESULT_LOG) //then for _, logMsg := range supportedProperties { - assert.True(t, logsContainExpectedMessage(logsArray, logMsg), "Logs not contain: "+logMsg) + assert.True(t, logsContainExpectedMessage(logsArray, logMsg), "Logs should contain: ["+logMsg+"]") } + removeTemporaryFile(RESULT_LOG) } func getCertificateRequestWithoutSkippedProperties() *cmapi.CertificateRequest { @@ -135,18 +140,31 @@ func getCertificateRequestWithSkippedProperties() *cmapi.CertificateRequest { return request } -func getLogBuffer() *bytes.Buffer { - tmpWriteBuffer := bytes.NewBuffer(nil) - klog.SetOutput(tmpWriteBuffer) - return tmpWriteBuffer +func convertBufferToStringArray(buffer *bytes.Buffer) []string { + return strings.Split(buffer.String(), "\n") } -func closeLogBuffer() { - klog.Flush() +func convertLogFileToStringArray(filename string) []string { + buffer := bytes.NewBuffer(make([]byte, 0)) + buffer.Write(readFile(filename)) + return convertBufferToStringArray(buffer) } -func convertBufferToStringArray(buffer *bytes.Buffer) []string { - return strings.Split(buffer.String(), "\n") +func readFile(filename string) []byte { + certRequest, err := ioutil.ReadFile(filename) + if err != nil { + log.Fatal(err) + } + return certRequest +} + +func removeTemporaryFile(fileName string) { + if _, err := os.Stat(fileName); err == nil { + e := os.Remove(fileName) + if e != nil { + log.Fatal(e) + } + } } func logsContainExpectedMessage(array []string, expectedMsg string) bool { diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/logger/testdata/test_logger_config.json b/certServiceK8sExternalProvider/src/cmpv2controller/logger/testdata/test_logger_config.json new file mode 100644 index 00000000..02030b6e --- /dev/null +++ b/certServiceK8sExternalProvider/src/cmpv2controller/logger/testdata/test_logger_config.json @@ -0,0 +1,11 @@ +{ + "level": "debug", + "encoding": "json", + "outputPaths": ["stdout", "testdata/test_result.log"], + "encoderConfig": { + "messageKey": "message", + "levelKey": "level", + "nameKey": "name", + "levelEncoder": "capital" + } +} diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/updater/certificate_request_status_updater.go b/certServiceK8sExternalProvider/src/cmpv2controller/updater/certificate_request_status_updater.go new file mode 100644 index 00000000..d4ed0237 --- /dev/null +++ b/certServiceK8sExternalProvider/src/cmpv2controller/updater/certificate_request_status_updater.go @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * This source code was copied from the following git repository: + * https://github.com/smallstep/step-issuer + * The source code was modified for usage in the ONAP project. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package updater + +import ( + "context" + "fmt" + + apiutil "github.com/jetstack/cert-manager/pkg/api/util" + cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" + cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" +) + +type CertificateRequestStatusUpdater struct { + client client.Client + recorder record.EventRecorder + logger leveledlogger.Logger + ctx context.Context + certificateRequest *cmapi.CertificateRequest +} + +func NewCertificateRequestUpdater(client client.Client, + recorder record.EventRecorder, certificateRequest *cmapi.CertificateRequest, ctx context.Context, log leveledlogger.Logger) *CertificateRequestStatusUpdater { + return &CertificateRequestStatusUpdater{ + client: client, + recorder: recorder, + logger: log, + ctx: ctx, + certificateRequest: certificateRequest, + } +} + +func (instance *CertificateRequestStatusUpdater) UpdateStatusWithEventTypeWarning(reason string, message string, args ...interface{}) error { + return instance.updateStatus(cmmeta.ConditionFalse, reason, message, args...) +} + +func (instance *CertificateRequestStatusUpdater) UpdateCertificateRequestWithSignedCertificates() error { + return instance.updateStatus(cmmeta.ConditionTrue, cmapi.CertificateRequestReasonIssued, "Certificate issued") +} + +func (instance *CertificateRequestStatusUpdater) updateStatus(status cmmeta.ConditionStatus, reason string, message string, args ...interface{}) error { + completeMessage := fmt.Sprintf(message, args...) + apiutil.SetCertificateRequestCondition(instance.certificateRequest, cmapi.CertificateRequestConditionReady, status, reason, completeMessage) + + FireEventCert(instance.recorder, instance.certificateRequest, status, reason, completeMessage) + + return instance.client.Status().Update(instance.ctx, instance.certificateRequest) +} diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_status_updater.go b/certServiceK8sExternalProvider/src/cmpv2controller/updater/cmpv2_issuer_status_updater.go index f07101db..e11c2b02 100644 --- a/certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_status_updater.go +++ b/certServiceK8sExternalProvider/src/cmpv2controller/updater/cmpv2_issuer_status_updater.go @@ -23,50 +23,51 @@ * ============LICENSE_END========================================================= */ -package cmpv2controller +package updater import ( "context" "fmt" - "github.com/go-logr/logr" - core "k8s.io/api/core/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + "k8s.io/utils/clock" + "sigs.k8s.io/controller-runtime/pkg/client" "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" ) type CMPv2IssuerStatusUpdater struct { - *CMPv2IssuerController - issuer *cmpv2api.CMPv2Issuer - logger logr.Logger + client client.Client + recorder record.EventRecorder + issuer *cmpv2api.CMPv2Issuer + clock clock.Clock + logger leveledlogger.Logger } -func newStatusUpdater(controller *CMPv2IssuerController, issuer *cmpv2api.CMPv2Issuer, log logr.Logger) *CMPv2IssuerStatusUpdater { +func NewCMPv2IssuerStatusUpdater(client client.Client, recorder record.EventRecorder, issuer *cmpv2api.CMPv2Issuer, clock clock.Clock, log leveledlogger.Logger) *CMPv2IssuerStatusUpdater { return &CMPv2IssuerStatusUpdater{ - CMPv2IssuerController: controller, - issuer: issuer, - logger: log, + client: client, + recorder: recorder, + issuer: issuer, + clock: clock, + logger: log, } } -func (updater *CMPv2IssuerStatusUpdater) Update(ctx context.Context, status cmpv2api.ConditionStatus, reason, message string, args ...interface{}) error { +func (instance *CMPv2IssuerStatusUpdater) Update(ctx context.Context, status cmpv2api.ConditionStatus, reason, message string, args ...interface{}) error { completeMessage := fmt.Sprintf(message, args...) - updater.setCondition(status, reason, completeMessage) + instance.setCondition(status, reason, completeMessage) - // Fire an Event to additionally inform users of the change - eventType := core.EventTypeNormal - if status == cmpv2api.ConditionFalse { - eventType = core.EventTypeWarning - } - updater.Recorder.Event(updater.issuer, eventType, reason, completeMessage) + FireEventIssuer(instance.recorder, instance.issuer, status, reason, completeMessage) - return updater.Client.Update(ctx, updater.issuer) + return instance.client.Update(ctx, instance.issuer) } -func (updater *CMPv2IssuerStatusUpdater) UpdateNoError(ctx context.Context, status cmpv2api.ConditionStatus, reason, message string, args ...interface{}) { - if err := updater.Update(ctx, status, reason, message, args...); err != nil { - updater.logger.Error(err, "failed to update", "status", status, "reason", reason) +func (instance *CMPv2IssuerStatusUpdater) UpdateNoError(ctx context.Context, status cmpv2api.ConditionStatus, reason, message string, args ...interface{}) { + if err := instance.Update(ctx, status, reason, message, args...); err != nil { + instance.logger.Error(err, "failed to update", "status", status, "reason", reason) } } @@ -79,8 +80,8 @@ func (updater *CMPv2IssuerStatusUpdater) UpdateNoError(ctx context.Context, stat // - If a condition of the same type and different state already exists, the // condition will be updated and the LastTransitionTime set to the current // time. -func (updater *CMPv2IssuerStatusUpdater) setCondition(status cmpv2api.ConditionStatus, reason, message string) { - now := meta.NewTime(updater.Clock.Now()) +func (instance *CMPv2IssuerStatusUpdater) setCondition(status cmpv2api.ConditionStatus, reason, message string) { + now := meta.NewTime(instance.clock.Now()) issuerCondition := cmpv2api.CMPv2IssuerCondition{ Type: cmpv2api.ConditionReady, Status: status, @@ -90,7 +91,7 @@ func (updater *CMPv2IssuerStatusUpdater) setCondition(status cmpv2api.ConditionS } // Search through existing conditions - for i, condition := range updater.issuer.Status.Conditions { + for i, condition := range instance.issuer.Status.Conditions { // Skip unrelated conditions if condition.Type != cmpv2api.ConditionReady { continue @@ -101,16 +102,16 @@ func (updater *CMPv2IssuerStatusUpdater) setCondition(status cmpv2api.ConditionS if condition.Status == status { issuerCondition.LastTransitionTime = condition.LastTransitionTime } else { - updater.logger.Info("found status change for CMPv2Issuer condition; setting lastTransitionTime", "condition", condition.Type, "old_status", condition.Status, "new_status", status, "time", now.Time) + instance.logger.Info("found status change for CMPv2Issuer condition; setting lastTransitionTime", "condition", condition.Type, "old_status", condition.Status, "new_status", status, "time", now.Time) } // Overwrite the existing condition - updater.issuer.Status.Conditions[i] = issuerCondition + instance.issuer.Status.Conditions[i] = issuerCondition return } // If we've not found an existing condition of this type, we simply insert // the new condition into the slice. - updater.issuer.Status.Conditions = append(updater.issuer.Status.Conditions, issuerCondition) - updater.logger.Info("setting lastTransitionTime for CMPv2Issuer condition", "condition", cmpv2api.ConditionReady, "time", now.Time) + instance.issuer.Status.Conditions = append(instance.issuer.Status.Conditions, issuerCondition) + instance.logger.Info("setting lastTransitionTime for CMPv2Issuer condition", "condition", cmpv2api.ConditionReady, "time", now.Time) } diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/updater/k8s_resource_updater.go b/certServiceK8sExternalProvider/src/cmpv2controller/updater/k8s_resource_updater.go new file mode 100644 index 00000000..e638d84a --- /dev/null +++ b/certServiceK8sExternalProvider/src/cmpv2controller/updater/k8s_resource_updater.go @@ -0,0 +1,49 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package updater + +import ( + core "k8s.io/api/core/v1" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + + cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" + + "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" +) + +// Fire an Event to additionally inform users of the change +func FireEventCert(recorder record.EventRecorder, resource runtime.Object, status cmmeta.ConditionStatus, reason string, message string) { + eventType := core.EventTypeNormal + if status == cmmeta.ConditionFalse { + eventType = core.EventTypeWarning + } + recorder.Event(resource, eventType, reason, message) +} + +func FireEventIssuer(recorder record.EventRecorder, resource runtime.Object, status cmpv2api.ConditionStatus, reason string, message string) { + eventType := core.EventTypeNormal + if status == cmpv2api.ConditionFalse { + eventType = core.EventTypeWarning + } + recorder.Event(resource, eventType, reason, message) +} diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/updater/k8s_resource_updater_test.go b/certServiceK8sExternalProvider/src/cmpv2controller/updater/k8s_resource_updater_test.go new file mode 100644 index 00000000..553c419f --- /dev/null +++ b/certServiceK8sExternalProvider/src/cmpv2controller/updater/k8s_resource_updater_test.go @@ -0,0 +1,68 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package updater + +import ( + "testing" + + cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" + "github.com/stretchr/testify/assert" + "k8s.io/client-go/tools/record" + + "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" +) + +const ( + recorderBufferSize = 3 +) + + +func Test_shouldFireWarningEvent_forCmpv2Issuer(t *testing.T) { + fakeRecorder := record.NewFakeRecorder(recorderBufferSize) + + FireEventIssuer(fakeRecorder, nil, cmpv2api.ConditionFalse, "testReason", "testMessage") + + assert.Equal(t, <-fakeRecorder.Events, "Warning testReason testMessage") +} + +func Test_shouldFireNormalEvent_forCmpv2Issuer(t *testing.T) { + fakeRecorder := record.NewFakeRecorder(recorderBufferSize) + + FireEventIssuer(fakeRecorder, nil, cmpv2api.ConditionTrue, "testReason", "testMessage") + + assert.Equal(t, <-fakeRecorder.Events, "Normal testReason testMessage") +} + +func Test_shouldFireWarningEvent_forCertRequest(t *testing.T) { + fakeRecorder := record.NewFakeRecorder(recorderBufferSize) + + FireEventCert(fakeRecorder, nil, cmmeta.ConditionFalse, "testReason", "testMessage") + + assert.Equal(t, <-fakeRecorder.Events, "Warning testReason testMessage") +} + +func Test_shouldFireNormalEvent_forCertRequest(t *testing.T) { + fakeRecorder := record.NewFakeRecorder(recorderBufferSize) + + FireEventCert(fakeRecorder, nil, cmmeta.ConditionTrue, "testReason", "testMessage") + + assert.Equal(t, <-fakeRecorder.Events, "Normal testReason testMessage") +} diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/status_reason.go b/certServiceK8sExternalProvider/src/cmpv2controller/updater/status_reason.go index fc1772e9..8fe8664c 100644 --- a/certServiceK8sExternalProvider/src/cmpv2controller/status_reason.go +++ b/certServiceK8sExternalProvider/src/cmpv2controller/updater/status_reason.go @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package cmpv2controller +package updater const ( NotFound = "NotFound" diff --git a/certServiceK8sExternalProvider/src/cmpv2provisioner/cmpv2_provisioner.go b/certServiceK8sExternalProvider/src/cmpv2provisioner/cmpv2_provisioner.go index 14cb228f..e89eb1f4 100644 --- a/certServiceK8sExternalProvider/src/cmpv2provisioner/cmpv2_provisioner.go +++ b/certServiceK8sExternalProvider/src/cmpv2provisioner/cmpv2_provisioner.go @@ -31,8 +31,8 @@ import ( certmanager "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" + "onap.org/oom-certservice/k8s-external-provider/src/leveledlogger" "onap.org/oom-certservice/k8s-external-provider/src/certserviceclient" "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner/csr" @@ -59,14 +59,14 @@ func New(cmpv2Issuer *cmpv2api.CMPv2Issuer, certServiceClient certserviceclient. ca.certEndpoint = cmpv2Issuer.Spec.CertEndpoint ca.certServiceClient = certServiceClient - log := ctrl.Log.WithName("cmpv2-provisioner") + log := leveledlogger.GetLoggerWithName("cmpv2-provisioner") log.Info("Configuring CA: ", "name", ca.name, "url", ca.url, "caName", ca.caName, "healthEndpoint", ca.healthEndpoint, "certEndpoint", ca.certEndpoint) return &ca, nil } func (ca *CertServiceCA) CheckHealth() error { - log := ctrl.Log.WithName("cmpv2-provisioner") + log := leveledlogger.GetLoggerWithName("cmpv2-provisioner") log.Info("Checking health of CMPv2 issuer: ", "name", ca.name) return ca.certServiceClient.CheckHealth() } @@ -89,26 +89,27 @@ func (ca *CertServiceCA) Sign( certificateRequest *certmanager.CertificateRequest, privateKeyBytes []byte, ) (signedCertificateChain []byte, trustedCertificates []byte, err error) { - log := ctrl.Log.WithName("certservice-provisioner") + log := leveledlogger.GetLoggerWithName("certservice-provisioner") log.Info("Signing certificate: ", "cert-name", certificateRequest.Name) log.Info("CA: ", "name", ca.name, "url", ca.url) csrBytes := certificateRequest.Spec.Request - log.Info("Csr PEM: ", "bytes", csrBytes) + log.Debug("Original CSR PEM: ", "bytes", csrBytes) filteredCsrBytes, err := csr.FilterFieldsFromCSR(csrBytes, privateKeyBytes) if err != nil { return nil, nil, err } + log.Debug("Filtered out CSR PEM: ", "bytes", csrBytes) response, err := ca.certServiceClient.GetCertificates(filteredCsrBytes, privateKeyBytes) if err != nil { return nil, nil, err } log.Info("Successfully received response from CertService API") - log.Info("Certificate Chain", "cert-chain", response.CertificateChain) - log.Info("Trusted Certificates", "trust-certs", response.TrustedCertificates) + log.Debug("Certificate Chain", "cert-chain", response.CertificateChain) + log.Debug("Trusted Certificates", "trust-certs", response.TrustedCertificates) log.Info("Start parsing response") signedCertificateChain, trustedCertificates, signErr := parseResponseToBytes(response) @@ -120,9 +121,8 @@ func (ca *CertServiceCA) Sign( log.Info("Successfully signed: ", "cert-name", certificateRequest.Name) - //TODO Debug level or skip - log.Info("Signed cert PEM: ", "bytes", signedCertificateChain) - log.Info("Trusted CA PEM: ", "bytes", trustedCertificates) + log.Debug("Signed cert PEM: ", "bytes", signedCertificateChain) + log.Debug("Trusted CA PEM: ", "bytes", trustedCertificates) return signedCertificateChain, trustedCertificates, nil } diff --git a/certServiceK8sExternalProvider/src/leveledlogger/logger.go b/certServiceK8sExternalProvider/src/leveledlogger/logger.go new file mode 100644 index 00000000..ee839cbc --- /dev/null +++ b/certServiceK8sExternalProvider/src/leveledlogger/logger.go @@ -0,0 +1,138 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package leveledlogger + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + + "github.com/go-logr/logr" + "go.uber.org/zap/zapcore" + "github.com/go-logr/zapr" + "go.uber.org/zap" +) + +const ( + WARNING = int(zapcore.WarnLevel) * -1 + INFO = int(zapcore.InfoLevel) * -1 + DEBUG = int(zapcore.DebugLevel) * -1 +) + +type Logger struct { + Log logr.Logger + ConfigFile string +} + +var configFileName = "default" +var logLevel = "warn" + +func SetConfigFileName(newName string) { + configFileName = newName +} + +func SetLogLevel(level string) { + logLevel = level +} + +func GetLogger() Logger { + var cfg zap.Config + + if err := json.Unmarshal(getConfig(), &cfg); err != nil { + panic(err) + } + logger, err := cfg.Build() + if err != nil { + panic(err) + } + + leveledLogger := Logger{ + Log: zapr.NewLogger(logger), + } + return leveledLogger +} + +func GetLoggerWithValues(keysAndValues ...interface{}) Logger { + leveledLogger := GetLogger() + leveledLogger.Log = leveledLogger.Log.WithValues(keysAndValues...) + return leveledLogger +} + +func GetLoggerWithName(name string) Logger { + leveledLogger := GetLogger() + leveledLogger.Log = leveledLogger.Log.WithName(name) + return leveledLogger +} + +func (logger *Logger) Error(err error, message string, keysAndValues ...interface{}) { + logger.Log.Error(err, message, keysAndValues...) +} + +func (logger *Logger) Warning(message string, keysAndValues ...interface{}) { + logger.log(message, WARNING, keysAndValues...) +} + +func (logger *Logger) Info(message string, keysAndValues ...interface{}) { + logger.log(message, INFO, keysAndValues...) +} + +func (logger *Logger) Debug(message string, keysAndValues ...interface{}) { + logger.log(message, DEBUG, keysAndValues...) +} + +func (logger *Logger) log(message string, lvl int, keysAndValues ...interface{}) { + logger.Log.V(lvl).Info(message, keysAndValues...) +} + +func getDefaultConfig() []byte { + return []byte(fmt.Sprintf(`{ + "level": "%s", + "encoding": "console", + "outputPaths": ["stdout"], + "encoderConfig": { + "timeKey": "timeKey", + "messageKey": "message", + "levelKey": "level", + "nameKey": "name", + "levelEncoder": "capital", + "timeEncoder": "iso8601" + } + }`, logLevel)) +} + +func getConfig() []byte { + var config = []byte{} + if configFileName == "default" { + config = getDefaultConfig() + } else { + config = readFile(configFileName) + } + return config +} + +func readFile(filename string) []byte { + certRequest, err := ioutil.ReadFile(filename) + if err != nil { + log.Fatal(err) + } + return certRequest +} diff --git a/certServiceK8sExternalProvider/src/leveledlogger/logger_config.json b/certServiceK8sExternalProvider/src/leveledlogger/logger_config.json new file mode 100644 index 00000000..96ba7024 --- /dev/null +++ b/certServiceK8sExternalProvider/src/leveledlogger/logger_config.json @@ -0,0 +1,13 @@ +{ + "level": "debug", + "encoding": "console", + "outputPaths": ["stdout"], + "encoderConfig": { + "timeKey": "timeKey", + "messageKey": "message", + "levelKey": "level", + "nameKey": "name", + "levelEncoder": "capital", + "timeEncoder": "iso8601" + } +} diff --git a/certServiceK8sExternalProvider/src/leveledlogger/logger_test.go b/certServiceK8sExternalProvider/src/leveledlogger/logger_test.go new file mode 100644 index 00000000..84aa5907 --- /dev/null +++ b/certServiceK8sExternalProvider/src/leveledlogger/logger_test.go @@ -0,0 +1,87 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package leveledlogger + +import ( + "bytes" + "fmt" + "log" + "os" + "testing" +) + +func TestLoggerOnWarningLevel(t *testing.T) { + const resultLogName = "testdata/test_result_warn.log" + const expectedLogName = "testdata/test_expected_warn.log" + + SetConfigFileName("testdata/test_logger_config_warn.json") + logger := GetLoggerWithName("loggername") + + logOnAllLevels(logger) + + resultLogBytes := readFile(resultLogName) + expectedLogBytes := readFile(expectedLogName) + + assertLogEquals(t, resultLogBytes, expectedLogBytes, resultLogName) +} + +func TestLoggerOnDebugLevel(t *testing.T) { + const resultLogName = "testdata/test_result_debug.log" + const expectedLogName = "testdata/test_expected_debug.log" + + SetConfigFileName("testdata/test_logger_config_debug.json") + logger := GetLoggerWithName("loggername") + + logOnAllLevels(logger) + + resultLogBytes := readFile(resultLogName) + expectedLogBytes := readFile(expectedLogName) + + assertLogEquals(t, resultLogBytes, expectedLogBytes, resultLogName) +} + +func logOnAllLevels(logger Logger) { + logger.Debug("this is a debug message") + logger.Info("this is an info message") + logger.Warning("this is a warning message", "key1", "value1") + logger.Error(fmt.Errorf("this is an error message"), "err msg") +} + +func assertLogEquals(t *testing.T, resultLogBytes []byte, expectedLogBytes []byte, resultLogName string) { + if areEqual(resultLogBytes, expectedLogBytes) { + removeTemporaryFile(resultLogName) + } else { + t.Fatal("Logs are different than expected. Please check: " + resultLogName) + } +} + +func areEqual(slice1 []byte, slice2 []byte) bool { + return bytes.Compare(slice1, slice2) == 0 +} + +func removeTemporaryFile(fileName string) { + if _, err := os.Stat(fileName); err == nil { + e := os.Remove(fileName) + if e != nil { + log.Fatal(e) + } + } +} diff --git a/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_expected_debug.log b/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_expected_debug.log new file mode 100644 index 00000000..25242eee --- /dev/null +++ b/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_expected_debug.log @@ -0,0 +1,4 @@ +DEBUG loggername this is a debug message +INFO loggername this is an info message +WARN loggername this is a warning message {"key1": "value1"} +ERROR loggername err msg {"error": "this is an error message"} diff --git a/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_expected_warn.log b/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_expected_warn.log new file mode 100644 index 00000000..b6a1985b --- /dev/null +++ b/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_expected_warn.log @@ -0,0 +1,2 @@ +WARN loggername this is a warning message {"key1": "value1"} +ERROR loggername err msg {"error": "this is an error message"} diff --git a/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_logger_config_debug.json b/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_logger_config_debug.json new file mode 100644 index 00000000..96ac5dc7 --- /dev/null +++ b/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_logger_config_debug.json @@ -0,0 +1,11 @@ +{ + "level": "debug", + "encoding": "console", + "outputPaths": ["stdout", "testdata/test_result_debug.log"], + "encoderConfig": { + "messageKey": "message", + "levelKey": "level", + "nameKey": "name", + "levelEncoder": "capital" + } +} diff --git a/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_logger_config_warn.json b/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_logger_config_warn.json new file mode 100644 index 00000000..a07bdb26 --- /dev/null +++ b/certServiceK8sExternalProvider/src/leveledlogger/testdata/test_logger_config_warn.json @@ -0,0 +1,11 @@ +{ + "level": "warn", + "encoding": "console", + "outputPaths": ["stdout", "testdata/test_result_warn.log"], + "encoderConfig": { + "messageKey": "message", + "levelKey": "level", + "nameKey": "name", + "levelEncoder": "capital" + } +} diff --git a/certServicePostProcessor/pom.xml b/certServicePostProcessor/pom.xml index 484531e9..0e3e1608 100644 --- a/certServicePostProcessor/pom.xml +++ b/certServicePostProcessor/pom.xml @@ -5,12 +5,12 @@ <parent> <artifactId>oom-certservice</artifactId> <groupId>org.onap.oom.platform.cert-service</groupId> - <version>2.1.1-SNAPSHOT</version> + <version>2.2.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>oom-certservice-post-processor</artifactId> - <version>2.1.1-SNAPSHOT</version> + <version>2.2.0-SNAPSHOT</version> <name>oom-certservice-post-processor</name> <description>An application which conducts certificate post-processing like: merging truststores, copying keystores.</description> <packaging>jar</packaging> diff --git a/docs/sections/release-notes.rst b/docs/sections/release-notes.rst index a31bf810..f1c7eecb 100644 --- a/docs/sections/release-notes.rst +++ b/docs/sections/release-notes.rst @@ -7,6 +7,51 @@ Release Notes ============== +Version: 2.2.0 +-------------- + +:Release Date: + +**New Features** + +* Added module **oom-certservice-k8s-external-provider** with following functionality: + + An external provider is a part of PKI infrastructure. It consumes CertificateRequest CRD from Cert-Manager and calls CertService API to enroll certificate from CMPv2 server. + + More information can be found on dedicated `wiki page <https://wiki.onap.org/display/DW/CertService+and+K8s+Cert-Manager+integration>`_ + +**Bug Fixes** + + N/A + +**Known Issues** + + N/A + +**Security Notes** + + N/A + +*Fixed Security Issues* + + N/A + +*Known Security Issues* + + N/A + +*Known Vulnerabilities in Used Modules* + + N/A + +**Upgrade Notes** + +**Deprecation Notes** + +**Other** + +============== + Version: 2.1.0 -------------- @@ -23,7 +23,7 @@ </parent> <groupId>org.onap.oom.platform.cert-service</groupId> <artifactId>oom-certservice</artifactId> - <version>2.1.1-SNAPSHOT</version> + <version>2.2.0-SNAPSHOT</version> <name>oom-certservice</name> <description>OOM Certification Service</description> <packaging>pom</packaging> diff --git a/releases/2.2.0-container.yaml b/releases/2.2.0-container.yaml new file mode 100644 index 00000000..07164cd6 --- /dev/null +++ b/releases/2.2.0-container.yaml @@ -0,0 +1,16 @@ +distribution_type: 'container' +container_release_tag: '2.2.0' +container_pull_registry: nexus3.onap.org:10003 +container_push_registry: nexus3.onap.org:10002 +project: 'oom-platform-cert-service' +log_dir: 'oom-platform-cert-service-maven-docker-stage-master/118' +ref: c3c260ac52d12a8a2bcec9c3e2451c48d388ecec +containers: + - name: 'org.onap.oom.platform.cert-service.oom-certservice-api' + version: '2.2.0-20201112T134226Z' + - name: 'org.onap.oom.platform.cert-service.oom-certservice-client' + version: '2.2.0-20201112T134226Z' + - name: 'org.onap.oom.platform.cert-service.oom-certservice-post-processor' + version: '2.2.0-20201112T134226Z' + - name: 'org.onap.oom.platform.cert-service.oom-certservice-k8s-external-provider' + version: '2.2.0-20201112T134226Z' diff --git a/version.properties b/version.properties index 3c5fba7f..3ad2137c 100644 --- a/version.properties +++ b/version.properties @@ -1,6 +1,6 @@ major=2 -minor=1 -patch=1 +minor=2 +patch=0 base_version=${major}.${minor}.${patch} release_version=${base_version} snapshot_version=${base_version}-SNAPSHOT |