Не могу зацепиться за агента Дженкинса. Данный файл или каталог отсутствует

Я использую Jenkins для настройки CI для приложения Android. Я пытаюсь настроить Android SDK как глобальный инструмент Jenkins, используя плагин Custom Tools. Вот установочный скрипт, который я настраиваю Jenkins>Global Tool Configuration,

printf "\nInstalling Android SDK as a Jenkins Custom Tool\n"

pwd
ls -la

if [ ! -d build-tools ];
    then
        printf "There's no dir by the name 'build-tools' on this agent yet. Will proceed to install the Android SDK.\n"

        printf "Downloading the Android SDK tools for Linux\n"
        curl -o android.zip https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
        printf "Download successful\n"

        printf "Unzipping downloaded Android SDK tools\n"
        unzip -o -z android.zip
        printf "Done unzipping\n"

        printf "Removing downloaded zip file\n"
        rm android.zip
        printf "Done removing\n"

        printf "Installing Android Build Tools 23.0.1\n"
        echo "y" | tools/bin/sdkmanager "build-tools;23.0.1"
        printf "Done installing Android Build Tools 23.0.1\n"
    else
        printf "There's already a dir by the name 'build-tools' on this agent. Aborting installation of the Android SDK.\n"
fi
printf "Done installing Android SDK as a Jenkins Custom Tool\n\n"

Работа, которую я сейчас пытаюсь настроить, загружает неподписанный apk из другого места и пытается подписать его.

Вот Дженкинсфайл:

properties([
    parameters([
        [
            $class: 'CredentialsParameterDefinition',
            name: 'ANDROID_KEYSTORE_FILE',
            credentialType: 'com.cloudbees.plugins.credentials.impl.CertificateCredentialsImpl',
            defaultValue: params.ANDROID_KEYSTORE_FILE?:'',
            description: 'The Android keystore file in p12 format.',
            required: false
        ],
        string(
            name: 'ANDROID_SIGN_KEY_ALIAS',
            defaultValue: params.ANDROID_SIGN_KEY_ALIAS?:'',
            description: 'The alias of the signing key inside your keystore. If your keystore only has one key, you can leave this blank.',
        ),
    ])
])

stage('Binary sign'){
    node('standard'){
        def pwd = pwd()
        echo(pwd)
        sh('curl -o foo-unsigned.apk https://some/place/in/my/intranet/FooApp_12.apk')
        sh('ls -la')

        def androidHome = tool('android-sdk')

        //Let's sign and archive the unsigned and signed apk files
        withEnv([
            "ANDROID_HOME=${androidHome}"]) {

            signAndroidApks (
                keyStoreId: params.ANDROID_KEYSTORE_FILE,
                keyAlias: params.ANDROID_SIGN_KEY_ALIAS,
                apksToSign: "**/*-unsigned.apk",
                androidHome: env.ANDROID_HOME,
                archiveSignedApks: true,
                archiveUnsignedApks: true
            )   
        }
    }
}

Вы можете видеть, что я использую шаг signAndroidApks. Проблема в том, что когда он выполняется, я получаю эту ошибку:

[android-sign-test] $ echo "resolving effective environment"
[SignApksBuilder] zipalign ANDROID_HOME explicitly set to /Jenkins/tools/com.cloudbees.jenkins.plugins.customtools.CustomTool/android
[SignApksBuilder] found zipalign in Android SDK's latest build tools: /Jenkins/tools/com.cloudbees.jenkins.plugins.customtools.CustomTool/android/build-tools/23.0.1/zipalign
[SignApksBuilder] /Jenkins/tools/com.cloudbees.jenkins.plugins.customtools.CustomTool/android/build-tools/23.0.1/zipalign -f -p 4 /Jenkins/workspace/AFS-2.0/android-sign-test/foo-unsigned.apk /Jenkins/workspace/AFS-2.0/android-sign-test/SignApksBuilder-out/zipalign/aligned-foo-unsigned-6084722845076851930.apk
[android-sign-test] $ /Jenkins/tools/com.cloudbees.jenkins.plugins.customtools.CustomTool/android/build-tools/23.0.1/zipalign -f -p 4 /Jenkins/workspace/AFS-2.0/android-sign-test/foo-unsigned.apk /Jenkins/workspace/AFS-2.0/android-sign-test/SignApksBuilder-out/zipalign/aligned-foo-unsigned-6084722845076851930.apk
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
    at hudson.Proc$LocalProc.<init>(Proc.java:249)
    at hudson.Proc$LocalProc.<init>(Proc.java:218)
    at hudson.Launcher$LocalLauncher.launch(Launcher.java:930)
    at hudson.Launcher$ProcStarter.start(Launcher.java:450)
    at hudson.Launcher$RemoteLaunchCallable.call(Launcher.java:1299)
    at hudson.Launcher$RemoteLaunchCallable.call(Launcher.java:1260)
    at hudson.remoting.UserRequest.perform(UserRequest.java:153)
    at hudson.remoting.UserRequest.perform(UserRequest.java:50)
    at hudson.remoting.Request$2.run(Request.java:336)
    at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:68)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at hudson.remoting.Engine$1$1.run(Engine.java:94)
    at java.lang.Thread.run(Thread.java:748)
Caused: java.io.IOException: Cannot run program "/Jenkins/tools/com.cloudbees.jenkins.plugins.customtools.CustomTool/android/build-tools/23.0.1/zipalign" (in directory "/Jenkins/workspace/AFS-2.0/android-sign-test"): error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at hudson.Proc$LocalProc.<init>(Proc.java:249)
    at hudson.Proc$LocalProc.<init>(Proc.java:218)
    at hudson.Launcher$LocalLauncher.launch(Launcher.java:930)
    at hudson.Launcher$ProcStarter.start(Launcher.java:450)
    at hudson.Launcher$RemoteLaunchCallable.call(Launcher.java:1299)
    at hudson.Launcher$RemoteLaunchCallable.call(Launcher.java:1260)
    at hudson.remoting.UserRequest.perform(UserRequest.java:153)
    at hudson.remoting.UserRequest.perform(UserRequest.java:50)
    at hudson.remoting.Request$2.run(Request.java:336)
    at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:68)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at hudson.remoting.Engine$1$1.run(Engine.java:94)
    at java.lang.Thread.run(Thread.java:748)
    at ......remote call to JNLP4-connect connection from ip-172-16-2-29.eu-west-1.compute.internal/172.16.2.29:44916(Native Method)
    at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1545)
    at hudson.remoting.UserResponse.retrieve(UserRequest.java:253)
    at hudson.remoting.Channel.call(Channel.java:830)
    at hudson.Launcher$RemoteLauncher.launch(Launcher.java:1053)
    at hudson.Launcher$ProcStarter.start(Launcher.java:450)
    at hudson.Launcher$ProcStarter.join(Launcher.java:461)
    at org.jenkinsci.plugins.androidsigning.SignApksBuilder.perform(SignApksBuilder.java:332)
    at org.jenkinsci.plugins.androidsigning.SignApksStep$SignApksStepExecution.run(SignApksStep.java:174)
    at org.jenkinsci.plugins.androidsigning.SignApksStep$SignApksStepExecution.run(SignApksStep.java:126)
    at org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution$1$1.call(AbstractSynchronousNonBlockingStepExecution.java:47)
    at hudson.security.ACL.impersonate(ACL.java:260)
    at org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution$1.run(AbstractSynchronousNonBlockingStepExecution.java:44)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Finished: FAILURE

Вы можете увидеть, что стек говорит No such file or directory, но я проверил, и исполняемый файл zipalign, и неподписанный apk находятся там, где они должны быть. Кто-нибудь сталкивался с этой проблемой раньше? Есть идеи?

1 ответ

Я нашел решение проблемы. Сначала я попробовал более простой скрипт, чтобы посмотреть, смогу ли я на самом деле вызвать zipalign программа:

stage('Binary sign'){
    node('standard'){

        sh("/Jenkins/tools/com.cloudbees.jenkins.plugins.customtools.CustomTool/android-sdk/build-tools/23.0.1/zipalign")
    }
}

Это вызвало следующую ошибку:

zipalign: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory

После небольшого исследования я обнаружил, что это связано с отсутствием поддержки 32-битных исполняемых файлов в некоторых дистрибутивах Linux. Мой агент сборки работал под управлением AWS Linux, который, по-видимому, не имеет встроенной поддержки 32-разрядных двоичных файлов. Инструменты сборки Android SDK - это 32-битные исполняемые файлы. Поэтому после некоторых исследований я попытался установить библиотеки для поддержки 32-битных двоичных файлов:

yum install glibc.i686

Выполнение того же сценария, приведенного выше, произвело эту ошибку:

zipalign: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory

Тогда я тоже попробовал:

yum install libzip.i686

И это наконец решило проблему. Сценарий выше теперь отображает нормальный ответ zipalign должен когда вызывается без аргументов.

Zip alignment utility
Copyright (C) 2009 The Android Open Source Project

Usage: zipalign [-f] [-p] [-v] [-z] <align> infile.zip outfile.zip
       zipalign -c [-v] <align> infile.zip

  <align>: alignment in bytes, e.g. '4' provides 32-bit alignment
  -c: check alignment only (does not modify file)
  -f: overwrite existing outfile.zip
  -p: page align stored shared object files
  -v: verbose output
  -z: recompress using Zopfli

Мой оригинальный сценарий теперь работает нормально.

Другие вопросы по тегам