Improve logging

This commit is contained in:
Tomasz Sęk 2019-02-17 00:45:34 +01:00
parent 08b6dfb691
commit 1ad5992160
No known key found for this signature in database
GPG Key ID: DC356D23F6A644D0
14 changed files with 155 additions and 120 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/jenkinsci/kubernetes-operator/pkg/apis"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants"
"github.com/jenkinsci/kubernetes-operator/pkg/event"
"github.com/jenkinsci/kubernetes-operator/pkg/log"
"github.com/jenkinsci/kubernetes-operator/version"
@ -17,6 +18,7 @@ import (
"github.com/operator-framework/operator-sdk/pkg/leader"
"github.com/operator-framework/operator-sdk/pkg/ready"
sdkVersion "github.com/operator-framework/operator-sdk/version"
"github.com/pkg/errors"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/manager"
@ -37,31 +39,31 @@ func main() {
debug := flag.Bool("debug", false, "Set log level to debug")
flag.Parse()
log.SetupLogger(debug)
log.SetupLogger(*debug)
printInfo()
namespace, err := k8sutil.GetWatchNamespace()
if err != nil {
fatal(err, "failed to get watch namespace")
fatal(errors.Wrap(err, "failed to get watch namespace"), *debug)
}
log.Log.Info(fmt.Sprintf("watch namespace: %v", namespace))
// get a config to talk to the apiserver
cfg, err := config.GetConfig()
if err != nil {
fatal(err, "failed to get config")
fatal(errors.Wrap(err, "failed to get config"), *debug)
}
// become the leader before proceeding
err = leader.Become(context.TODO(), "jenkins-operator-lock")
if err != nil {
fatal(err, "failed to become leader")
fatal(errors.Wrap(err, "failed to become leader"), *debug)
}
r := ready.NewFileReady()
err = r.Set()
if err != nil {
fatal(err, "failed to get ready.NewFileReady")
fatal(errors.Wrap(err, "failed to get ready.NewFileReady"), *debug)
}
defer func() {
_ = r.Unset()
@ -70,36 +72,40 @@ func main() {
// create a new Cmd to provide shared dependencies and start components
mgr, err := manager.New(cfg, manager.Options{Namespace: namespace})
if err != nil {
fatal(err, "failed to create manager")
fatal(errors.Wrap(err, "failed to create manager"), *debug)
}
log.Log.Info("Registering Components.")
// setup Scheme for all resources
if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
fatal(err, "failed to setup scheme")
fatal(errors.Wrap(err, "failed to setup scheme"), *debug)
}
// setup events
events, err := event.New(cfg)
events, err := event.New(cfg, constants.OperatorName)
if err != nil {
fatal(err, "failed to create manager")
fatal(errors.Wrap(err, "failed to create manager"), *debug)
}
// setup Jenkins controller
if err := jenkins.Add(mgr, *local, *minikube, events); err != nil {
fatal(err, "failed to setup controllers")
fatal(errors.Wrap(err, "failed to setup controllers"), *debug)
}
log.Log.Info("Starting the Cmd.")
// start the Cmd
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
fatal(err, "failed to start cmd")
fatal(errors.Wrap(err, "failed to start cmd"), *debug)
}
}
func fatal(err error, message string) {
log.Log.Error(err, message)
func fatal(err error, debug bool) {
if debug {
log.Log.Error(nil, fmt.Sprintf("%+v", err))
} else {
log.Log.Error(nil, fmt.Sprintf("%s", err))
}
os.Exit(-1)
}

View File

@ -64,20 +64,13 @@ func (jenkins *jenkins) CreateOrUpdateJob(config, jobName string) (job *gojenkin
if isNotFoundError(err) {
job, err = jenkins.CreateJob(config, jobName)
created = true
return
return job, true, errors.WithStack(err)
} else if err != nil {
return
return job, false, errors.WithStack(err)
}
err = job.UpdateConfig(config)
return
}
func isNotFoundError(err error) bool {
if err != nil {
return err.Error() == errorNotFound.Error()
}
return false
return job, false, errors.WithStack(err)
}
// BuildJenkinsAPIUrl returns Jenkins API URL
@ -89,7 +82,7 @@ func BuildJenkinsAPIUrl(namespace, serviceName string, portNumber int, local, mi
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return "", err
return "", errors.WithStack(err)
}
lines := strings.Split(out.String(), "\n")
// First is for http, the second one is for Jenkins slaves communication
@ -135,3 +128,10 @@ func New(url, user, passwordOrToken string) (Jenkins, error) {
return jenkinsClient, nil
}
func isNotFoundError(err error) bool {
if err != nil {
return err.Error() == errorNotFound.Error()
}
return false
}

View File

@ -16,6 +16,7 @@ import (
"github.com/bndr/gojenkins"
"github.com/go-logr/logr"
stackerr "github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -141,7 +142,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod
func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsclient.Jenkins) (bool, error) {
allPluginsInJenkins, err := jenkinsClient.GetPlugins(fetchAllPlugins)
if err != nil {
return false, err
return false, stackerr.WithStack(err)
}
var installedPlugins []string
@ -200,9 +201,9 @@ func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta
err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.jenkins), Namespace: r.jenkins.ObjectMeta.Namespace}, found)
if err != nil && apierrors.IsNotFound(err) {
return r.createResource(resources.NewOperatorCredentialsSecret(meta, r.jenkins))
return stackerr.WithStack(r.createResource(resources.NewOperatorCredentialsSecret(meta, r.jenkins)))
} else if err != nil && !apierrors.IsNotFound(err) {
return err
return stackerr.WithStack(err)
}
if found.Data[resources.OperatorCredentialsSecretUserNameKey] != nil &&
@ -210,7 +211,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta
return nil
}
return r.updateResource(resources.NewOperatorCredentialsSecret(meta, r.jenkins))
return stackerr.WithStack(r.updateResource(resources.NewOperatorCredentialsSecret(meta, r.jenkins)))
}
func (r *ReconcileJenkinsBaseConfiguration) createScriptsConfigMap(meta metav1.ObjectMeta) error {
@ -218,7 +219,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createScriptsConfigMap(meta metav1.O
if err != nil {
return err
}
return r.createOrUpdateResource(configMap)
return stackerr.WithStack(r.createOrUpdateResource(configMap))
}
func (r *ReconcileJenkinsBaseConfiguration) createInitConfigurationConfigMap(meta metav1.ObjectMeta) error {
@ -226,29 +227,26 @@ func (r *ReconcileJenkinsBaseConfiguration) createInitConfigurationConfigMap(met
if err != nil {
return err
}
return r.createOrUpdateResource(configMap)
return stackerr.WithStack(r.createOrUpdateResource(configMap))
}
func (r *ReconcileJenkinsBaseConfiguration) createBaseConfigurationConfigMap(meta metav1.ObjectMeta) error {
configMap, err := resources.NewBaseConfigurationConfigMap(meta, r.jenkins)
if err != nil {
return err
}
return r.createOrUpdateResource(configMap)
configMap := resources.NewBaseConfigurationConfigMap(meta, r.jenkins)
return stackerr.WithStack(r.createOrUpdateResource(configMap))
}
func (r *ReconcileJenkinsBaseConfiguration) createUserConfigurationConfigMap(meta metav1.ObjectMeta) error {
currentConfigMap := &corev1.ConfigMap{}
err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: resources.GetUserConfigurationConfigMapName(r.jenkins), Namespace: r.jenkins.Namespace}, currentConfigMap)
if err != nil && errors.IsNotFound(err) {
return r.k8sClient.Create(context.TODO(), resources.NewUserConfigurationConfigMap(r.jenkins))
return stackerr.WithStack(r.k8sClient.Create(context.TODO(), resources.NewUserConfigurationConfigMap(r.jenkins)))
} else if err != nil {
return err
return stackerr.WithStack(err)
}
valid := r.verifyLabelsForWatchedResource(currentConfigMap)
if !valid {
currentConfigMap.ObjectMeta.Labels = resources.BuildLabelsForWatchedResources(r.jenkins)
return r.k8sClient.Update(context.TODO(), currentConfigMap)
return stackerr.WithStack(r.k8sClient.Update(context.TODO(), currentConfigMap))
}
return nil
@ -258,19 +256,19 @@ func (r *ReconcileJenkinsBaseConfiguration) createRBAC(meta metav1.ObjectMeta) e
serviceAccount := resources.NewServiceAccount(meta)
err := r.createResource(serviceAccount)
if err != nil && !errors.IsAlreadyExists(err) {
return err
return stackerr.WithStack(err)
}
role := resources.NewRole(meta)
err = r.createOrUpdateResource(role)
if err != nil {
return err
return stackerr.WithStack(err)
}
roleBinding := resources.NewRoleBinding(meta)
err = r.createOrUpdateResource(roleBinding)
if err != nil {
return err
return stackerr.WithStack(err)
}
return nil
@ -279,7 +277,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createRBAC(meta metav1.ObjectMeta) e
func (r *ReconcileJenkinsBaseConfiguration) createService(meta metav1.ObjectMeta) error {
err := r.createResource(resources.NewService(meta, r.minikube))
if err != nil && !apierrors.IsAlreadyExists(err) {
return err
return stackerr.WithStack(err)
}
return nil
@ -290,7 +288,7 @@ func (r *ReconcileJenkinsBaseConfiguration) getJenkinsMasterPod(meta metav1.Obje
currentJenkinsMasterPod := &corev1.Pod{}
err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: jenkinsMasterPod.Name, Namespace: jenkinsMasterPod.Namespace}, currentJenkinsMasterPod)
if err != nil {
return nil, err
return nil, err // don't wrap error
}
return currentJenkinsMasterPod, nil
}
@ -303,16 +301,16 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsMasterPod(meta metav1.O
r.logger.Info(fmt.Sprintf("Creating a new Jenkins Master Pod %s/%s", jenkinsMasterPod.Namespace, jenkinsMasterPod.Name))
err = r.createResource(jenkinsMasterPod)
if err != nil {
return reconcile.Result{}, err
return reconcile.Result{}, stackerr.WithStack(err)
}
r.jenkins.Status = v1alpha1.JenkinsStatus{}
err = r.updateResource(r.jenkins)
if err != nil {
return reconcile.Result{}, err
return reconcile.Result{}, err // don't wrap error
}
return reconcile.Result{}, nil
} else if err != nil && !errors.IsNotFound(err) {
return reconcile.Result{}, err
return reconcile.Result{}, stackerr.WithStack(err)
}
// Recreate pod
@ -357,7 +355,7 @@ func (r *ReconcileJenkinsBaseConfiguration) restartJenkinsMasterPod(meta metav1.
if err != nil {
return err
}
return r.k8sClient.Delete(context.TODO(), currentJenkinsMasterPod)
return stackerr.WithStack(r.k8sClient.Delete(context.TODO(), currentJenkinsMasterPod))
}
func (r *ReconcileJenkinsBaseConfiguration) waitForJenkins(meta metav1.ObjectMeta) (reconcile.Result, error) {
@ -397,7 +395,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsClient(meta metav1.Obje
credentialsSecret := &corev1.Secret{}
err = r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.jenkins), Namespace: r.jenkins.ObjectMeta.Namespace}, credentialsSecret)
if err != nil {
return nil, err
return nil, stackerr.WithStack(err)
}
currentJenkinsMasterPod, err := r.getJenkinsMasterPod(meta)
if err != nil {
@ -437,7 +435,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsClient(meta metav1.Obje
credentialsSecret.Data[resources.OperatorCredentialsSecretTokenCreationKey] = now
err = r.updateResource(credentialsSecret)
if err != nil {
return nil, err
return nil, stackerr.WithStack(err)
}
}
@ -459,7 +457,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureBaseConfiguration(jenkinsClien
namespaceName := types.NamespacedName{Namespace: r.jenkins.Namespace, Name: resources.GetBaseConfigurationConfigMapName(r.jenkins)}
err = r.k8sClient.Get(context.TODO(), namespaceName, configuration)
if err != nil {
return reconcile.Result{}, err
return reconcile.Result{}, stackerr.WithStack(err)
}
done, err := groovyClient.EnsureGroovyJob(configuration.Data, r.jenkins)

View File

@ -2,8 +2,8 @@ package base
import (
"context"
"fmt"
stackerr "github.com/pkg/errors"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -13,33 +13,33 @@ import (
func (r *ReconcileJenkinsBaseConfiguration) createResource(obj metav1.Object) error {
runtimeObj, ok := obj.(runtime.Object)
if !ok {
return fmt.Errorf("is not a %T a runtime.Object", obj)
return stackerr.Errorf("is not a %T a runtime.Object", obj)
}
// Set Jenkins instance as the owner and controller
if err := controllerutil.SetControllerReference(r.jenkins, obj, r.scheme); err != nil {
return err
return stackerr.WithStack(err)
}
return r.k8sClient.Create(context.TODO(), runtimeObj)
return r.k8sClient.Create(context.TODO(), runtimeObj) // don't wrap error
}
func (r *ReconcileJenkinsBaseConfiguration) updateResource(obj metav1.Object) error {
runtimeObj, ok := obj.(runtime.Object)
if !ok {
return fmt.Errorf("is not a %T a runtime.Object", obj)
return stackerr.Errorf("is not a %T a runtime.Object", obj)
}
// set Jenkins instance as the owner and controller, don't check error(can be already set)
_ = controllerutil.SetControllerReference(r.jenkins, obj, r.scheme)
return r.k8sClient.Update(context.TODO(), runtimeObj)
return r.k8sClient.Update(context.TODO(), runtimeObj) // don't wrap error
}
func (r *ReconcileJenkinsBaseConfiguration) createOrUpdateResource(obj metav1.Object) error {
runtimeObj, ok := obj.(runtime.Object)
if !ok {
return fmt.Errorf("is not a %T a runtime.Object", obj)
return stackerr.Errorf("is not a %T a runtime.Object", obj)
}
// set Jenkins instance as the owner and controller, don't check error(can be already set)
@ -49,7 +49,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createOrUpdateResource(obj metav1.Ob
if err != nil && errors.IsAlreadyExists(err) {
return r.updateResource(obj)
} else if err != nil && !errors.IsAlreadyExists(err) {
return err
return stackerr.WithStack(err)
}
return nil

View File

@ -167,7 +167,7 @@ func GetBaseConfigurationConfigMapName(jenkins *v1alpha1.Jenkins) string {
}
// NewBaseConfigurationConfigMap builds Kubernetes config map used to base configuration
func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins) (*corev1.ConfigMap, error) {
func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins) *corev1.ConfigMap {
meta.Name = GetBaseConfigurationConfigMapName(jenkins)
return &corev1.ConfigMap{
@ -183,5 +183,5 @@ func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha1.Jen
jenkins.ObjectMeta.Namespace, GetResourceName(jenkins), HTTPPortInt),
"7-configure-views.groovy": configureViews,
},
}, nil
}
}

View File

@ -3,13 +3,15 @@ package resources
import (
"bytes"
"text/template"
"github.com/pkg/errors"
)
// render executes a parsed template (go-template) with configuration from data
func render(template *template.Template, data interface{}) (string, error) {
var buffer bytes.Buffer
if err := template.Execute(&buffer, data); err != nil {
return "", err
return "", errors.WithStack(err)
}
return buffer.String(), nil

View File

@ -13,6 +13,7 @@ import (
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/jobs"
"github.com/go-logr/logr"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
k8s "sigs.k8s.io/controller-runtime/pkg/client"
@ -73,7 +74,7 @@ func (r *ReconcileUserConfiguration) ensureSeedJobs() (reconcile.Result, error)
return reconcile.Result{}, nil
}
// unexpected error - requeue reconciliation loop
return reconcile.Result{}, err
return reconcile.Result{}, errors.WithStack(err)
}
// build not finished yet - requeue reconciliation loop with timeout
if !done {
@ -94,7 +95,7 @@ func (r *ReconcileUserConfiguration) ensureUserConfiguration(jenkinsClient jenki
namespaceName := types.NamespacedName{Namespace: r.jenkins.Namespace, Name: resources.GetUserConfigurationConfigMapName(r.jenkins)}
err = r.k8sClient.Get(context.TODO(), namespaceName, configuration)
if err != nil {
return reconcile.Result{}, err
return reconcile.Result{}, errors.WithStack(err)
}
done, err := groovyClient.EnsureGroovyJob(configuration.Data, r.jenkins)

View File

@ -4,13 +4,13 @@ import (
"context"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"strings"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
"github.com/jenkinsci/kubernetes-operator/pkg/log"
stackerr "github.com/pkg/errors"
"k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
@ -55,7 +55,7 @@ func (r *ReconcileUserConfiguration) validateSeedJobs(jenkins *v1alpha1.Jenkins)
logger.Info("secret not found")
valid = false
} else if err != nil {
return false, err
return false, stackerr.WithStack(err)
}
privateKey := string(deployKeySecret.Data[seedJob.PrivateKey.SecretKeyRef.Key])
@ -77,17 +77,17 @@ func (r *ReconcileUserConfiguration) validateSeedJobs(jenkins *v1alpha1.Jenkins)
func validatePrivateKey(privateKey string) error {
block, _ := pem.Decode([]byte(privateKey))
if block == nil {
return errors.New("failed to decode PEM block")
return stackerr.New("failed to decode PEM block")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return err
return stackerr.WithStack(err)
}
err = priv.Validate()
if err != nil {
return err
return stackerr.WithStack(err)
}
return nil

View File

@ -13,6 +13,7 @@ import (
"github.com/jenkinsci/kubernetes-operator/pkg/log"
"github.com/go-logr/logr"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
@ -57,13 +58,13 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Create a new controller
c, err := controller.New("jenkins-controller", mgr, controller.Options{Reconciler: r})
if err != nil {
return err
return errors.WithStack(err)
}
// Watch for changes to primary resource Jenkins
err = c.Watch(&source.Kind{Type: &v1alpha1.Jenkins{}}, &handler.EnqueueRequestForObject{})
if err != nil {
return err
return errors.WithStack(err)
}
// Watch for changes to secondary resource Pods and requeue the owner Jenkins
@ -72,18 +73,18 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
OwnerType: &v1alpha1.Jenkins{},
})
if err != nil {
return err
return errors.WithStack(err)
}
jenkinsHandler := &enqueueRequestForJenkins{}
err = c.Watch(&source.Kind{Type: &corev1.Secret{}}, jenkinsHandler)
if err != nil {
return err
return errors.WithStack(err)
}
err = c.Watch(&source.Kind{Type: &corev1.ConfigMap{}}, jenkinsHandler)
if err != nil {
return err
return errors.WithStack(err)
}
return nil
@ -109,7 +110,11 @@ func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Resul
logger.V(log.VWarn).Info(err.Error())
return reconcile.Result{Requeue: true}, nil
} else if err != nil {
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed: %+v", err))
if log.Debug {
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed: %+v", err))
} else {
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed: %s", err))
}
return reconcile.Result{Requeue: true}, nil
}
return result, nil
@ -127,7 +132,7 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request, logger logr.Logg
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request.
return reconcile.Result{}, err
return reconcile.Result{}, errors.WithStack(err)
}
err = r.setDefaults(jenkins, logger)
@ -161,7 +166,7 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request, logger logr.Logg
jenkins.Status.BaseConfigurationCompletedTime = &now
err = r.client.Update(context.TODO(), jenkins)
if err != nil {
return reconcile.Result{}, err
return reconcile.Result{}, errors.WithStack(err)
}
logger.Info("Base configuration phase is complete")
r.events.Emit(jenkins, event.TypeNormal, reasonBaseConfigurationSuccess, "Base configuration completed")
@ -192,7 +197,7 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request, logger logr.Logg
jenkins.Status.UserConfigurationCompletedTime = &now
err = r.client.Update(context.TODO(), jenkins)
if err != nil {
return reconcile.Result{}, err
return reconcile.Result{}, errors.WithStack(err)
}
logger.Info("User configuration phase is complete")
r.events.Emit(jenkins, event.TypeNormal, reasonUserConfigurationSuccess, "User configuration completed")
@ -241,7 +246,7 @@ func (r *ReconcileJenkins) setDefaults(jenkins *v1alpha1.Jenkins, logger logr.Lo
}
if changed {
return r.client.Update(context.TODO(), jenkins)
return errors.WithStack(r.client.Update(context.TODO(), jenkins))
}
return nil
}

View File

@ -2,7 +2,6 @@ package jobs
import (
"context"
"errors"
"fmt"
"strings"
@ -11,21 +10,22 @@ import (
"github.com/jenkinsci/kubernetes-operator/pkg/log"
"github.com/go-logr/logr"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8s "sigs.k8s.io/controller-runtime/pkg/client"
)
var (
// ErrorUnexpectedBuildStatus - this is custom error returned when jenkins build has unexpected status
ErrorUnexpectedBuildStatus = errors.New("unexpected build status")
ErrorUnexpectedBuildStatus = fmt.Errorf("unexpected build status")
// ErrorBuildFailed - this is custom error returned when jenkins build has failed
ErrorBuildFailed = errors.New("build failed")
ErrorBuildFailed = fmt.Errorf("build failed")
// ErrorAbortBuildFailed - this is custom error returned when jenkins build couldn't be aborted
ErrorAbortBuildFailed = errors.New("build abort failed")
ErrorAbortBuildFailed = fmt.Errorf("build abort failed")
// ErrorUnrecoverableBuildFailed - this is custom error returned when jenkins build has failed and cannot be recovered
ErrorUnrecoverableBuildFailed = errors.New("build failed and cannot be recovered")
ErrorUnrecoverableBuildFailed = fmt.Errorf("build failed and cannot be recovered")
// ErrorNotFound - this is error returned when jenkins build couldn't be found
ErrorNotFound = errors.New("404")
ErrorNotFound = fmt.Errorf("404")
// BuildRetires - determines max amount of retires for failed build
BuildRetires = 3
)
@ -54,11 +54,7 @@ func New(jenkinsClient client.Jenkins, k8sClient k8s.Client, logger logr.Logger)
func (jobs *Jobs) EnsureBuildJob(jobName, hash string, parameters map[string]string, jenkins *v1alpha1.Jenkins, preserveStatus bool) (done bool, err error) {
jobs.logger.V(log.VDebug).Info(fmt.Sprintf("Ensuring build, name:'%s' hash:'%s'", jobName, hash))
build, err := jobs.getBuildFromStatus(jobName, hash, jenkins)
if err != nil {
return false, err
}
build := jobs.getBuildFromStatus(jobName, hash, jenkins)
if build != nil {
jobs.logger.V(log.VDebug).Info(fmt.Sprintf("Build exists in status, %+v", build))
switch build.Status {
@ -86,16 +82,16 @@ func (jobs *Jobs) EnsureBuildJob(jobName, hash string, parameters map[string]str
return jobs.buildJob(newBuild, parameters, jenkins)
}
func (jobs *Jobs) getBuildFromStatus(jobName string, hash string, jenkins *v1alpha1.Jenkins) (*v1alpha1.Build, error) {
func (jobs *Jobs) getBuildFromStatus(jobName string, hash string, jenkins *v1alpha1.Jenkins) *v1alpha1.Build {
if jenkins != nil {
builds := jenkins.Status.Builds
for _, build := range builds {
if build.JobName == jobName && build.Hash == hash {
return &build, nil
return &build
}
}
}
return nil, nil
return nil
}
func (jobs *Jobs) ensureSuccessBuild(build v1alpha1.Build, jenkins *v1alpha1.Jenkins, preserveStatus bool) (bool, error) {
@ -103,7 +99,6 @@ func (jobs *Jobs) ensureSuccessBuild(build v1alpha1.Build, jenkins *v1alpha1.Jen
if !preserveStatus {
err := jobs.removeBuildFromStatus(build, jenkins)
jobs.logger.V(log.VDebug).Info(fmt.Sprintf("Removing build from status, %+v", build))
if err != nil {
jobs.logger.V(log.VWarn).Info(fmt.Sprintf("Couldn't remove build from status, %+v", build))
return false, err
@ -122,7 +117,7 @@ func (jobs *Jobs) ensureRunningBuild(build v1alpha1.Build, jenkins *v1alpha1.Jen
return false, nil
} else if err != nil {
jobs.logger.V(log.VWarn).Info(fmt.Sprintf("Couldn't get jenkins build, %+v", build))
return false, err
return false, errors.WithStack(err)
}
if jenkinsBuild.GetResult() != "" {
@ -166,7 +161,6 @@ func (jobs *Jobs) ensureFailedBuild(build v1alpha1.Build, jenkins *v1alpha1.Jenk
jobs.logger.V(log.VWarn).Info(fmt.Sprintf("The retries limit was reached , %+v", build))
if !preserveStatus {
jobs.logger.V(log.VDebug).Info(fmt.Sprintf("Removing build from status, %+v", build))
err := jobs.removeBuildFromStatus(build, jenkins)
if err != nil {
jobs.logger.V(log.VWarn).Info(fmt.Sprintf("Couldn't remove build from status, %+v", build))
@ -181,17 +175,17 @@ func (jobs *Jobs) ensureExpiredBuild(build v1alpha1.Build, jenkins *v1alpha1.Jen
jenkinsBuild, err := jobs.jenkinsClient.GetBuild(build.JobName, build.Number)
if err != nil {
return false, err
return false, errors.WithStack(err)
}
_, err = jenkinsBuild.Stop()
if err != nil {
return false, err
return false, errors.WithStack(err)
}
jenkinsBuild, err = jobs.jenkinsClient.GetBuild(build.JobName, build.Number)
if err != nil {
return false, err
return false, errors.WithStack(err)
}
if v1alpha1.BuildStatus(jenkinsBuild.GetResult()) != v1alpha1.BuildAbortedStatus {
@ -206,7 +200,6 @@ func (jobs *Jobs) ensureExpiredBuild(build v1alpha1.Build, jenkins *v1alpha1.Jen
// TODO(antoniaklja) clean up k8s resources
if !preserveStatus {
jobs.logger.V(log.VDebug).Info(fmt.Sprintf("Removing build from status, %+v", build))
err = jobs.removeBuildFromStatus(build, jenkins)
if err != nil {
jobs.logger.V(log.VWarn).Info(fmt.Sprintf("Couldn't remove build from status, %+v", build))
@ -218,6 +211,7 @@ func (jobs *Jobs) ensureExpiredBuild(build v1alpha1.Build, jenkins *v1alpha1.Jen
}
func (jobs *Jobs) removeBuildFromStatus(build v1alpha1.Build, jenkins *v1alpha1.Jenkins) error {
jobs.logger.V(log.VDebug).Info(fmt.Sprintf("Removing build from status, %+v", build))
builds := make([]v1alpha1.Build, len(jenkins.Status.Builds))
for _, existingBuild := range jenkins.Status.Builds {
if existingBuild.JobName != build.JobName && existingBuild.Hash != build.Hash {
@ -227,7 +221,7 @@ func (jobs *Jobs) removeBuildFromStatus(build v1alpha1.Build, jenkins *v1alpha1.
jenkins.Status.Builds = builds
err := jobs.k8sClient.Update(context.TODO(), jenkins)
if err != nil {
return err
return err // don't wrap because apierrors.IsConflict(err) won't work in jenkins_controller
}
return nil
@ -238,7 +232,7 @@ func (jobs *Jobs) buildJob(build v1alpha1.Build, parameters map[string]string, j
job, err := jobs.jenkinsClient.GetJob(build.JobName)
if err != nil {
jobs.logger.V(log.VWarn).Info(fmt.Sprintf("Couldn't find jenkins job, %+v", build))
return false, err
return false, errors.WithStack(err)
}
nextBuildNumber := job.GetDetails().NextBuildNumber
@ -246,7 +240,7 @@ func (jobs *Jobs) buildJob(build v1alpha1.Build, parameters map[string]string, j
_, err = jobs.jenkinsClient.BuildJob(build.JobName, parameters)
if err != nil {
jobs.logger.V(log.VWarn).Info(fmt.Sprintf("Couldn't run build, %+v", build))
return false, err
return false, errors.WithStack(err)
}
build.Status = v1alpha1.BuildRunningStatus
@ -281,7 +275,7 @@ func (jobs *Jobs) updateBuildStatus(build v1alpha1.Build, jenkins *v1alpha1.Jenk
}
err := jobs.k8sClient.Update(context.TODO(), jenkins)
if err != nil {
return err
return err // don't wrap because apierrors.IsConflict(err) won't work in jenkins_controller
}
return nil

View File

@ -5,6 +5,8 @@ import (
"strings"
"github.com/jenkinsci/kubernetes-operator/pkg/log"
"github.com/pkg/errors"
)
// Plugin represents jenkins plugin
@ -22,7 +24,7 @@ func (p Plugin) String() string {
func New(nameWithVersion string) (*Plugin, error) {
val := strings.SplitN(nameWithVersion, ":", 2)
if val == nil || len(val) != 2 {
return nil, fmt.Errorf("invalid plugin format '%s'", nameWithVersion)
return nil, errors.Errorf("invalid plugin format '%s'", nameWithVersion)
}
return &Plugin{
Name: val[0],

View File

@ -9,8 +9,7 @@ import (
)
func TestVerifyDependencies(t *testing.T) {
debug := false
log.SetupLogger(&debug)
log.SetupLogger(false)
t.Run("happy, single root plugin with one dependent plugin", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{

View File

@ -3,8 +3,7 @@ package event
import (
"fmt"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants"
"github.com/pkg/errors"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
@ -38,8 +37,8 @@ type recorder struct {
}
// New returns recorder used to emit events
func New(config *rest.Config) (Recorder, error) {
eventRecorder, err := initializeEventRecorder(config)
func New(config *rest.Config, component string) (Recorder, error) {
eventRecorder, err := initializeEventRecorder(config, component)
if err != nil {
return nil, err
}
@ -49,10 +48,10 @@ func New(config *rest.Config) (Recorder, error) {
}, nil
}
func initializeEventRecorder(config *rest.Config) (record.EventRecorder, error) {
func initializeEventRecorder(config *rest.Config, component string) (record.EventRecorder, error) {
client, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
return nil, errors.WithStack(err)
}
eventBroadcaster := record.NewBroadcaster()
//eventBroadcaster.StartLogging(glog.Infof) TODO integrate with proper logger
@ -61,8 +60,8 @@ func initializeEventRecorder(config *rest.Config) (record.EventRecorder, error)
Interface: client.CoreV1().Events("")})
eventRecorder := eventBroadcaster.NewRecorder(
scheme.Scheme,
v1.EventSource{
Component: constants.OperatorName})
v1.EventSource{Component: component},
)
return eventRecorder, nil
}

View File

@ -1,12 +1,19 @@
package log
import (
"sigs.k8s.io/controller-runtime/pkg/runtime/log"
"log"
"github.com/go-logr/logr"
"github.com/go-logr/zapr"
"go.uber.org/zap"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
)
// Log represents global logger
var Log = log.Log.WithName("controller-jenkins")
var Log = logf.Log.WithName("controller-jenkins")
// Debug indicates that debug level is set
var Debug bool
const (
// VWarn defines warning log level
@ -15,8 +22,30 @@ const (
VDebug = 1
)
// SetupLogger setups global logger
func SetupLogger(development *bool) {
logf.SetLogger(logf.ZapLogger(*development))
Log = log.Log.WithName("controller-jenkins")
func zapLogger(debug bool) logr.Logger {
var zapLog *zap.Logger
var err error
zapLogCfg := zap.NewDevelopmentConfig()
if debug {
zapLogCfg.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
} else {
zapLogCfg.Level = zap.NewAtomicLevelAt(zap.InfoLevel)
}
zapLog, err = zapLogCfg.Build(zap.AddStacktrace(zap.DPanicLevel), zap.AddCallerSkip(1))
// who watches the watchmen?
fatalIfErr(err, log.Fatalf)
return zapr.NewLogger(zapLog)
}
func fatalIfErr(err error, f func(format string, v ...interface{})) {
if err != nil {
f("unable to construct the logger: %v", err)
}
}
// SetupLogger setups global logger
func SetupLogger(debug bool) {
Debug = debug
logf.SetLogger(zapLogger(debug))
Log = logf.Log.WithName("controller-jenkins")
}