JClouds-Chef: IllegalAccessError on TokenType2?

守給你的承諾、 提交于 2019-12-24 12:25:06

问题


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:

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?


回答1:


You will need the following, in order to be able to bootstrap your VM:

  • The ip address of the VM. 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.
  • A client in the Chef Server and its corresponding private key. That client is used by jclouds to perform the operations against the Chef Server REST API.
  • The validator certificate. That certificate will be uploaded to the node so it can self-register in the Chef Server.

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.

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.

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.

// 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();
}


来源:https://stackoverflow.com/questions/24777085/jclouds-chef-illegalaccesserror-on-tokentype2

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!