#27 Restart Jenkins when any user plugin version has changed
This commit is contained in:
parent
78f801b211
commit
67550f962f
|
|
@ -88,13 +88,12 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenki
|
||||||
}
|
}
|
||||||
r.logger.V(log.VDebug).Info("Jenkins API client set")
|
r.logger.V(log.VDebug).Info("Jenkins API client set")
|
||||||
|
|
||||||
ok, err := r.verifyPlugins(jenkinsClient)
|
ok, err := r.verifyPlugins(jenkinsClient, plugins.BasePluginsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return reconcile.Result{}, nil, err
|
return reconcile.Result{}, nil, err
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
r.logger.V(log.VWarn).Info("Please correct Jenkins CR(spec.master.OperatorPlugins or spec.master.plugins)")
|
r.logger.Info("Some plugins have changed, restarting Jenkins")
|
||||||
// TODO inform user via Admin Monitor and don't restart Jenkins
|
|
||||||
return reconcile.Result{Requeue: true}, nil, r.restartJenkinsMasterPod(metaObject)
|
return reconcile.Result{Requeue: true}, nil, r.restartJenkinsMasterPod(metaObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +149,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsclient.Jenkins) (bool, error) {
|
func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsclient.Jenkins, basePlugins map[string][]plugins.Plugin) (bool, error) {
|
||||||
allPluginsInJenkins, err := jenkinsClient.GetPlugins(fetchAllPlugins)
|
allPluginsInJenkins, err := jenkinsClient.GetPlugins(fetchAllPlugins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, stackerr.WithStack(err)
|
return false, stackerr.WithStack(err)
|
||||||
|
|
@ -158,7 +157,7 @@ func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsc
|
||||||
|
|
||||||
var installedPlugins []string
|
var installedPlugins []string
|
||||||
for _, jenkinsPlugin := range allPluginsInJenkins.Raw.Plugins {
|
for _, jenkinsPlugin := range allPluginsInJenkins.Raw.Plugins {
|
||||||
if !jenkinsPlugin.Deleted {
|
if isValidPlugin(jenkinsPlugin) {
|
||||||
installedPlugins = append(installedPlugins, plugins.Plugin{Name: jenkinsPlugin.ShortName, Version: jenkinsPlugin.Version}.String())
|
installedPlugins = append(installedPlugins, plugins.Plugin{Name: jenkinsPlugin.ShortName, Version: jenkinsPlugin.Version}.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -178,7 +177,7 @@ func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsc
|
||||||
}
|
}
|
||||||
|
|
||||||
status := true
|
status := true
|
||||||
allRequiredPlugins := []map[string][]plugins.Plugin{plugins.BasePluginsMap, userPlugins}
|
allRequiredPlugins := []map[string][]plugins.Plugin{basePlugins, userPlugins}
|
||||||
for _, requiredPlugins := range allRequiredPlugins {
|
for _, requiredPlugins := range allRequiredPlugins {
|
||||||
for rootPluginName, p := range requiredPlugins {
|
for rootPluginName, p := range requiredPlugins {
|
||||||
rootPlugin, _ := plugins.New(rootPluginName)
|
rootPlugin, _ := plugins.New(rootPluginName)
|
||||||
|
|
@ -195,16 +194,43 @@ func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for rootPluginName, p := range userPlugins {
|
||||||
|
rootPlugin, _ := plugins.New(rootPluginName)
|
||||||
|
if found, ok := isPluginVersionCompatible(allPluginsInJenkins, *rootPlugin); !ok {
|
||||||
|
r.logger.V(log.VWarn).Info(fmt.Sprintf("Incompatible plugin '%s' version, actual '%+v'", rootPlugin, found))
|
||||||
|
status = false
|
||||||
|
}
|
||||||
|
for _, requiredPlugin := range p {
|
||||||
|
if found, ok := isPluginInstalled(allPluginsInJenkins, requiredPlugin); !ok {
|
||||||
|
r.logger.V(log.VWarn).Info(fmt.Sprintf("Incompatible plugin '%s' version, actual '%+v'", requiredPlugin, found))
|
||||||
|
status = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return status, nil
|
return status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isPluginVersionCompatible(plugins *gojenkins.Plugins, plugin plugins.Plugin) (gojenkins.Plugin, bool) {
|
||||||
|
p := plugins.Contains(plugin.Name)
|
||||||
|
if p == nil {
|
||||||
|
return gojenkins.Plugin{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return *p, p.Version == plugin.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidPlugin(plugin gojenkins.Plugin) bool {
|
||||||
|
return plugin.Active && plugin.Enabled && !plugin.Deleted
|
||||||
|
}
|
||||||
|
|
||||||
func isPluginInstalled(plugins *gojenkins.Plugins, requiredPlugin plugins.Plugin) (gojenkins.Plugin, bool) {
|
func isPluginInstalled(plugins *gojenkins.Plugins, requiredPlugin plugins.Plugin) (gojenkins.Plugin, bool) {
|
||||||
p := plugins.Contains(requiredPlugin.Name)
|
p := plugins.Contains(requiredPlugin.Name)
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return gojenkins.Plugin{}, false
|
return gojenkins.Plugin{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return *p, p.Active && p.Enabled && !p.Deleted
|
return *p, isValidPlugin(*p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta metav1.ObjectMeta) error {
|
func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta metav1.ObjectMeta) error {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
||||||
|
"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/configuration/base/resources"
|
||||||
|
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/plugins"
|
||||||
|
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||||
|
|
||||||
|
"github.com/bndr/gojenkins"
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
)
|
)
|
||||||
|
|
@ -149,3 +154,216 @@ func TestCompareVolumes(t *testing.T) {
|
||||||
assert.True(t, got)
|
assert.True(t, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReconcileJenkinsBaseConfiguration_verifyPlugins(t *testing.T) {
|
||||||
|
log.SetupLogger(true)
|
||||||
|
|
||||||
|
t.Run("happy, empty base and user plugins", func(t *testing.T) {
|
||||||
|
jenkins := &v1alpha1.Jenkins{}
|
||||||
|
r := ReconcileJenkinsBaseConfiguration{
|
||||||
|
logger: log.Log,
|
||||||
|
jenkins: jenkins,
|
||||||
|
}
|
||||||
|
pluginsInJenkins := &gojenkins.Plugins{
|
||||||
|
Raw: &gojenkins.PluginResponse{},
|
||||||
|
}
|
||||||
|
basePlugins := map[string][]plugins.Plugin{}
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
jenkinsClient := client.NewMockJenkins(ctrl)
|
||||||
|
jenkinsClient.EXPECT().GetPlugins(fetchAllPlugins).Return(pluginsInJenkins, nil)
|
||||||
|
|
||||||
|
got, err := r.verifyPlugins(jenkinsClient, basePlugins)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, got)
|
||||||
|
})
|
||||||
|
t.Run("happy, not empty base and empty user plugins", func(t *testing.T) {
|
||||||
|
jenkins := &v1alpha1.Jenkins{}
|
||||||
|
r := ReconcileJenkinsBaseConfiguration{
|
||||||
|
logger: log.Log,
|
||||||
|
jenkins: jenkins,
|
||||||
|
}
|
||||||
|
pluginsInJenkins := &gojenkins.Plugins{
|
||||||
|
Raw: &gojenkins.PluginResponse{
|
||||||
|
Plugins: []gojenkins.Plugin{
|
||||||
|
{
|
||||||
|
ShortName: "plugin-name",
|
||||||
|
Active: true,
|
||||||
|
Deleted: false,
|
||||||
|
Enabled: true,
|
||||||
|
Version: "0.0.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
basePlugins := map[string][]plugins.Plugin{
|
||||||
|
"plugin-name:0.0.1": {},
|
||||||
|
}
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
jenkinsClient := client.NewMockJenkins(ctrl)
|
||||||
|
jenkinsClient.EXPECT().GetPlugins(fetchAllPlugins).Return(pluginsInJenkins, nil)
|
||||||
|
|
||||||
|
got, err := r.verifyPlugins(jenkinsClient, basePlugins)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, got)
|
||||||
|
})
|
||||||
|
t.Run("happy, empty base and not empty user plugins", func(t *testing.T) {
|
||||||
|
jenkins := &v1alpha1.Jenkins{
|
||||||
|
Spec: v1alpha1.JenkinsSpec{
|
||||||
|
Master: v1alpha1.JenkinsMaster{
|
||||||
|
Plugins: map[string][]string{"plugin-name:0.0.1": {}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
r := ReconcileJenkinsBaseConfiguration{
|
||||||
|
logger: log.Log,
|
||||||
|
jenkins: jenkins,
|
||||||
|
}
|
||||||
|
pluginsInJenkins := &gojenkins.Plugins{
|
||||||
|
Raw: &gojenkins.PluginResponse{
|
||||||
|
Plugins: []gojenkins.Plugin{
|
||||||
|
{
|
||||||
|
ShortName: "plugin-name",
|
||||||
|
Active: true,
|
||||||
|
Deleted: false,
|
||||||
|
Enabled: true,
|
||||||
|
Version: "0.0.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
basePlugins := map[string][]plugins.Plugin{}
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
jenkinsClient := client.NewMockJenkins(ctrl)
|
||||||
|
jenkinsClient.EXPECT().GetPlugins(fetchAllPlugins).Return(pluginsInJenkins, nil)
|
||||||
|
|
||||||
|
got, err := r.verifyPlugins(jenkinsClient, basePlugins)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, got)
|
||||||
|
})
|
||||||
|
t.Run("happy, plugin version doesn't matter for base plugins", func(t *testing.T) {
|
||||||
|
jenkins := &v1alpha1.Jenkins{}
|
||||||
|
r := ReconcileJenkinsBaseConfiguration{
|
||||||
|
logger: log.Log,
|
||||||
|
jenkins: jenkins,
|
||||||
|
}
|
||||||
|
pluginsInJenkins := &gojenkins.Plugins{
|
||||||
|
Raw: &gojenkins.PluginResponse{
|
||||||
|
Plugins: []gojenkins.Plugin{
|
||||||
|
{
|
||||||
|
ShortName: "plugin-name",
|
||||||
|
Active: true,
|
||||||
|
Deleted: false,
|
||||||
|
Enabled: true,
|
||||||
|
Version: "0.0.2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
basePlugins := map[string][]plugins.Plugin{
|
||||||
|
"plugin-name:0.0.1": {},
|
||||||
|
}
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
jenkinsClient := client.NewMockJenkins(ctrl)
|
||||||
|
jenkinsClient.EXPECT().GetPlugins(fetchAllPlugins).Return(pluginsInJenkins, nil)
|
||||||
|
|
||||||
|
got, err := r.verifyPlugins(jenkinsClient, basePlugins)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, got)
|
||||||
|
})
|
||||||
|
t.Run("plugin version matter for user plugins", func(t *testing.T) {
|
||||||
|
jenkins := &v1alpha1.Jenkins{
|
||||||
|
Spec: v1alpha1.JenkinsSpec{
|
||||||
|
Master: v1alpha1.JenkinsMaster{
|
||||||
|
Plugins: map[string][]string{"plugin-name:0.0.2": {}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
r := ReconcileJenkinsBaseConfiguration{
|
||||||
|
logger: log.Log,
|
||||||
|
jenkins: jenkins,
|
||||||
|
}
|
||||||
|
pluginsInJenkins := &gojenkins.Plugins{
|
||||||
|
Raw: &gojenkins.PluginResponse{
|
||||||
|
Plugins: []gojenkins.Plugin{
|
||||||
|
{
|
||||||
|
ShortName: "plugin-name",
|
||||||
|
Active: true,
|
||||||
|
Deleted: false,
|
||||||
|
Enabled: true,
|
||||||
|
Version: "0.0.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
basePlugins := map[string][]plugins.Plugin{}
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
jenkinsClient := client.NewMockJenkins(ctrl)
|
||||||
|
jenkinsClient.EXPECT().GetPlugins(fetchAllPlugins).Return(pluginsInJenkins, nil)
|
||||||
|
|
||||||
|
got, err := r.verifyPlugins(jenkinsClient, basePlugins)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, got)
|
||||||
|
})
|
||||||
|
t.Run("missing base plugin", func(t *testing.T) {
|
||||||
|
jenkins := &v1alpha1.Jenkins{}
|
||||||
|
r := ReconcileJenkinsBaseConfiguration{
|
||||||
|
logger: log.Log,
|
||||||
|
jenkins: jenkins,
|
||||||
|
}
|
||||||
|
pluginsInJenkins := &gojenkins.Plugins{
|
||||||
|
Raw: &gojenkins.PluginResponse{
|
||||||
|
Plugins: []gojenkins.Plugin{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
basePlugins := map[string][]plugins.Plugin{
|
||||||
|
"plugin-name:0.0.2": {},
|
||||||
|
}
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
jenkinsClient := client.NewMockJenkins(ctrl)
|
||||||
|
jenkinsClient.EXPECT().GetPlugins(fetchAllPlugins).Return(pluginsInJenkins, nil)
|
||||||
|
|
||||||
|
got, err := r.verifyPlugins(jenkinsClient, basePlugins)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, got)
|
||||||
|
})
|
||||||
|
t.Run("missing user plugin", func(t *testing.T) {
|
||||||
|
jenkins := &v1alpha1.Jenkins{
|
||||||
|
Spec: v1alpha1.JenkinsSpec{
|
||||||
|
Master: v1alpha1.JenkinsMaster{
|
||||||
|
Plugins: map[string][]string{"plugin-name:0.0.2": {}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
r := ReconcileJenkinsBaseConfiguration{
|
||||||
|
logger: log.Log,
|
||||||
|
jenkins: jenkins,
|
||||||
|
}
|
||||||
|
pluginsInJenkins := &gojenkins.Plugins{
|
||||||
|
Raw: &gojenkins.PluginResponse{
|
||||||
|
Plugins: []gojenkins.Plugin{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
basePlugins := map[string][]plugins.Plugin{}
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
jenkinsClient := client.NewMockJenkins(ctrl)
|
||||||
|
jenkinsClient.EXPECT().GetPlugins(fetchAllPlugins).Return(pluginsInJenkins, nil)
|
||||||
|
|
||||||
|
got, err := r.verifyPlugins(jenkinsClient, basePlugins)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue