#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")
|
||||
|
||||
ok, err := r.verifyPlugins(jenkinsClient)
|
||||
ok, err := r.verifyPlugins(jenkinsClient, plugins.BasePluginsMap)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, nil, err
|
||||
}
|
||||
if !ok {
|
||||
r.logger.V(log.VWarn).Info("Please correct Jenkins CR(spec.master.OperatorPlugins or spec.master.plugins)")
|
||||
// TODO inform user via Admin Monitor and don't restart Jenkins
|
||||
r.logger.Info("Some plugins have changed, restarting Jenkins")
|
||||
return reconcile.Result{Requeue: true}, nil, r.restartJenkinsMasterPod(metaObject)
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +149,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod
|
|||
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)
|
||||
if err != nil {
|
||||
return false, stackerr.WithStack(err)
|
||||
|
|
@ -158,7 +157,7 @@ func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsc
|
|||
|
||||
var installedPlugins []string
|
||||
for _, jenkinsPlugin := range allPluginsInJenkins.Raw.Plugins {
|
||||
if !jenkinsPlugin.Deleted {
|
||||
if isValidPlugin(jenkinsPlugin) {
|
||||
installedPlugins = append(installedPlugins, plugins.Plugin{Name: jenkinsPlugin.ShortName, Version: jenkinsPlugin.Version}.String())
|
||||
}
|
||||
}
|
||||
|
|
@ -178,7 +177,7 @@ func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsc
|
|||
}
|
||||
|
||||
status := true
|
||||
allRequiredPlugins := []map[string][]plugins.Plugin{plugins.BasePluginsMap, userPlugins}
|
||||
allRequiredPlugins := []map[string][]plugins.Plugin{basePlugins, userPlugins}
|
||||
for _, requiredPlugins := range allRequiredPlugins {
|
||||
for rootPluginName, p := range requiredPlugins {
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
p := plugins.Contains(requiredPlugin.Name)
|
||||
if p == nil {
|
||||
return gojenkins.Plugin{}, false
|
||||
}
|
||||
|
||||
return *p, p.Active && p.Enabled && !p.Deleted
|
||||
return *p, isValidPlugin(*p)
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta metav1.ObjectMeta) error {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,13 @@ import (
|
|||
"testing"
|
||||
|
||||
"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/plugins"
|
||||
"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"
|
||||
)
|
||||
|
|
@ -149,3 +154,216 @@ func TestCompareVolumes(t *testing.T) {
|
|||
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