Small code improvements

This commit is contained in:
Tomasz Sęk 2019-08-19 16:56:17 +02:00
parent 64f6fa68eb
commit 89c46a1720
No known key found for this signature in database
GPG Key ID: DC356D23F6A644D0
15 changed files with 118 additions and 110 deletions

View File

@ -32,4 +32,3 @@ spec:
fieldPath: metadata.name
- name: OPERATOR_NAME
value: "jenkins-operator"

View File

@ -424,7 +424,7 @@ spec:
- name: JENKINS_HOME
value: /jenkins-home
- name: BACKUP_COUNT
value: "2" # keep only the 2 most recent backups
value: "3" # keep only the 2 most recent backups
image: virtuslab/jenkins-operator-backup-pvc:v0.0.5 # look at backup/pvc directory
imagePullPolicy: IfNotPresent
volumeMounts:

View File

@ -569,7 +569,7 @@ spec:
- name: JENKINS_HOME
value: /jenkins-home
- name: BACKUP_COUNT
value: "2" # keep only the 2 most recent backups
value: "3" # keep only the 2 most recent backups
image: virtuslab/jenkins-operator-backup-pvc:v0.0.5 # look at backup/pvc directory
imagePullPolicy: IfNotPresent
volumeMounts:

View File

@ -17,8 +17,8 @@ type JenkinsSpec struct {
// +optional
SeedJobs []SeedJob `json:"seedJobs,omitempty"`
// Notifications defines services which are used to inform about Jenkins status
// Can be used to integrate chat services like Slack or Email services like Mailgun
// Notifications defines list of a services which are used to inform about Jenkins status
// Can be used to integrate chat services like Slack, Microsoft MicrosoftTeams or Mailgun
Notifications []Notification `json:"notifications,omitempty"`
// Service is Kubernetes service of Jenkins master HTTP pod
@ -54,29 +54,40 @@ type JenkinsSpec struct {
ConfigurationAsCode ConfigurationAsCode `json:"configurationAsCode,omitempty"`
}
// Notification is info sending service about Jenkins Operator
// NotificationLogLevel defines logging level of Notification
type NotificationLogLevel string
const (
// NotificationLogLevelWarning - Only Warnings
NotificationLogLevelWarning NotificationLogLevel = "warning"
// NotificationLogLevelInfo - Only info
NotificationLogLevelInfo NotificationLogLevel = "info"
)
// Notification is a service configuration used to send notifications about Jenkins status
type Notification struct {
LoggingLevel JenkinsNotificationLogLevel `json:"loggingLevel"`
Verbose bool `json:"verbose"`
Name string `json:"name"`
Slack Slack `json:"slack,omitempty"`
Teams Teams `json:"teams,omitempty"`
Mailgun Mailgun `json:"mailgun,omitempty"`
LoggingLevel NotificationLogLevel `json:"loggingLevel"`
Verbose bool `json:"verbose"`
Name string `json:"name"`
Slack *Slack `json:"slack,omitempty"`
Teams *MicrosoftTeams `json:"teams,omitempty"`
Mailgun *Mailgun `json:"mailgun,omitempty"`
}
// Slack is handler for Slack
// Slack is handler for Slack notification channel
type Slack struct {
// The web hook URL to Slack App
URLSecretKeySelector SecretKeySelector `json:"urlSecretKeySelector"`
WebHookURLSecretKeySelector SecretKeySelector `json:"webHookURLSecretKeySelector"`
}
// Teams is handler for Microsoft Teams
type Teams struct {
// The web hook URL to Teams App
URLSecretKeySelector SecretKeySelector `json:"urlSecretKeySelector"`
// MicrosoftTeams is handler for Microsoft MicrosoftTeams notification channel
type MicrosoftTeams struct {
// The web hook URL to MicrosoftTeams App
WebHookURLSecretKeySelector SecretKeySelector `json:"webHookURLSecretKeySelector"`
}
// Mailgun is handler for Mailgun email service
// Mailgun is handler for Mailgun email service notification channel
type Mailgun struct {
Domain string `json:"domain"`
APIKeySecretKeySelector SecretKeySelector `json:"apiKeySecretKeySelector"`
@ -87,9 +98,9 @@ type Mailgun struct {
// SecretKeySelector selects a key of a Secret.
type SecretKeySelector struct {
// The name of the secret in the pod's namespace to select from.
corev1.LocalObjectReference `json:",inline" protobuf:"bytes,1,opt,name=localObjectReference"`
corev1.LocalObjectReference `json:"secret"`
// The key of the secret to select from. Must be a valid secret key.
Key string `json:"key" protobuf:"bytes,2,opt,name=key"`
Key string `json:"key"`
}
// Container defines Kubernetes container attributes
@ -485,17 +496,6 @@ const (
UsernamePasswordCredentialType JenkinsCredentialType = "usernamePassword"
)
// JenkinsNotificationLogLevel defines type of Notification feature frequency of sending logger entries
type JenkinsNotificationLogLevel string
const (
// LogLevelWarning - Only Warnings
LogLevelWarning JenkinsNotificationLogLevel = "warning"
// LogLevelInfo - Only info
LogLevelInfo JenkinsNotificationLogLevel = "info"
)
// AllowedJenkinsCredentialMap contains all allowed Jenkins credentials types
var AllowedJenkinsCredentialMap = map[string]string{
string(NoJenkinsCredentialCredentialType): "",

View File

@ -369,7 +369,9 @@ func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) {
if in.Notifications != nil {
in, out := &in.Notifications, &out.Notifications
*out = make([]Notification, len(*in))
copy(*out, *in)
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.Service.DeepCopyInto(&out.Service)
in.SlaveService.DeepCopyInto(&out.SlaveService)
@ -452,12 +454,41 @@ func (in *Mailgun) DeepCopy() *Mailgun {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MicrosoftTeams) DeepCopyInto(out *MicrosoftTeams) {
*out = *in
out.WebHookURLSecretKeySelector = in.WebHookURLSecretKeySelector
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MicrosoftTeams.
func (in *MicrosoftTeams) DeepCopy() *MicrosoftTeams {
if in == nil {
return nil
}
out := new(MicrosoftTeams)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Notification) DeepCopyInto(out *Notification) {
*out = *in
out.Slack = in.Slack
out.Teams = in.Teams
out.Mailgun = in.Mailgun
if in.Slack != nil {
in, out := &in.Slack, &out.Slack
*out = new(Slack)
**out = **in
}
if in.Teams != nil {
in, out := &in.Teams, &out.Teams
*out = new(MicrosoftTeams)
**out = **in
}
if in.Mailgun != nil {
in, out := &in.Mailgun, &out.Mailgun
*out = new(Mailgun)
**out = **in
}
return
}
@ -591,7 +622,7 @@ func (in *Service) DeepCopy() *Service {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Slack) DeepCopyInto(out *Slack) {
*out = *in
out.URLSecretKeySelector = in.URLSecretKeySelector
out.WebHookURLSecretKeySelector = in.WebHookURLSecretKeySelector
return
}
@ -604,20 +635,3 @@ func (in *Slack) DeepCopy() *Slack {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Teams) DeepCopyInto(out *Teams) {
*out = *in
out.URLSecretKeySelector = in.URLSecretKeySelector
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Teams.
func (in *Teams) DeepCopy() *Teams {
if in == nil {
return nil
}
out := new(Teams)
in.DeepCopyInto(out)
return out
}

View File

@ -127,14 +127,14 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenki
return result, jenkinsClient, err
}
// GetJenkinsOpts put container JENKINS_OPTS env parameters in map and returns it
func GetJenkinsOpts(jenkins *v1alpha2.Jenkins) map[string]string {
// GetJenkinsOpts gets JENKINS_OPTS env parameter, parses it's values and returns it as a map`
func GetJenkinsOpts(jenkins v1alpha2.Jenkins) map[string]string {
envs := jenkins.Spec.Master.Containers[0].Env
jenkinsOpts := make(map[string]string)
for k, v := range envs {
if v.Name == "JENKINS_OPTS" {
jenkinsOptsEnv := envs[k]
for key, value := range envs {
if value.Name == "JENKINS_OPTS" {
jenkinsOptsEnv := envs[key]
jenkinsOptsWithDashes := jenkinsOptsEnv.Value
if len(jenkinsOptsWithDashes) == 0 {
return nil
@ -781,7 +781,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsClient(meta metav1.Obje
jenkinsURL, err := jenkinsclient.BuildJenkinsAPIUrl(
r.jenkins.ObjectMeta.Namespace, resources.GetJenkinsHTTPServiceName(r.jenkins), r.jenkins.Spec.Service.Port, r.local, r.minikube)
if prefix, ok := GetJenkinsOpts(r.jenkins)["prefix"]; ok {
if prefix, ok := GetJenkinsOpts(*r.jenkins)["prefix"]; ok {
jenkinsURL = jenkinsURL + prefix
}

View File

@ -16,7 +16,7 @@ import (
func TestGetJenkinsOpts(t *testing.T) {
t.Run("JENKINS_OPTS is uninitialized", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
@ -35,7 +35,7 @@ func TestGetJenkinsOpts(t *testing.T) {
})
t.Run("JENKINS_OPTS is empty", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
@ -54,7 +54,7 @@ func TestGetJenkinsOpts(t *testing.T) {
})
t.Run("JENKINS_OPTS have --prefix argument ", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
@ -77,7 +77,7 @@ func TestGetJenkinsOpts(t *testing.T) {
})
t.Run("JENKINS_OPTS have --prefix and --httpPort argument", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
@ -103,7 +103,7 @@ func TestGetJenkinsOpts(t *testing.T) {
})
t.Run("JENKINS_OPTS have --httpPort argument", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
@ -126,7 +126,7 @@ func TestGetJenkinsOpts(t *testing.T) {
})
t.Run("JENKINS_OPTS have --httpPort=--8080 argument", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{

View File

@ -231,9 +231,9 @@ func NewJenkinsMasterContainer(jenkins *v1alpha2.Jenkins) corev1.Container {
},
},
SecurityContext: jenkinsContainer.SecurityContext,
Env: envs,
Resources: jenkinsContainer.Resources,
VolumeMounts: append(GetJenkinsMasterContainerBaseVolumeMounts(jenkins), jenkinsContainer.VolumeMounts...),
Env: envs,
Resources: jenkinsContainer.Resources,
VolumeMounts: append(GetJenkinsMasterContainerBaseVolumeMounts(jenkins), jenkinsContainer.VolumeMounts...),
}
}

View File

@ -61,40 +61,42 @@ func (r *ReconcileJenkinsBaseConfiguration) Validate(jenkins *v1alpha2.Jenkins)
}
func (r *ReconcileJenkinsBaseConfiguration) validateImagePullSecrets() (bool, error) {
var err error
for _, sr := range r.jenkins.Spec.Master.ImagePullSecrets {
valid, err := r.validateImagePullSecret(sr.Name)
if err != nil || !valid {
if err != nil {
return false, err
}
if !valid {
return false, nil
}
}
return true, err
return true, nil
}
func (r *ReconcileJenkinsBaseConfiguration) validateImagePullSecret(name string) (bool, error) {
func (r *ReconcileJenkinsBaseConfiguration) validateImagePullSecret(secretName string) (bool, error) {
secret := &corev1.Secret{}
err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: r.jenkins.ObjectMeta.Namespace}, secret)
err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: secretName, Namespace: r.jenkins.ObjectMeta.Namespace}, secret)
if err != nil && apierrors.IsNotFound(err) {
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret %s not found defined in spec.master.imagePullSecrets", name))
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret %s not found defined in spec.master.imagePullSecrets", secretName))
return false, nil
} else if err != nil && !apierrors.IsNotFound(err) {
return false, stackerr.WithStack(err)
}
if secret.Data["docker-server"] == nil {
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' defined in spec.master.imagePullSecrets doesn't have 'docker-server' key.", name))
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' defined in spec.master.imagePullSecrets doesn't have 'docker-server' key.", secretName))
return false, nil
}
if secret.Data["docker-username"] == nil {
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' defined in spec.master.imagePullSecrets doesn't have 'docker-username' key.", name))
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' defined in spec.master.imagePullSecrets doesn't have 'docker-username' key.", secretName))
return false, nil
}
if secret.Data["docker-password"] == nil {
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' defined in spec.master.imagePullSecrets doesn't have 'docker-password' key.", name))
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' defined in spec.master.imagePullSecrets doesn't have 'docker-password' key.", secretName))
return false, nil
}
if secret.Data["docker-email"] == nil {
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' defined in spec.master.imagePullSecrets doesn't have 'docker-email' key.", name))
r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' defined in spec.master.imagePullSecrets doesn't have 'docker-email' key.", secretName))
return false, nil
}

View File

@ -40,16 +40,16 @@ const content = `
</body>
</html>`
// MailGun is service for sending emails
// MailGun is a sending emails notification service
type MailGun struct {
k8sClient k8sclient.Client
}
func (m MailGun) getStatusColor(logLevel LoggingLevel) StatusColor {
func (m MailGun) getStatusColor(logLevel v1alpha2.NotificationLogLevel) StatusColor {
switch logLevel {
case LogInfo:
case v1alpha2.NotificationLogLevelInfo:
return "blue"
case LogWarn:
case v1alpha2.NotificationLogLevelWarning:
return "red"
default:
return "gray"

View File

@ -14,7 +14,7 @@ import (
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
)
// Teams is Microsoft Teams Service
// Teams is a Microsoft MicrosoftTeams notification service
type Teams struct {
k8sClient k8sclient.Client
}
@ -40,11 +40,11 @@ type TeamsFact struct {
Value string `json:"value"`
}
func (t Teams) getStatusColor(logLevel LoggingLevel) StatusColor {
func (t Teams) getStatusColor(logLevel v1alpha2.NotificationLogLevel) StatusColor {
switch logLevel {
case LogInfo:
case v1alpha2.NotificationLogLevelInfo:
return "439FE0"
case LogWarn:
case v1alpha2.NotificationLogLevelWarning:
return "E81123"
default:
return "C8C8C8"
@ -55,7 +55,7 @@ func (t Teams) getStatusColor(logLevel LoggingLevel) StatusColor {
func (t Teams) Send(event Event, config v1alpha2.Notification) error {
secret := &corev1.Secret{}
selector := config.Teams.URLSecretKeySelector
selector := config.Teams.WebHookURLSecretKeySelector
err := t.k8sClient.Get(context.TODO(), types.NamespacedName{Name: selector.Name, Namespace: event.Jenkins.Namespace}, secret)
if err != nil {

View File

@ -84,8 +84,8 @@ func TestTeams_Send(t *testing.T) {
assert.NoError(t, err)
err = teams.Send(event, v1alpha2.Notification{
Teams: v1alpha2.Teams{
URLSecretKeySelector: v1alpha2.SecretKeySelector{
Teams: &v1alpha2.MicrosoftTeams{
WebHookURLSecretKeySelector: v1alpha2.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: testSecretName,
},

View File

@ -12,12 +12,6 @@ import (
)
const (
// LogWarn is warning log entry
LogWarn LoggingLevel = "warn"
// LogInfo is info log entry
LogInfo LoggingLevel = "info"
titleText = "Operator reconciled."
messageFieldName = "Message"
loggingLevelFieldName = "Logging Level"
@ -33,7 +27,7 @@ var (
testNamespace = "default"
testMessage = "test-message"
testMessageVerbose = "detail-test-message"
testLoggingLevel = LogWarn
testLoggingLevel = v1alpha2.NotificationLogLevelWarning
client = http.Client{}
)
@ -48,7 +42,7 @@ type LoggingLevel string
type Event struct {
Jenkins v1alpha2.Jenkins
ConfigurationType string
LogLevel LoggingLevel
LogLevel v1alpha2.NotificationLogLevel
Message string
MessageVerbose string
}
@ -65,11 +59,11 @@ func Listen(events chan Event, k8sClient k8sclient.Client) {
var err error
var svc service
if notificationConfig.Slack != (v1alpha2.Slack{}) {
if notificationConfig.Slack != nil {
svc = Slack{k8sClient: k8sClient}
} else if notificationConfig.Teams != (v1alpha2.Teams{}) {
} else if notificationConfig.Teams != nil {
svc = Teams{k8sClient: k8sClient}
} else if notificationConfig.Mailgun != (v1alpha2.Mailgun{}) {
} else if notificationConfig.Mailgun != nil {
svc = MailGun{k8sClient: k8sClient}
} else {
logger.V(log.VWarn).Info(fmt.Sprintf("Unexpected notification `%+v`", notificationConfig))
@ -93,7 +87,7 @@ func Listen(events chan Event, k8sClient k8sclient.Client) {
}
func notify(svc service, event Event, manifest v1alpha2.Notification) error {
if event.LogLevel == LogInfo && string(manifest.LoggingLevel) == string(LogWarn) {
if event.LogLevel == v1alpha2.NotificationLogLevelInfo && manifest.LoggingLevel == v1alpha2.NotificationLogLevelWarning {
return nil
}

View File

@ -14,7 +14,7 @@ import (
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
)
// Slack is messaging service
// Slack is a Slack notification service
type Slack struct {
k8sClient k8sclient.Client
}
@ -43,11 +43,11 @@ type SlackField struct {
Short bool `json:"short"`
}
func (s Slack) getStatusColor(logLevel LoggingLevel) StatusColor {
func (s Slack) getStatusColor(logLevel v1alpha2.NotificationLogLevel) StatusColor {
switch logLevel {
case LogInfo:
case v1alpha2.NotificationLogLevelInfo:
return "#439FE0"
case LogWarn:
case v1alpha2.NotificationLogLevelWarning:
return "danger"
default:
return "#c8c8c8"
@ -57,7 +57,7 @@ func (s Slack) getStatusColor(logLevel LoggingLevel) StatusColor {
// Send is function for sending directly to API
func (s Slack) Send(event Event, config v1alpha2.Notification) error {
secret := &corev1.Secret{}
selector := config.Slack.URLSecretKeySelector
selector := config.Slack.WebHookURLSecretKeySelector
err := s.k8sClient.Get(context.TODO(), types.NamespacedName{Name: selector.Name, Namespace: event.Jenkins.Namespace}, secret)
if err != nil {

View File

@ -84,8 +84,8 @@ func TestSlack_Send(t *testing.T) {
assert.NoError(t, err)
err = slack.Send(event, v1alpha2.Notification{
Slack: v1alpha2.Slack{
URLSecretKeySelector: v1alpha2.SecretKeySelector{
Slack: &v1alpha2.Slack{
WebHookURLSecretKeySelector: v1alpha2.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: testSecretName,
},
@ -93,6 +93,5 @@ func TestSlack_Send(t *testing.T) {
},
},
})
assert.NoError(t, err)
}