lint with golangci-lint

This commit is contained in:
jkhelil
2020-05-06 16:22:52 +02:00
parent eb8b2e32e8
commit 128c97be6b
46 changed files with 394 additions and 181 deletions
+9 -8
View File
@@ -16,7 +16,7 @@ var (
regex = regexp.MustCompile("(<application-desc main-class=\"hudson.remoting.jnlp.Main\"><argument>)(?P<secret>[a-z0-9]*)")
)
// Jenkins defines Jenkins API
// Jenkins defines Jenkins API.
type Jenkins interface {
GenerateToken(userName, tokenName string) (*UserToken, error)
Info() (*gojenkins.ExecutorResponse, error)
@@ -62,7 +62,7 @@ type jenkins struct {
gojenkins.Jenkins
}
// JenkinsAPIConnectionSettings is struct that handle information about Jenkins API connection
// JenkinsAPIConnectionSettings is struct that handle information about Jenkins API connection.
type JenkinsAPIConnectionSettings struct {
Hostname string
Port int
@@ -86,7 +86,7 @@ func (t *setBearerToken) RoundTrip(r *http.Request) (*http.Response, error) {
return t.transport().RoundTrip(r)
}
// CreateOrUpdateJob creates or updates a job from config
// CreateOrUpdateJob creates or updates a job from config.
func (jenkins *jenkins) CreateOrUpdateJob(config, jobName string) (job *gojenkins.Job, created bool, err error) {
// create or update
job, err = jenkins.GetJob(jobName)
@@ -102,7 +102,7 @@ func (jenkins *jenkins) CreateOrUpdateJob(config, jobName string) (job *gojenkin
return job, false, errors.WithStack(err)
}
// BuildJenkinsAPIUrl returns Jenkins API URL
// BuildJenkinsAPIUrl returns Jenkins API URL.
func (j JenkinsAPIConnectionSettings) BuildJenkinsAPIUrl(serviceName string, serviceNamespace string, servicePort int32, serviceNodePort int32) string {
if j.Hostname == "" && j.Port == 0 {
return fmt.Sprintf("http://%s.%s:%d", serviceName, serviceNamespace, servicePort)
@@ -115,7 +115,7 @@ func (j JenkinsAPIConnectionSettings) BuildJenkinsAPIUrl(serviceName string, ser
return fmt.Sprintf("http://%s:%d", j.Hostname, j.Port)
}
// Validate validates jenkins API connection settings
// Validate validates jenkins API connection settings.
func (j JenkinsAPIConnectionSettings) Validate() error {
if j.Port > 0 && j.UseNodePort {
return errors.New("can't use service port and nodePort both. Please use port or nodePort")
@@ -132,12 +132,12 @@ func (j JenkinsAPIConnectionSettings) Validate() error {
return nil
}
// NewUserAndPasswordAuthorization creates Jenkins API client with user and password authorization
// NewUserAndPasswordAuthorization creates Jenkins API client with user and password authorization.
func NewUserAndPasswordAuthorization(url, userName, passwordOrToken string) (Jenkins, error) {
return newClient(url, userName, passwordOrToken)
}
// NewBearerTokenAuthorization creates Jenkins API client with bearer token authorization
// NewBearerTokenAuthorization creates Jenkins API client with bearer token authorization.
func NewBearerTokenAuthorization(url, token string) (Jenkins, error) {
return newClient(url, "", token)
}
@@ -194,10 +194,11 @@ func isNotFoundError(err error) bool {
func (jenkins *jenkins) GetNodeSecret(name string) (string, error) {
var content string
_, err := jenkins.Requester.GetXML(fmt.Sprintf("/computer/%s/slave-agent.jnlp", name), &content, nil)
r, err := jenkins.Requester.GetXML(fmt.Sprintf("/computer/%s/slave-agent.jnlp", name), &content, nil)
if err != nil {
return "", errors.WithStack(err)
}
defer r.Body.Close()
match := regex.FindStringSubmatch(content)
if match == nil {
+2 -1
View File
@@ -5,9 +5,10 @@
package client
import (
"reflect"
"github.com/bndr/gojenkins"
"github.com/golang/mock/gomock"
"reflect"
)
// MockJenkins is a mock of Jenkins interface
+1
View File
@@ -48,6 +48,7 @@ func (jenkins *jenkins) executeScript(script string, verifier string) (string, e
if err != nil {
return "", errors.Wrapf(err, "couldn't execute groovy script, logs '%s'", output)
}
defer r.Body.Close()
if r.StatusCode != http.StatusOK {
return output, errors.Errorf("invalid status code '%d', logs '%s'", r.StatusCode, output)
+2 -3
View File
@@ -11,6 +11,8 @@ import (
"github.com/stretchr/testify/assert"
)
const script = "some groovy code"
func Test_ExecuteScript(t *testing.T) {
verifier := "verifier-text"
t.Run("logs have verifier text", func(t *testing.T) {
@@ -34,7 +36,6 @@ func Test_ExecuteScript(t *testing.T) {
BasicAuth: &gojenkins.BasicAuth{Username: "unused", Password: "unused"},
}
script := "some groovy code"
logs, err := jenkinsClient.executeScript(script, verifier)
assert.NoError(t, err, logs)
})
@@ -60,7 +61,6 @@ func Test_ExecuteScript(t *testing.T) {
BasicAuth: &gojenkins.BasicAuth{Username: "unused", Password: "unused"},
}
script := "some groovy code"
logs, err := jenkinsClient.executeScript(script, verifier)
assert.EqualError(t, err, "script execution failed", logs)
assert.Equal(t, response, logs)
@@ -82,7 +82,6 @@ func Test_ExecuteScript(t *testing.T) {
BasicAuth: &gojenkins.BasicAuth{Username: "unused", Password: "unused"},
}
script := "some groovy code"
logs, err := jenkinsClient.executeScript(script, verifier)
assert.EqualError(t, err, "invalid status code '500', logs ''", logs)
})
+1 -1
View File
@@ -35,10 +35,10 @@ func (jenkins *jenkins) GenerateToken(userName, tokenName string) (*UserToken, e
endpoint := token.base
data := map[string]string{"newTokenName": tokenName}
r, err := jenkins.Requester.Post(endpoint, nil, token.raw, data)
if err != nil {
return nil, errors.Wrap(err, "couldn't generate API token")
}
defer r.Body.Close()
if r.StatusCode == http.StatusOK {
if token.raw.Status == "ok" {
@@ -200,7 +200,7 @@ func triggerBackup(ticker *time.Ticker, k8sClient k8s.Client, logger logr.Logger
logger.V(log.VWarn).Info(fmt.Sprintf("backup trigger, error when fetching CR: %s", err))
}
if jenkins.Status.LastBackup == jenkins.Status.PendingBackup {
jenkins.Status.PendingBackup = jenkins.Status.PendingBackup + 1
jenkins.Status.PendingBackup++
err = k8sClient.Update(context.TODO(), jenkins)
if err != nil {
logger.V(log.VWarn).Info(fmt.Sprintf("backup trigger, error when updating CR: %s", err))
@@ -10,7 +10,7 @@ import (
func (r *ReconcileJenkinsBaseConfiguration) compareContainers(expected corev1.Container, actual corev1.Container) (messages []string, verbose []string) {
if !reflect.DeepEqual(expected.Args, actual.Args) {
messages = append(messages, "Arguments have changed")
verbose = append(messages, fmt.Sprintf("Arguments have changed to '%+v' in container '%s'", expected.Args, expected.Name))
verbose = append(verbose, fmt.Sprintf("Arguments have changed to '%+v' in container '%s'", expected.Args, expected.Name))
}
if !reflect.DeepEqual(expected.Command, actual.Command) {
messages = append(messages, "Command has changed")
@@ -194,7 +194,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsMasterPod(meta metav1.O
}
if r.Configuration.Jenkins.Spec.Backup.MakeBackupBeforePodDeletion && !r.Configuration.Jenkins.Status.BackupDoneBeforePodDeletion {
if r.Configuration.Jenkins.Status.LastBackup == r.Configuration.Jenkins.Status.PendingBackup {
r.Configuration.Jenkins.Status.PendingBackup = r.Configuration.Jenkins.Status.PendingBackup + 1
r.Configuration.Jenkins.Status.PendingBackup++
}
if err = backupAndRestore.Backup(true); err != nil {
return reconcile.Result{}, err
@@ -4,13 +4,13 @@ import (
"context"
"testing"
"github.com/bndr/gojenkins"
"github.com/golang/mock/gomock"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/client"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources"
"github.com/jenkinsci/kubernetes-operator/pkg/log"
"github.com/bndr/gojenkins"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
@@ -21,7 +21,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)
func TestCompareContainerVolumeMounts(t *testing.T) {
t.Run("happy with service account", func(t *testing.T) {
expectedContainer := corev1.Container{
@@ -172,12 +172,12 @@ GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration.class).useScript
GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration.class).save()
`
// GetBaseConfigurationConfigMapName returns name of Kubernetes config map used to base configuration
// GetBaseConfigurationConfigMapName returns name of Kubernetes config map used to base configuration.
func GetBaseConfigurationConfigMapName(jenkins *v1alpha2.Jenkins) string {
return fmt.Sprintf("%s-base-configuration-%s", constants.OperatorName, jenkins.ObjectMeta.Name)
}
// NewBaseConfigurationConfigMap builds Kubernetes config map used to base configuration
// NewBaseConfigurationConfigMap builds Kubernetes config map used to base configuration.
func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha2.Jenkins) (*corev1.ConfigMap, error) {
meta.Name = GetBaseConfigurationConfigMapName(jenkins)
jenkinsServiceFQDN, err := GetJenkinsHTTPServiceFQDN(jenkins)
@@ -1,7 +1,7 @@
package resources
import (
"k8s.io/api/rbac/v1"
v1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -11,26 +11,27 @@ import (
//RouteKind the kind name for route
const RouteKind = "Route"
var isRouteAPIAvailable = false
var routeAPIChecked = false
var isRouteAPIAvailable = false
var routeAPIChecked = false
// UpdateRoute returns new route matching the service
func UpdateRoute(actual routev1.Route,jenkins *v1alpha2.Jenkins) routev1.Route {
func UpdateRoute(actual routev1.Route, jenkins *v1alpha2.Jenkins) routev1.Route {
actualTargetService := actual.Spec.To
serviceName := GetJenkinsHTTPServiceName(jenkins)
if( actualTargetService.Name != serviceName ) {
if actualTargetService.Name != serviceName {
actual.Spec.To.Name = serviceName
}
port := jenkins.Spec.Service.Port
if( actual.Spec.Port.TargetPort.IntVal != port){
if actual.Spec.Port.TargetPort.IntVal != port {
actual.Spec.Port.TargetPort = intstr.FromInt(int(port))
}
return actual
}
//IsRouteAPIAvailable tells if the Route API is installed and discoverable
func IsRouteAPIAvailable(clientSet *kubernetes.Clientset) (bool) {
if (routeAPIChecked){
func IsRouteAPIAvailable(clientSet *kubernetes.Clientset) bool {
if routeAPIChecked {
return isRouteAPIAvailable
}
gv := schema.GroupVersion{
@@ -2,6 +2,7 @@ package resources
import (
"fmt"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants"
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
@@ -12,6 +13,7 @@ import (
"net"
"strings"
)
//ServiceKind the kind name for Service
const ServiceKind = "Service"
@@ -1,7 +1,7 @@
package resources
import (
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -3,6 +3,7 @@ package base
import (
"context"
"fmt"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"k8s.io/apimachinery/pkg/util/intstr"
@@ -15,7 +16,7 @@ import (
)
// createRoute takes the ServiceName and Creates the Route based on it
func (r *ReconcileJenkinsBaseConfiguration) createRoute(meta metav1.ObjectMeta, serviceName string, config *v1alpha2.Jenkins) error{
func (r *ReconcileJenkinsBaseConfiguration) createRoute(meta metav1.ObjectMeta, serviceName string, config *v1alpha2.Jenkins) error {
route := routev1.Route{}
name := fmt.Sprintf("%s-%s", config.ObjectMeta.Name, config.ObjectMeta.Namespace)
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: meta.Namespace}, &route)
@@ -21,6 +21,8 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log/zap"
)
const defaultNamespace = "default"
func TestValidatePlugins(t *testing.T) {
log.SetupLogger(true)
baseReconcileLoop := New(configuration.Configuration{}, log.Log, client.JenkinsAPIConnectionSettings{})
@@ -557,7 +559,6 @@ func TestValidateContainerVolumeMounts(t *testing.T) {
}
func TestValidateConfigMapVolume(t *testing.T) {
namespace := "default"
t.Run("optional", func(t *testing.T) {
optional := true
volume := corev1.Volume{
@@ -580,8 +581,8 @@ func TestValidateConfigMapVolume(t *testing.T) {
})
t.Run("happy, required", func(t *testing.T) {
optional := false
configMap := corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "configmap-name"}}
jenkins := &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}}
configMap := corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNamespace, Name: "configmap-name"}}
jenkins := &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNamespace}}
volume := corev1.Volume{
Name: "volume-name",
VolumeSource: corev1.VolumeSource{
@@ -608,8 +609,8 @@ func TestValidateConfigMapVolume(t *testing.T) {
})
t.Run("missing configmap", func(t *testing.T) {
optional := false
configMap := corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "configmap-name"}}
jenkins := &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}}
configMap := corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNamespace, Name: "configmap-name"}}
jenkins := &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNamespace}}
volume := corev1.Volume{
Name: "volume-name",
VolumeSource: corev1.VolumeSource{
@@ -636,7 +637,6 @@ func TestValidateConfigMapVolume(t *testing.T) {
}
func TestValidateSecretVolume(t *testing.T) {
namespace := "default"
t.Run("optional", func(t *testing.T) {
optional := true
volume := corev1.Volume{
@@ -659,8 +659,8 @@ func TestValidateSecretVolume(t *testing.T) {
})
t.Run("happy, required", func(t *testing.T) {
optional := false
secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "secret-name"}}
jenkins := &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}}
secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNamespace, Name: "secret-name"}}
jenkins := &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNamespace}}
volume := corev1.Volume{
Name: "volume-name",
VolumeSource: corev1.VolumeSource{
@@ -685,8 +685,8 @@ func TestValidateSecretVolume(t *testing.T) {
})
t.Run("missing secret", func(t *testing.T) {
optional := false
secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "secret-name"}}
jenkins := &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}}
secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNamespace, Name: "secret-name"}}
jenkins := &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNamespace}}
volume := corev1.Volume{
Name: "volume-name",
VolumeSource: corev1.VolumeSource{
@@ -710,12 +710,11 @@ func TestValidateSecretVolume(t *testing.T) {
}
func TestValidateCustomization(t *testing.T) {
namespace := "default"
secretName := "secretName"
configMapName := "configmap-name"
jenkins := &v1alpha2.Jenkins{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Namespace: defaultNamespace,
},
}
t.Run("empty", func(t *testing.T) {
@@ -739,7 +738,7 @@ func TestValidateCustomization(t *testing.T) {
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Namespace: defaultNamespace,
},
}
fakeClient := fake.NewFakeClient()
@@ -764,13 +763,13 @@ func TestValidateCustomization(t *testing.T) {
configMap := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: configMapName,
Namespace: namespace,
Namespace: defaultNamespace,
},
}
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Namespace: defaultNamespace,
},
}
fakeClient := fake.NewFakeClient()
@@ -797,7 +796,7 @@ func TestValidateCustomization(t *testing.T) {
configMap := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: configMapName,
Namespace: namespace,
Namespace: defaultNamespace,
},
}
fakeClient := fake.NewFakeClient()
@@ -822,7 +821,7 @@ func TestValidateCustomization(t *testing.T) {
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Namespace: defaultNamespace,
},
}
fakeClient := fake.NewFakeClient()
@@ -7,10 +7,10 @@ import (
"time"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/client"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications/event"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications/reason"
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/client"
stackerr "github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
@@ -166,7 +166,7 @@ func (c *Configuration) GetJenkinsMasterContainer() *v1alpha2.Container {
// GetJenkinsClient gets jenkins client from a configuration
func (c *Configuration) GetJenkinsClient() (jenkinsclient.Jenkins, error) {
switch c.Jenkins.Spec.JenkinsAPISettings.AuthorizationStrategy {
switch c.Jenkins.Spec.JenkinsAPISettings.AuthorizationStrategy {
case v1alpha2.ServiceAccountAuthorizationStrategy:
return c.GetJenkinsClientFromServiceAccount()
case v1alpha2.CreateUserAuthorizationStrategy:
@@ -189,7 +189,7 @@ func (c *Configuration) getJenkinsAPIUrl() (string, error) {
}
jenkinsURL := c.JenkinsAPIConnectionSettings.BuildJenkinsAPIUrl(service.Name, service.Namespace, service.Spec.Ports[0].Port, service.Spec.Ports[0].NodePort)
if prefix, ok := GetJenkinsOpts(*c.Jenkins)["prefix"]; ok {
jenkinsURL = jenkinsURL + prefix
jenkinsURL += prefix
}
return jenkinsURL, nil
}
@@ -289,4 +289,4 @@ func GetJenkinsOpts(jenkins v1alpha2.Jenkins) map[string]string {
}
}
return nil
}
}
@@ -2,7 +2,7 @@ package configuration
import (
"testing"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
@@ -2,9 +2,10 @@ package seedjobs
import (
"context"
"k8s.io/apimachinery/pkg/api/errors"
"testing"
"k8s.io/apimachinery/pkg/api/errors"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/client"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration"
@@ -24,6 +25,8 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log/zap"
)
const agentSecret = "test-secret"
func jenkinsCustomResource() *v1alpha2.Jenkins {
return &v1alpha2.Jenkins{
ObjectMeta: metav1.ObjectMeta{
@@ -81,7 +84,6 @@ func TestEnsureSeedJobs(t *testing.T) {
err = fakeClient.Create(ctx, jenkins)
assert.NoError(t, err)
agentSecret := "test-secret"
testNode := &gojenkins.Node{
Raw: &gojenkins.NodeResponse{
DisplayName: AgentName,
@@ -123,7 +125,6 @@ func TestEnsureSeedJobs(t *testing.T) {
ctx := context.TODO()
defer ctrl.Finish()
agentSecret := "test-secret"
jenkins := jenkinsCustomResource()
jenkins.Spec.SeedJobs = []v1alpha2.SeedJob{}
@@ -174,7 +175,6 @@ func TestCreateAgent(t *testing.T) {
ctx := context.TODO()
defer ctrl.Finish()
agentSecret := "test-secret"
jenkins := jenkinsCustomResource()
jenkinsClient := jenkinsclient.NewMockJenkins(ctrl)
@@ -10,7 +10,7 @@ import (
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
stackerr "github.com/pkg/errors"
"github.com/robfig/cron"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
)
+2 -4
View File
@@ -20,9 +20,10 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)
const configurationType = "test-conf-type"
func TestGroovy_EnsureSingle(t *testing.T) {
log.SetupLogger(true)
configurationType := "test-conf-type"
emptyCustomization := v1alpha2.Customization{}
hash := "hash"
groovyScript := "groovy-script"
@@ -246,7 +247,6 @@ func TestGroovy_EnsureSingle(t *testing.T) {
assert.Equal(t, thirdGroovyScriptHash, jenkins.Status.AppliedGroovyScripts[2].Hash)
assert.Equal(t, source, jenkins.Status.AppliedGroovyScripts[2].Source)
assert.Equal(t, thirdGroovyScriptName, jenkins.Status.AppliedGroovyScripts[2].Name)
})
t.Run("execute two groovy scripts with same names in two config maps", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
@@ -349,7 +349,6 @@ func TestGroovy_EnsureSingle(t *testing.T) {
func TestGroovy_Ensure(t *testing.T) {
log.SetupLogger(true)
configurationType := "test-conf-type"
groovyScript := "groovy-script"
groovyScriptName := "groovy-script-name.groovy"
ctx := context.TODO()
@@ -615,7 +614,6 @@ func TestGroovy_Ensure(t *testing.T) {
func TestGroovy_isGroovyScriptAlreadyApplied(t *testing.T) {
log.SetupLogger(true)
emptyCustomization := v1alpha2.Customization{}
configurationType := "test-conf-type"
t.Run("found", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
+12 -14
View File
@@ -51,7 +51,7 @@ func Add(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.Jenkins
return add(mgr, reconciler)
}
// newReconciler returns a new reconcile.Reconciler
// newReconciler returns a new reconcile.Reconciler.
func newReconciler(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings, clientSet kubernetes.Clientset, config rest.Config, notificationEvents *chan event.Event) reconcile.Reconciler {
return &ReconcileJenkins{
client: mgr.GetClient(),
@@ -63,7 +63,7 @@ func newReconciler(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclie
}
}
// add adds a new Controller to mgr with r as the reconcile.Reconciler
// add adds a new Controller to mgr with r as the reconcile.Reconciler.
func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Create a new controller
c, err := controller.New("jenkins-controller", mgr, controller.Options{Reconciler: r})
@@ -111,7 +111,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
var _ reconcile.Reconciler = &ReconcileJenkins{}
// ReconcileJenkins reconciles a Jenkins object
// ReconcileJenkins reconciles a Jenkins object.
type ReconcileJenkins struct {
client client.Client
scheme *runtime.Scheme
@@ -121,7 +121,7 @@ type ReconcileJenkins struct {
notificationEvents *chan event.Event
}
// Reconcile it's a main reconciliation loop which maintain desired state based on Jenkins.Spec
// Reconcile it's a main reconciliation loop which maintain desired state based on Jenkins.Spec.
func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Result, error) {
reconcileFailLimit := uint64(10)
logger := r.buildLogger(request.Name)
@@ -167,10 +167,8 @@ func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Resul
if log.Debug {
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed: %+v", err))
} else {
if err.Error() != fmt.Sprintf("Operation cannot be fulfilled on jenkins.jenkins.io \"%s\": the object has been modified; please apply your changes to the latest version and try again", request.Name) {
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed: %s", err))
}
} else if err.Error() != fmt.Sprintf("Operation cannot be fulfilled on jenkins.jenkins.io \"%s\": the object has been modified; please apply your changes to the latest version and try again", request.Name) {
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed: %s", err))
}
if groovyErr, ok := err.(*jenkinsclient.GroovyScriptExecutionFailed); ok {
@@ -227,12 +225,12 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request, logger logr.Logg
}
config := configuration.Configuration{
Client: r.client,
ClientSet: r.clientSet,
Notifications: r.notificationEvents,
Jenkins: jenkins,
Scheme: r.scheme,
Config: &r.config,
Client: r.client,
ClientSet: r.clientSet,
Notifications: r.notificationEvents,
Jenkins: jenkins,
Scheme: r.scheme,
Config: &r.config,
JenkinsAPIConnectionSettings: r.jenkinsAPIConnectionSettings,
}
@@ -8,13 +8,13 @@ import (
// Phase defines the context where notification has been generated: base or user.
type Phase string
// StatusColor is useful for better UX
// StatusColor is useful for better UX.
type StatusColor string
// LoggingLevel is type for selecting different logging levels
// LoggingLevel is type for selecting different logging levels.
type LoggingLevel string
// Event contains event details which will be sent as a notification
// Event contains event details which will be sent as a notification.
type Event struct {
Jenkins v1alpha2.Jenkins
Phase Phase
@@ -30,11 +30,12 @@ const (
// NotificationTitle converts NotificationLevel enum to string
func NotificationTitle(event event.Event) string {
if event.Level == v1alpha2.NotificationLevelInfo {
switch event.Level {
case v1alpha2.NotificationLevelInfo:
return InfoTitleText
} else if event.Level == v1alpha2.NotificationLevelWarning {
case v1alpha2.NotificationLevelWarning:
return WarnTitleText
} else {
default:
return ""
}
}
@@ -11,66 +11,66 @@ const (
HumanSource Source = "human"
)
// Reason is interface that let us know why operator sent notification
// Reason is interface that let us know why operator sent notification.
type Reason interface {
Short() []string
Verbose() []string
HasMessages() bool
}
// Undefined is base or untraceable reason
// Undefined is base or untraceable reason.
type Undefined struct {
source Source
short []string
verbose []string
}
// PodRestart defines the reason why Jenkins master pod restarted
// PodRestart defines the reason why Jenkins master pod restarted.
type PodRestart struct {
Undefined
}
// PodCreation informs that pod is being created
// PodCreation informs that pod is being created.
type PodCreation struct {
Undefined
}
// ReconcileLoopFailed defines the reason why the reconcile loop failed
// ReconcileLoopFailed defines the reason why the reconcile loop failed.
type ReconcileLoopFailed struct {
Undefined
}
// GroovyScriptExecutionFailed defines the reason why the groovy script execution failed
// GroovyScriptExecutionFailed defines the reason why the groovy script execution failed.
type GroovyScriptExecutionFailed struct {
Undefined
}
// BaseConfigurationFailed defines the reason why base configuration phase failed
// BaseConfigurationFailed defines the reason why base configuration phase failed.
type BaseConfigurationFailed struct {
Undefined
}
// BaseConfigurationComplete informs that base configuration is valid and complete
// BaseConfigurationComplete informs that base configuration is valid and complete.
type BaseConfigurationComplete struct {
Undefined
}
// UserConfigurationFailed defines the reason why user configuration phase failed
// UserConfigurationFailed defines the reason why user configuration phase failed.
type UserConfigurationFailed struct {
Undefined
}
// UserConfigurationComplete informs that user configuration is valid and complete
// UserConfigurationComplete informs that user configuration is valid and complete.
type UserConfigurationComplete struct {
Undefined
}
// NewUndefined returns new instance of Undefined
// NewUndefined returns new instance of Undefined.
func NewUndefined(source Source, short []string, verbose ...string) *Undefined {
return &Undefined{source: source, short: short, verbose: checkIfVerboseEmpty(short, verbose)}
}
// NewPodRestart returns new instance of PodRestart
// NewPodRestart returns new instance of PodRestart.
func NewPodRestart(source Source, short []string, verbose ...string) *PodRestart {
restartPodMessage := fmt.Sprintf("Jenkins master pod restarted by %s:", source)
if len(short) == 1 {
@@ -94,7 +94,7 @@ func NewPodRestart(source Source, short []string, verbose ...string) *PodRestart
}
}
// NewPodCreation returns new instance of PodCreation
// NewPodCreation returns new instance of PodCreation.
func NewPodCreation(source Source, short []string, verbose ...string) *PodCreation {
return &PodCreation{
Undefined{
@@ -105,7 +105,7 @@ func NewPodCreation(source Source, short []string, verbose ...string) *PodCreati
}
}
// NewReconcileLoopFailed returns new instance of ReconcileLoopFailed
// NewReconcileLoopFailed returns new instance of ReconcileLoopFailed.
func NewReconcileLoopFailed(source Source, short []string, verbose ...string) *ReconcileLoopFailed {
return &ReconcileLoopFailed{
Undefined{
@@ -116,7 +116,7 @@ func NewReconcileLoopFailed(source Source, short []string, verbose ...string) *R
}
}
// NewGroovyScriptExecutionFailed returns new instance of GroovyScriptExecutionFailed
// NewGroovyScriptExecutionFailed returns new instance of GroovyScriptExecutionFailed.
func NewGroovyScriptExecutionFailed(source Source, short []string, verbose ...string) *GroovyScriptExecutionFailed {
return &GroovyScriptExecutionFailed{
Undefined{
@@ -127,7 +127,7 @@ func NewGroovyScriptExecutionFailed(source Source, short []string, verbose ...st
}
}
// NewBaseConfigurationFailed returns new instance of BaseConfigurationFailed
// NewBaseConfigurationFailed returns new instance of BaseConfigurationFailed.
func NewBaseConfigurationFailed(source Source, short []string, verbose ...string) *BaseConfigurationFailed {
return &BaseConfigurationFailed{
Undefined{
@@ -138,7 +138,7 @@ func NewBaseConfigurationFailed(source Source, short []string, verbose ...string
}
}
// NewBaseConfigurationComplete returns new instance of BaseConfigurationComplete
// NewBaseConfigurationComplete returns new instance of BaseConfigurationComplete.
func NewBaseConfigurationComplete(source Source, short []string, verbose ...string) *BaseConfigurationComplete {
return &BaseConfigurationComplete{
Undefined{
@@ -149,7 +149,7 @@ func NewBaseConfigurationComplete(source Source, short []string, verbose ...stri
}
}
// NewUserConfigurationFailed returns new instance of UserConfigurationFailed
// NewUserConfigurationFailed returns new instance of UserConfigurationFailed.
func NewUserConfigurationFailed(source Source, short []string, verbose ...string) *UserConfigurationFailed {
return &UserConfigurationFailed{
Undefined{
@@ -160,7 +160,7 @@ func NewUserConfigurationFailed(source Source, short []string, verbose ...string
}
}
// NewUserConfigurationComplete returns new instance of UserConfigurationComplete
// NewUserConfigurationComplete returns new instance of UserConfigurationComplete.
func NewUserConfigurationComplete(source Source, short []string, verbose ...string) *UserConfigurationComplete {
return &UserConfigurationComplete{
Undefined{
@@ -171,20 +171,20 @@ func NewUserConfigurationComplete(source Source, short []string, verbose ...stri
}
}
// Source is enum type that informs us what triggered notification
// Source is enum type that informs us what triggered notification.
type Source string
// Short is list of reasons
// Short is list of reasons.
func (p Undefined) Short() []string {
return p.short
}
// Verbose is list of reasons with details
// Verbose is list of reasons with details.
func (p Undefined) Verbose() []string {
return p.verbose
}
// HasMessages checks if there is any message
// HasMessages checks if there is any message.
func (p Undefined) HasMessages() bool {
return len(p.short) > 0 || len(p.verbose) > 0
}
@@ -59,7 +59,6 @@ func TestUndefined_HasMessages(t *testing.T) {
podRestart := NewUndefined(KubernetesSource, []string{}, []string{}...)
assert.False(t, podRestart.HasMessages())
})
}
func TestPodRestartPrepend(t *testing.T) {
@@ -19,12 +19,12 @@ import (
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
)
// Provider is the communication service handler
// Provider is the communication service handler.
type Provider interface {
Send(event event.Event) error
}
// Listen listens for incoming events and send it as notifications
// Listen listens for incoming events and send it as notifications.
func Listen(events chan event.Event, k8sEvent k8sevent.Recorder, k8sClient k8sclient.Client) {
httpClient := http.Client{}
for e := range events {
@@ -44,16 +44,16 @@ func Listen(events chan event.Event, k8sEvent k8sevent.Recorder, k8sClient k8scl
for _, notificationConfig := range e.Jenkins.Spec.Notifications {
var err error
var provider Provider
if notificationConfig.Slack != nil {
switch {
case notificationConfig.Slack != nil:
provider = slack.New(k8sClient, notificationConfig, httpClient)
} else if notificationConfig.Teams != nil {
case notificationConfig.Teams != nil:
provider = msteams.New(k8sClient, notificationConfig, httpClient)
} else if notificationConfig.Mailgun != nil {
case notificationConfig.Mailgun != nil:
provider = mailgun.New(k8sClient, notificationConfig)
} else if notificationConfig.SMTP != nil {
case notificationConfig.SMTP != nil:
provider = smtp.New(k8sClient, notificationConfig)
} else {
default:
logger.V(log.VWarn).Info(fmt.Sprintf("Unknown notification service `%+v`", notificationConfig))
continue
}
@@ -23,25 +23,25 @@ const (
defaultColor = "#c8c8c8"
)
// Slack is a Slack notification service
// Slack is a Slack notification service.
type Slack struct {
httpClient http.Client
k8sClient k8sclient.Client
config v1alpha2.Notification
}
// New returns instance of Slack
// New returns instance of Slack.
func New(k8sClient k8sclient.Client, config v1alpha2.Notification, httpClient http.Client) *Slack {
return &Slack{k8sClient: k8sClient, config: config, httpClient: httpClient}
}
// Message is representation of json message
// Message is representation of json message.
type Message struct {
Text string `json:"text"`
Attachments []Attachment `json:"attachments"`
}
// Attachment is representation of json attachment
// Attachment is representation of json attachment.
type Attachment struct {
Fallback string `json:"fallback"`
Color event.StatusColor `json:"color"`
@@ -117,7 +117,7 @@ func (s Slack) generateMessage(e event.Event) Message {
return sm
}
// Send is function for sending directly to API
// Send is function for sending directly to API.
func (s Slack) Send(e event.Event) error {
secret := &corev1.Secret{}
selector := s.config.Slack.WebHookURLSecretKeySelector
@@ -47,13 +47,13 @@ const (
</html>`
)
// SMTP is Simple Mail Transport Protocol used for sending emails
// SMTP is Simple Mail Transport Protocol used for sending emails.
type SMTP struct {
k8sClient k8sclient.Client
config v1alpha2.Notification
}
// New returns instance of SMTP
// New returns instance of SMTP.
func New(k8sClient k8sclient.Client, config v1alpha2.Notification) *SMTP {
return &SMTP{k8sClient: k8sClient, config: config}
}
@@ -83,7 +83,7 @@ func (s SMTP) generateMessage(e event.Event) *gomail.Message {
return message
}
// Send is function for sending notification by SMTP server
// Send is function for sending notification by SMTP server.
func (s SMTP) Send(e event.Event) error {
usernameSecret := &corev1.Secret{}
passwordSecret := &corev1.Secret{}
@@ -37,6 +37,8 @@ const (
fromHeader = "From"
toHeader = "To"
subjectHeader = "Subject"
nilConst = "nil"
)
var (
@@ -106,11 +108,12 @@ func (s *testSession) Data(r io.Reader) error {
}
for i := range headers {
if headers[i][1] == fromHeader && headers[i][2] != testFrom {
switch {
case headers[i][1] == fromHeader && headers[i][2] != testFrom:
return fmt.Errorf("`From` header is not equal: '%s', expected '%s'", headers[i][2], testFrom)
} else if headers[i][1] == toHeader && headers[i][2] != testTo {
case headers[i][1] == toHeader && headers[i][2] != testTo:
return fmt.Errorf("`To` header is not equal: '%s', expected '%s'", headers[i][2], testTo)
} else if headers[i][1] == subjectHeader && headers[i][2] != testSubject {
case headers[i][1] == subjectHeader && headers[i][2] != testSubject:
return fmt.Errorf("`Subject` header is not equal: '%s', expected '%s'", headers[i][2], testSubject)
}
}
@@ -242,13 +245,13 @@ func TestGenerateMessage(t *testing.T) {
})
t.Run("with nils", func(t *testing.T) {
crName := "nil"
crName := nilConst
phase := event.PhaseBase
level := v1alpha2.NotificationLevelInfo
res := reason.NewUndefined(reason.KubernetesSource, []string{"nil"}, []string{"nil"}...)
res := reason.NewUndefined(reason.KubernetesSource, []string{nilConst}, []string{nilConst}...)
from := "nil"
to := "nil"
from := nilConst
to := nilConst
e := event.Event{
Jenkins: v1alpha2.Jenkins{
@@ -10,7 +10,7 @@ const (
workflowJobPlugin = "workflow-job:2.38"
)
// basePluginsList contains plugins to install by operator
// basePluginsList contains plugins to install by operator.
var basePluginsList = []Plugin{
Must(New(kubernetesPlugin)),
Must(New(workflowJobPlugin)),
@@ -21,7 +21,7 @@ var basePluginsList = []Plugin{
Must(New(kubernetesCredentialsProviderPlugin)),
}
// BasePlugins returns list of plugins to install by operator
// BasePlugins returns list of plugins to install by operator.
func BasePlugins() []Plugin {
return basePluginsList
}
+5 -5
View File
@@ -8,7 +8,7 @@ import (
"github.com/pkg/errors"
)
// Plugin represents jenkins plugin
// Plugin represents jenkins plugin.
type Plugin struct {
Name string `json:"name"`
Version string `json:"version"`
@@ -29,7 +29,7 @@ var (
DownloadURLPattern = regexp.MustCompile(`https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`)
)
// New creates plugin from string, for example "name-of-plugin:0.0.1"
// New creates plugin from string, for example "name-of-plugin:0.0.1".
func New(nameWithVersion string) (*Plugin, error) {
val := strings.SplitN(nameWithVersion, ":", 2)
if val == nil || len(val) != 2 {
@@ -48,7 +48,7 @@ func New(nameWithVersion string) (*Plugin, error) {
}, nil
}
// NewPlugin creates plugin from name and version, for example "name-of-plugin:0.0.1"
// NewPlugin creates plugin from name and version, for example "name-of-plugin:0.0.1".
func NewPlugin(name, version, downloadURL string) (*Plugin, error) {
if err := validatePlugin(name, version, downloadURL); err != nil {
return nil, err
@@ -76,7 +76,7 @@ func validatePlugin(name, version, downloadURL string) error {
return nil
}
// Must returns plugin from pointer and throws panic when error is set
// Must returns plugin from pointer and throws panic when error is set.
func Must(plugin *Plugin, err error) Plugin {
if err != nil {
panic(err)
@@ -85,7 +85,7 @@ func Must(plugin *Plugin, err error) Plugin {
return *plugin
}
// VerifyDependencies checks if all plugins have compatible versions
// VerifyDependencies checks if all plugins have compatible versions.
func VerifyDependencies(values ...map[Plugin][]Plugin) []string {
var messages []string
// key - plugin name, value array of versions