简体   繁体   English

JClouds-Chef:TokenType2上的IllegalAccessError?

[英]JClouds-Chef: IllegalAccessError on TokenType2?

I am using the JClouds-Chef API to bootstrap a Linux VM ( myapp01.me.example.com ) with Chef Client, and to then run the client and configure the VM with its app stack via a typicalapp role: 我正在使用JClouds-Chef API通过Chef Client引导Linux VM( myapp01.me.example.com ),然后运行客户端并通过typicalapp角色配置VM及其应用程序堆栈:

package com.me.myorg.chef;

import org.jclouds.Constants
import org.jclouds.ContextBuilder
import org.jclouds.chef.ChefContext
import org.jclouds.chef.ChefService
import org.jclouds.chef.config.ChefProperties
import org.jclouds.chef.domain.BootstrapConfig
import org.jclouds.chef.util.RunListBuilder
import org.jclouds.compute.domain.ExecResponse
import org.jclouds.compute.domain.OsFamily
import org.jclouds.domain.LoginCredentials
import org.jclouds.scriptbuilder.domain.Statement
import org.jclouds.ssh.SshClient
import org.jclouds.sshj.config.SshjSshClientModule

import com.google.common.base.Charsets
import com.google.common.collect.ImmutableSet
import com.google.common.io.Files
import com.google.common.net.HostAndPort
import com.google.inject.Key
import com.google.inject.TypeLiteral

public class ChefProvisioner {
    public static void main(String[] args) {
        ChefProvisioner.provision()
    }

    public static provision() {
        String vmIp = "myapp01.me.example.com";     // A Linux VM living in our local vCenter
        String vmSshUsername = "admin";
        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");

        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();
        BootstrapConfig bootstrapConfig = BootstrapConfig.builder().runlist(runlist).build();

        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();
        try {
            String rawScript = bootstrap.render(OsFamily.UNIX);
            ExecResponse result = ssh.exec(rawScript);
        } finally {
            ssh.disconnect();
        }
    }
}

When I run this I get: 当我运行这个时,我得到:

Exception in thread "main" java.util.ServiceConfigurationError: org.jclouds.apis.ApiMetadata: Provider org.jclouds.openstack.swift.SwiftApiMetadata could not be instantiated: java.lang.IllegalAccessError: tried to access class com.google.common.reflect.TypeResolver from class org.jclouds.util.TypeToken2
    at java.util.ServiceLoader.fail(ServiceLoader.java:224)
    at java.util.ServiceLoader.access$100(ServiceLoader.java:181)
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:377)
    at java.util.ServiceLoader$1.next(ServiceLoader.java:445)
    at com.google.common.collect.ImmutableCollection$Builder.addAll(ImmutableCollection.java:323)
    at com.google.common.collect.ImmutableSet$Builder.addAll(ImmutableSet.java:633)
    at org.jclouds.apis.Apis.all(Apis.java:72)
    at org.jclouds.apis.Apis.withId(Apis.java:89)
    at org.jclouds.ContextBuilder.newBuilder(ContextBuilder.java:168)
    at org.jclouds.ContextBuilder$newBuilder.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at com.me.myorg.chef.ChefProvisioner.provision(ChefProvisioner.groovy:51)
    at com.me.myorg.chef.ChefProvisioner$provision.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at com.me.myorg.chef.ChefProvisioner.main(ChefProvisioner.groovy:27)
Caused by: java.lang.IllegalAccessError: tried to access class com.google.common.reflect.TypeResolver from class org.jclouds.util.TypeToken2
    at org.jclouds.util.TypeToken2.where(TypeToken2.java:47)
    at org.jclouds.rest.internal.BaseRestApiMetadata.contextToken(BaseRestApiMetadata.java:60)
    at org.jclouds.rest.internal.BaseRestApiMetadata$Builder.<init>(BaseRestApiMetadata.java:74)
    at org.jclouds.openstack.swift.SwiftApiMetadata$Builder.<init>(SwiftApiMetadata.java:85)
    at org.jclouds.openstack.swift.SwiftApiMetadata$Builder.<init>(SwiftApiMetadata.java:81)
    at org.jclouds.openstack.swift.SwiftApiMetadata$ConcreteBuilder.<init>(SwiftApiMetadata.java:108)
    at org.jclouds.openstack.swift.SwiftApiMetadata$ConcreteBuilder.<init>(SwiftApiMetadata.java:108)
    at org.jclouds.openstack.swift.SwiftApiMetadata.<init>(SwiftApiMetadata.java:60)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at java.lang.Class.newInstance(Class.java:374)
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:373)
    ... 16 more

Any ideas as to what is going on here? 关于这里发生了什么的任何想法?

You will need the following, in order to be able to bootstrap your VM: 您将需要以下内容,以便能够引导您的VM:

  • The ip address of the VM. VM的IP地址。 It must be reachable, have the port 22 open (as the bootstrap will be done via SSH) and have access to the Internet so it can install Ruby and Chef. 它必须是可访问的,端口22打开(因为引导程序将通过SSH完成)并且可以访问Internet以便它可以安装Ruby和Chef。
  • A client in the Chef Server and its corresponding private key. Chef Server中的客户端及其对应的私钥。 That client is used by jclouds to perform the operations against the Chef Server REST API. jclouds使用该客户端来执行针对Chef Server REST API的操作。
  • The validator certificate. 验证者证书。 That certificate will be uploaded to the node so it can self-register in the Chef Server. 该证书将上传到节点,以便它可以在Chef服务器中自行注册。

In this case, as the jclouds ComputeService is not being used, you'll have to manually instantiate an SSH client to connect to the virtual machine, but it should be pretty straightforward. 在这种情况下,由于未使用jclouds ComputeService,您必须手动实例化SSH客户端以连接到虚拟机,但它应该非常简单。

In the example you mention, the Git repo is cloned when using ChefSolo, but since you have a Chef Server the only thing you need to do is to configure the connection and the desired run list and attributes. 在您提到的示例中,使用ChefSolo时会克隆Git存储库,但由于您拥有Chef服务器,因此您唯一需要做的就是配置连接以及所需的运行列表和属性。

A minimal program to do that would require the following dependencies: 执行此操作的最小程序将需要以下依赖项:

<!-- Required 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>

And it could be something like the following: 它可能类似于以下内容:

Update: I've changed the configuration to match the provided knife.rb configuration, and also added a couple properties to avoid SSL errors, as your Chef endpoint is https. 更新:我已更改配置以匹配提供的knife.rb配置,并且还添加了一些属性以避免SSL错误,因为Chef端点为https。

// Configuration
String vmIp = "vm-ip";
String vmSshUsername = "root";
String vmSshPassword = "foo";

String endpoint = "https://mychefserver.example.com";
String client = "myuser";
String validator = "chef-validator";
String clientCredential = Files.toString(new File("/home/myuser/.chef/myuser.pem"), Charsets.UTF_8);
String validatorCredential = Files.toString(new File("/home/myuser/.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");

/* *** First, create the context to connect to the Chef Server *** */

// Create the context and configure the SSH driver to use. sshj in this example
ChefContext ctx = ContextBuilder.newBuilder("chef")
    .endpoint(endpoint)
    .credentials(client, clientCredential)
    .overrides(props)
    .modules(ImmutableSet.of(new SshjSshClientModule())) //
    .buildView(ChefContext.class);
CherService chef = ctx.getChefService();

/* *** Second, generate the bootstrap script *** */

// Generate the bootsrap configuration
List<String> runlist = new RunListBuilder().addRole("typicalapp").build();
BootstrapConfig bootstrapConfig = BootstrapConfig.builder().runlist(runlist).build();

// Generate the bootstrap script to be executed in the VM (this will persist
// the configuration in a data bag under the key 'jclouds-chef' so it can be reused
// and then build the bootstrap script with the information in the configuration data bag)
chef.updateBootstrapConfigForGroup("jclouds-chef", bootstrapConfig);
Statement bootstrap = chef.createBootstrapScriptForGroup("jclouds-chef");

/* *** Finally create an SSH connection manually and run the script on the VM *** */

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();
try {
    String rawScript = bootstrap.render(OsFamily.UNIX);
    ExecResponse result = ssh.exec(rawScript);
} finally {
    ssh.disconnect();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM