docker icon indicating copy to clipboard operation
docker copied to clipboard

Preventing plugin setup wizard

Open carlossg opened this issue 8 years ago • 33 comments

if I use

FROM jenkins:2.7.1
RUN echo 2.7.1 > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state
RUN echo 2.7.1 > /usr/share/jenkins/ref/jenkins.install.InstallUtil.lastExecVersion

then I can avoid the wizard, but the admin password is not printed in the logs

Is there a way to just prevent the plugin setup?

carlossg avatar Jul 18 '16 14:07 carlossg

Not sure. @kzantow do you know?

jglick avatar Jul 26 '16 01:07 jglick

If the initial admin user is actually created, it should print to the logs, see: https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/install/SetupWizard.java#L91-L153

You may also want to pass -Djenkins.install.runSetupWizard=false to skip the initial setup altogether.

Optionally, you could cat $JENKINS_HOME/secrets/initialAdminPassword.

kzantow avatar Jul 26 '16 01:07 kzantow

If you actually just want to prevent the plugin setup, but you DO want the initial security setup, you can implement your own InstallStateFilter to alter the flow. You would need a plugin installed at boot time or to inject a class file into the war distribution, though. See: https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/install/UpgradeWizard.java#L154 for a simple example.

kzantow avatar Jul 26 '16 02:07 kzantow

The problem with -Djenkins.install.runSetupWizard=false is that it is a runtime flag, not build time, vs. burning a file in the image I'd say the typical flow is to build the image with some preconfigured plugins, then not ask for plugin setup at startup. Creating the admin user may be ok.

carlossg avatar Jul 26 '16 06:07 carlossg

Hm, is there any way to provide a properties file or set system properties at boot time? Maybe hook into this somehow? https://github.com/jenkinsci/extras-executable-war/blob/master/src/main/java/Main.java#L171

kzantow avatar Jul 26 '16 13:07 kzantow

at boot time yes, you can set JAVA_OPTS=-Djenkins.install.runSetupWizard=false but I'm looking for something to do at build time, as it is then when the plugins are installed into the image

carlossg avatar Jul 26 '16 14:07 carlossg

I guess as things stand, either package it with a modification to the Main file I referenced to set the system property (or find a way to include a properties file in the distribution... or just add the command line flag to a run script if this is for a docker image). Or package a simple plugin that overrides the default behavior. It's trivial to do the latter, just involves actually making a plugin. I could send you an example, but it's basically the same as the UpgradeWizard I referenced: you just plug into the lifecycle, and set it to the RUNNING state, no matter what and It'll bypass the wizard (or wait until the security is configured and send it to the RUNNING state). There are a lot of solutions to this problem, let me know if I can help any other way.

kzantow avatar Jul 26 '16 17:07 kzantow

@carlossg Is there any update here?

recena avatar Aug 11 '16 14:08 recena

No updates. IIUC there is the option to skip the wizard but not a way to skip only plugin installation.

carlossg avatar Aug 11 '16 15:08 carlossg

@carlossg Again, a fairly trivial InstallStateFilter will do the trick, you just need to add a plugin with it before the app starts.

kzantow avatar Aug 11 '16 15:08 kzantow

@kzantow yes, I mean there is no way for someone extending the image to just do that easily with a file marker or something like that

carlossg avatar Aug 11 '16 15:08 carlossg

In our case we created a new Jenkins image which automatically installs some plugins and creates a admin user with a default password. So there is no Jenkins setup visible and after starting the container you can directly use Jenkins. See here: https://github.com/foxylion/docker-jenkins

foxylion avatar Sep 26 '16 09:09 foxylion

@foxylion I tried using the approach you described after looking at your Dockerfile but, I can't login to Jenkins. The Docker image built fine but when I try to login via the Jenkins web UI, I specify the default id and password that were also specified in the Dockefile and I get: Invalid login information. Please try again.

Never mind, I looked closer at your Dockerfile and figured it out....

carltonmason avatar Oct 01 '16 15:10 carltonmason

@ckmason You're missing the Groovy file to add the user: https://github.com/foxylion/docker-jenkins/blob/master/docker-images/master/default-user.groovy

Edit: Ok. :smile:

foxylion avatar Oct 04 '16 07:10 foxylion

@foxylion -- I am having trouble making my own image using your ideas, so I've fallen back on using your image but that doesn't work either. Details in foxylion/docker-jenkins#1

hartzell avatar Nov 03 '16 01:11 hartzell

@kzantow Can you please expain this behaviour? When I create a new Jenkins container with no mounts to store data in the host, then complete the Jenkins setup and then stop the container to save it as a new docker image (docker commit ...). Why isn't the setup completed when I start a new container with the saved image? I was expecting that my saved image contains now a Jenkins that is configured and ready to use.

e.g.:

sudo docker pull jenkins sudo docker run -d -p 8080:8080 jenkins ...complete Jenkins setup .... sudo docker stop a9 sudo docker commit a9 foo sudo docker rm a9 sudo docker run -d -p 8080:8080 foo .... do Jenkins setup again because it can find the old setup

Is there a way to save images with Jenkins data? I want to use my Docker registry as a backup system

krm1 avatar Feb 13 '17 17:02 krm1

Ok, found it out, its because of the Volume statement in the Dockerfile, removing it gets me to the expected behaviour.

https://github.com/jenkinsci/docker/blob/fd794015787ba07d84a7c8d4c625652e648408c5/Dockerfile#L21

krm1 avatar Feb 13 '17 17:02 krm1

@krm1 to clarify, volumes are not preserved into an image layer during commit.

dejayc avatar Sep 14 '17 17:09 dejayc

So @kzantow there is still no way to choose not to run the plugin install wizard at build time?

carlossg avatar Nov 10 '17 10:11 carlossg

@kzantow It is possible, have a look at my customized image: https://github.com/foxylion/docker-jenkins You can also use this image directly.

foxylion avatar Nov 10 '17 10:11 foxylion

If you want to do this from just groovy, I think correct incantation is:

import static jenkins.model.Jenkins.instance as jenkins
import jenkins.install.InstallState
if (!jenkins.installState.isSetupComplete()) {
  println '--> Neutering SetupWizard'
  InstallState.INITIAL_SETUP_COMPLETED.initializeState()
}

coderanger avatar Nov 14 '17 01:11 coderanger

@foxylion In your master docker image, I can see where you copy your groovy scripts, but where in the Dockerfile do you Run them? Sorry if I'm missing something totally obvious, I'm a docker noob!

ckhajavi avatar Feb 15 '18 17:02 ckhajavi

Ohh nm, it's because it's an init file.

ckhajavi avatar Feb 15 '18 17:02 ckhajavi

@coderanger 's incantation worked for me.

Worth noting, I could not get it to work when executing through a $JENKINS_HOME/init.groovy hook. Inside the call to InstallState.INITIAL_SETUP_COMPLETED.initializeState(), a null SetupWizard object was returned here which caused the init.groovy script to crash. But when running the script as the admin or any other user with appropriate permissions, it successfully disabled the Startup Wizard.

thorntonryan avatar Feb 15 '18 22:02 thorntonryan

This is what was working for me inside docker for Jenkins version 2.107.3. I created this groovy script which disables setup wizard and creates admin user with custom admin password so you can just cut out the part with creating user if you don't need that.

basic-security.groovy

#!groovy
import jenkins.model.*
import hudson.security.*
import jenkins.install.InstallState

def instance = Jenkins.getInstance()

println "--> creating local user 'admin'"
// Create user with custom pass
def user = instance.getSecurityRealm().createAccount('admin', 'someAdminPass')
user.save()

def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
strategy.setAllowAnonymousRead(false)
instance.setAuthorizationStrategy(strategy)

if (!instance.installState.isSetupComplete()) {
  println '--> Neutering SetupWizard'
  InstallState.INITIAL_SETUP_COMPLETED.initializeState()
}

instance.save()

Then in Dockerfile

COPY basic-security.groovy /var/lib/jenkins/init.groovy.d/

# In case you are running as root
RUN chown -R jenkins:jenkins /var/lib/jenkins/init.groovy.d/

Also if you want preinstalled plugins when building the image, you will need to copy plugin installation script from orginal Jenkins docker repository and optionally a text file with plugins to be installed.

install-plugins.sh https://github.com/jenkinsci/docker/blob/master/install-plugins.sh jenkins-support https://github.com/jenkinsci/docker/blob/master/jenkins-support

Plugins file example: plugins.txt https://github.com/fabric8io/jenkins-docker/blob/master/plugins.txt

Dockerfile

COPY install-plugins.sh /usr/local/bin/
COPY jenkins-support /usr/local/bin/
COPY plugins.txt /var/lib/jenkins/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /var/lib/jenkins/plugins.txt

For me, the problem was default jenkins directory which is /var/lib/jenkins and preinstalled plugins go to /usr/share/jenkins/ref/plugins. Although the script should move installed plugins to /var/lib/jenkins/plugins, for some reason it didn't work. So I needed to change REF_DIR variable in install-plugins.sh script. After that, the script will install plugins directly to Jenkins home folder.

REF_DIR=${REF:-/usr/share/jenkins/ref/plugins}
to
REF_DIR=${REF:-/var/lib/jenkins/plugins}

Alternatively, if you don't want to change file directly you can do it with sed while building the image: RUN sed -i "/REF_DIR=/c\REF_DIR=${REF:-/var/lib/jenkins/plugins}" /usr/local/bin/install-plugins.sh

cromat avatar May 18 '18 07:05 cromat

@cromat Unfortunately the code for disabling the wizard does not work as of 2.121.1

bkowenswork avatar Aug 10 '18 15:08 bkowenswork

@foxylion after skip the setup wizard.the file jenkins.model.JenkinsLocationConfiguration.xml at jenkins_home was missed. and in that case when I access the BUILD_URL or JOB_URL then will ruturn null, so I have to click the save-button in system settings.and after that the file jenkins.model.JenkinsLocationConfiguration.xml was be created. and as you know the jenkinsUrl in that file which can't be predefined in Dockerfile. is there anything else I can do ?

gaoguoxin avatar Jan 29 '19 12:01 gaoguoxin

This seems to cause a great deal of confusion, see e.g.

  • https://issues.jenkins-ci.org/browse/JENKINS-40279
  • https://github.com/jenkinsci/configuration-as-code-plugin/issues/393
  • https://github.com/geerlingguy/ansible-role-jenkins/issues/50
  • https://riptutorial.com/jenkins/example/24925/disable-setup-wizard

etc. But many instructions seem wrong, outdated, etc. I can't yet find a method that actually works.

The answer "oh, just click OK" isn't really cool. This is meant to be a CI system, surely making it unnecessarily painful to deploy in fully automated, testable, configuration managed manner isn't ideal.

I was eventually able to make it behave with two JAVA_OPTS properties, e.g.

docker run -it -p 8080:8080 -p 50000:50000 --rm \
  --env JAVA_OPTS="-Djenkins.install.runSetupWizard=false" \
  jenkins/jenkins

(Obviously my real run uses volumes etc, this is a minimal example)

I've created https://github.com/jenkinsci/docker/pull/833 to request some changes

ringerc avatar Jun 06 '19 07:06 ringerc

After some trial and error, I was able to disable just the plugin installation phase of the installation wizard, without affecting the other sections.

The code I'm using is here: https://github.com/gryphon-zone/jenkins/blob/7788a6f9668561d5631c4c4b12fc69ba3bec1d84/configuration/disable-plugin-install-wizard.groovy And I'm adding it into my Dockerfile here: https://github.com/gryphon-zone/jenkins/blob/7788a6f9668561d5631c4c4b12fc69ba3bec1d84/Dockerfile#L41-L42

(worth noting, I'm doing other customization in the Dockerfile to make Jenkins work for my specific use case, but the disable-plugin-install-wizard.groovy script is solely for disabling the plugin section of the wizard, and can be used in isolation of any of the rest of the repo)

As mentioned in the comments for the groovy script, right now there isn't a dedicated installation state for the plugin configuration section of the wizard (or at least if there is, I couldn't find it), meaning it's possible that the script will break in a future release of Jenkins/start skipping more than just the plugin installation (if dedicated states are added in the future I'll update the script).

Additionally, I'm using the deprecated ExtensionList.add() method: https://github.com/jenkinsci/jenkins/blob/57a3268afb749c84196ce5fa3cfd51b08cda1328/core/src/main/java/hudson/ExtensionList.java#L263-L279 (that may not be required, I haven't tried to get automatic registration working).

Definitely agree that given the presence of the install-plugins.sh, it would be much more convenient if there were a simpler way to disable just the plugin installation phase of the wizard, without affecting other aspects.

Also worth mentioning, adding -Djenkins.install.runSetupWizard=false isn't a good option anymore if your intention is just to skip plugin installation (if it ever was), because it bypasses the entire setup wizard, meaning things like adding an admin user and configuring the base URL are also skipped.

chief-tyrol avatar Jun 24 '19 04:06 chief-tyrol

I think the README should be corrected, as is it misleading in its current state. The README clearly states:

For 2.x-derived images, you may also want to

RUN echo 2.0 > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state

to indicate that this Jenkins installation is fully configured. Otherwise a banner will appear prompting the user to install additional plugins, which may be inappropriate.

This is clearly wrong, so this should be removed from the README.

ChristianCiach avatar Feb 24 '20 14:02 ChristianCiach