JClouds-Chef не загружает и не настраивает виртуальную машину

Я пытаюсь получить следующий код JClouds-Chef (v1.7.3) для начальной загрузки клиента Chef. на совершенно новой виртуальной машине Linux, а затем выполните список запуска, чтобы фактически настроить эту виртуальную машину со стеком приложений (typical_app):

public class ChefPlugin {
    public static void main(String[] args) {
        ChefPlugin.provision();
        System.out.println("And done!");
        System.exit(0);
    }

    public static provision() {
        String vmIp = "myapp01";
        String vmSshUsername = "myadmin";
        String vmSshPassword = "12345";

        String endpoint = "https://mychefserver";
        String client = "myuser";
        String validator = "chef-validator";
        String clientCredential = Files.toString(new File("C:\\Users\\myuser\\sandbox\\chef\\myuser.pem"), Charsets.UTF_8);
        String validatorCredential = Files.toString(new File("C:\\Users\\myuser\\sandbox\\chef\\chef-validator.pem"), Charsets.UTF_8);

        Properties props = new Properties();
        props.put(ChefProperties.CHEF_VALIDATOR_NAME, validator);
        props.put(ChefProperties.CHEF_VALIDATOR_CREDENTIAL, validatorCredential);
        props.put(Constants.PROPERTY_RELAX_HOSTNAME, "true");
        props.put(Constants.PROPERTY_TRUST_ALL_CERTS, "true");

        System.out.println("Setup complete.");

        ChefContext ctx = ContextBuilder.newBuilder("chef")
            .endpoint(endpoint)
            .credentials(client, clientCredential)
            .overrides(props)
            .modules(ImmutableSet.of(new SshjSshClientModule())) //
            .buildView(ChefContext.class);
        ChefService chef = ctx.getChefService();

        List<String> runlist = new RunListBuilder().addRole("typicalapp").build();

        ArrayList<String> runList2 = new ArrayList<String>();
        for(String item : runlist) {
            runList2.add(item);
        }

        BootstrapConfig bootstrapConfig = BootstrapConfig.builder().runList(runList2).build();

        System.out.println("Configured the bootstrapper.");

        chef.updateBootstrapConfigForGroup("jclouds-chef", bootstrapConfig);
        Statement bootstrap = chef.createBootstrapScriptForGroup("jclouds-chef");
        SshClient.Factory sshFactory = ctx.unwrap().utils()
            .injector().getInstance(Key.get(new TypeLiteral<SshClient.Factory>() {}));
        SshClient ssh = sshFactory.create(HostAndPort.fromParts(vmIp, 22),
        LoginCredentials.builder().user(vmSshUsername).password(vmSshPassword).build());

        ssh.connect();

        System.out.println("Connected to SSH.");
        try {
            String rawScript = bootstrap.render(OsFamily.UNIX);
            System.out.println("Raw script rendered.");
            ExecResponse result = ssh.exec(rawScript);

            System.out.println("Bootstrap script executed...");
        } catch(Throwable t) {
            System.out.println("Exception: " + t.getMessage());
        } finally {
            ssh.disconnect();
            System.out.println("SSH closed.");
        }
    }
}

Когда я запускаю это, я получаю следующий вывод от SLF4J:

Setup complete.
Configured the bootstrapper.
[main] INFO net.schmizz.sshj.common.SecurityUtils - BouncyCastle registration succeeded
[main] WARN net.schmizz.sshj.DefaultConfig - Disabling high-strength ciphers: cipher strengths apparently limited by JCE policy
[main] INFO net.schmizz.sshj.transport.TransportImpl - Client identity string: SSH-2.0-SSHJ_0/etc/chef1_SNAPSHOT
[main] INFO net.schmizz.sshj.transport.TransportImpl - Server identity string: SSH-2.0-OpenSSH_6.6p1 Ubuntu-2ubuntu1
Connected to SSH.
Raw script rendered.
[main] INFO net.schmizz.sshj.connection.channel.direct.SessionChannel - Will request to exec `setupPublicCurl || exit 1
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET  https://www.opscode.com/chef/install.sh |(bash)
mkdir -p /etc/chef
cat >> /etc/chef/client.rb <<-'END_OF_JCLOUDS_FILE'
    require 'rubygems'
    require 'ohai'
    o = Ohai::System.new
    o.all_plugins
    node_name "jclouds-chef-" + o[:ipaddress]
    log_level :info
    log_location STDOUT
    validation_client_name "chef-validator"
    chef_server_url "https://mychefserver"
END_OF_JCLOUDS_FILE
cat >> /etc/chef/validation.pem <<-'END_OF_JCLOUDS_FILE'
    -----BEGIN RSA PRIVATE KEY-----
    <omitted for security purposes>
    -----END RSA PRIVATE KEY-----

END_OF_JCLOUDS_FILE
cat >> /etc/chef/first-boot.json <<-'END_OF_JCLOUDS_FILE'
    {"id":"jclouds-chef","run_list":["role[typical_app]"]}
END_OF_JCLOUDS_FILE
chef-client -j /etc/chef/first-boot.json
`
Bootstrap script executed...
[main] INFO net.schmizz.sshj.transport.TransportImpl - Disconnected - BY_APPLICATION
SSH closed.
And done!

Когда я подключаюсь по SSH к серверу (myapp01), если я запускаю which ruby, я вижу, что Ruby установлен. Однако which chef-client не производит вывода, как и which java. На сервере также нет каталога /etc/chef. Это заставляет меня думать, что мой код работает лишь частично и, возможно, только устанавливает Ruby на виртуальную машину, но больше ничего. Вдобавок ко всему, если я не поставлю System.exit(0) после оператора печати "И готово!", код никогда не завершится. Это заставляет меня думать, что есть фоновый/рабочий поток (возможно, процесс SSH что-то делает на сервере), который не возвращается/не завершается.

Здесь нет ошибок или исключений.

Мои вопросы:

  1. Может ли кто-нибудь понять, почему этот код не работает (под "работает" я имею в виду, кажется, только частично устанавливает Chef Client и даже не устанавливает Java, которая является частью роли typical_app )?
  2. Я что-то упустил в своем коде, чтобы предотвратить завершение фонового потока? Почему он никогда не выходит?

Чтобы воспроизвести, используйте следующий Maven POM для извлечения зависимостей, а затем запустите приведенный выше код точно так, как он есть (просто используйте свой собственный сервер Chef и виртуальную машину Linux).

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <properties>
        <jclouds.version>1.7.3</jclouds.version>
    </properties>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.jclouds.driver</groupId>
            <artifactId>jclouds-sshj</artifactId>
            <version>${jclouds.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.jclouds.api</groupId>
            <artifactId>chef</artifactId>
            <version>${jclouds.version}</version>
        </dependency>
    </dependencies>
</project>

Обновление: вот мой файл /tmp/stderr, который я получил после внесения изменений, предложенных @Ignasi Barrera:

--2014-07-22 10:58:14--  https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/13.04/x86_64/chef_11.12.8-2_amd64.deb
Resolving opscode-omnibus-packages.s3.amazonaws.com (opscode-omnibus-packages.s3.amazonaws.com)... 176.32.100.240
Connecting to opscode-omnibus-packages.s3.amazonaws.com (opscode-omnibus-packages.s3.amazonaws.com)|176.32.100.240|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 33399362 (32M) [application/x-debian-package]
Saving to: ‘/tmp/install.sh.10185/chef_11.12.8-2_amd64.deb’

    0K .......... .......... .......... .......... ..........  0%  908K 36s
   50K .......... .......... .......... .......... ..........  0% 1.13M 32s
  100K .......... .......... .......... .......... ..........  0% 26.9M 22s
  150K .......... .......... .......... .......... ..........  0% 1.36M 22s
  200K .......... .......... .......... .......... ..........  0% 17.2M 18s
... omitted for brevity
32400K .......... .......... .......... .......... .......... 99% 2.64M 0s
32450K .......... .......... .......... .......... .......... 99% 26.2M 0s
32500K .......... .......... .......... .......... .......... 99% 31.9M 0s
32550K .......... .......... .......... .......... .......... 99% 6.12M 0s
32600K .......... ......                                     100% 4.09M=7.1s

2014-07-22 10:58:22 (4.49 MB/s) - ‘/tmp/install.sh.10185/chef_11.12.8-2_amd64.deb’ saved [33399362/33399362]

person IAmYourFaja    schedule 21.07.2014    source источник
comment
Этот вопрос кажется не по теме, потому что он включает 3 разных вопроса и не дает краткого объяснения и шагов воспроизведения.   -  person sethvargo    schedule 21.07.2014
comment
Извините, но я не согласен с @sethvargo. Я удалю третий пункт выше, но если вы прочитаете весь вопрос, то увидите, что первые два пункта очень тесно связаны и на них можно ответить одним и тем же изменение кода (правильное решение позволит правильно установить Chef Client и поток, выполняющий его, вернется). Также я не смог предоставить более емкое объяснение и набор шагов воспроизведения! Посмотрите выше, где я говорю Чтобы воспроизвести..., похоже, вы не читали эту часть. И это ни в коем случае не по теме: это вопрос программирования, в котором нет дубликатов и есть исследования.   -  person IAmYourFaja    schedule 21.07.2014
comment
Мои извенения. Мой предыдущий ответ на связанный вопрос не был на 100% точным, и для правильного отображения сценария потребовалось несколько ручных шагов. Я объяснил их здесь и подтвердил, что теперь они работают.   -  person Ignasi Barrera    schedule 22.07.2014


Ответы (1)


Основная проблема здесь заключается в том, что вы пытаетесь запустить скрипт на узле без использования службы вычислений jclouds. Код использует jclouds-chef для создания оператора, но предполагается, что этот оператор выполняется вычислительной службой jclouds, которая имеет свои собственные механизмы для обработки выполняемых сценариев.

Чтобы получить полный необработанный скрипт и иметь возможность выполнять его напрямую, используя необработанное SSH-соединение, необходимо выполнить несколько действий вручную. В частности, сценарий jclouds-chef предполагает, что определены несколько функций bash, а они отсутствуют при рендеринге сценария таким образом.

Вы должны изменить создание строки rawString следующим образом:

StringBuilder rawScript = new StringBuilder();

Map<String, String> resolvedFunctions = ScriptBuilder.resolveFunctionDependenciesForStatements(
    new HashMap<String, String>(), ImmutableSet.of(bootstrap), OsFamily.UNIX);

ScriptBuilder.writeFunctions(resolvedFunctions, OsFamily.UNIX, rawScript);
rawScript.append(bootstrap.render(OsFamily.UNIX));

ssh.put("/tmp/chef-bootstrap.sh", rawScript.toString());
ExecResponse result = ssh.exec("bash /tmp/chef-bootstrap.sh");

Таким образом, окончательный сценарий будет иметь все зависимые функции. Также обратите внимание, что вместо прямого запуска сценария я изменил код, чтобы загрузить его, а затем запустить файл локально. Это поможет вам устранить неполадки в случае сбоя сценария.

Также обратите внимание, что сценарий будет генерировать содержимое каталога /etc/chef при каждом запуске, поэтому перед повторным запуском вам может потребоваться удалить этот каталог.

person Ignasi Barrera    schedule 21.07.2014
comment
Спасибо @Ignasi Barrera (+1) - Пожалуйста, посмотрите мое обновление (включает /tmp/stderr). Я внес предложенные вами изменения, и теперь код завершает выполнение (нет зависших потоков), однако, когда я подключаюсь по SSH к машина, похоже, изменения все еще не сработали. Если я запускаю which ruby, я получаю /usr/bin/ruby, но which chef-client и which java (typicalapp — это веб-сервер Java) я не получаю вывода. Нет каталога /etc/chef, а в каталоге /tmp я вижу файл stderr, содержимое которого на самом деле не содержит ошибок/исключений. Любые идеи/мысли здесь? Спасибо еще раз! - person IAmYourFaja; 22.07.2014
comment
После сбоя подключитесь к машине по SSH, удалите каталог /etc/chef, если он существует, и запустите скрипт оттуда вручную. Вы увидите результат и то, что может быть не так. - person Ignasi Barrera; 22.07.2014
comment
Еще раз спасибо @Ignasi Barrera, но я не думаю, что вы меня понимаете: я говорю, что /etc/chef никогда даже не создается! Например, после выполнения кода я подключаюсь к машине по SSH и беги cd /etc/chef. Это производит вывод -bash: cd: /etc/chef: No such file or directory. - person IAmYourFaja; 22.07.2014
comment
Каталог создается скриптом, и, возможно, раньше он не работал. Я просто предлагаю вам подключиться к машине по SSH и запустить скрипт локально, чтобы выяснить, что происходит не так. - person Ignasi Barrera; 22.07.2014
comment
Спасибо @Ignasi Barrera (+1) - похоже, что сам сценарий chef-bootstrap.sh плохой. Когда я запускаю sh chef-bootstrap.sh, я получаю следующую ошибку: chef-bootstrap.sh: 5: chef-bootstrap.sh: Syntax error: "(" unexpected. Это соответствует следующей строке кода: function ensure_cmd_or_install_package_apt(){. Есть идеи? - person IAmYourFaja; 22.07.2014
comment
Отрендеренный скрипт - это bash, а не sh. Вы запускаете его с именем сценария bash? - person Ignasi Barrera; 22.07.2014
comment
Спасибо @Ignasi Barrera (+1) - да, я неправильно выполнял сценарий. Запустив его как bash chef-bootstrap.sh, я увидел ошибки: у пользователя myadmin нет разрешений sudo, и поэтому, когда chef-boostrap.sh пытается выполнить mkdir /etc/chef, у него нет на это прав. Эти виртуальные машины предоставляются через наш VMware vCenter (с использованием шаблонов), поэтому я работаю с нашей командой по инфраструктуре над изменением шаблона и предоставлением myadmin необходимого доступа. Как только я доберусь до этого момента, я попробую еще раз, и, надеюсь, все сработает! - person IAmYourFaja; 22.07.2014
comment
И просто для подтверждения, поскольку это был довольно болезненный процесс (я уверен, для нас обоих!), сценарий chef-boostrap.sh должен установить и запустить клиент шеф-повара на виртуальной машине, верно? Если нет, что мне нужно сделать, чтобы фактически запустить Chef Client и настроить виртуальную машину (как роль typicalapp)? - person IAmYourFaja; 22.07.2014
comment
Да, он установит все необходимое и запустит Chef. Надеюсь, у вас все получится! - person Ignasi Barrera; 22.07.2014
comment
Потребовалось время, чтобы получить запрос через ИТ. Да, это работает! Спасибо, @Ignasi Barrera! - person IAmYourFaja; 26.07.2014