2014-07-16 32 views
1

我使用JClouds-Chef API来引导一个Linux VM(myapp01.me.example.com)与厨师客户端,并再运行客户端,并通过typicalapp作用,其应用程序堆栈配置VM:JClouds-Chef:TokenType2上的IllegalAccessError?

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

当我运行这个我得到:

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 

有关这里发生了什么的任何想法?

回答

3

您将需要以下,为了能够引导您的VM:

  • 虚拟机的IP地址。它必须可以访问,打开端口22(因为引导程序将通过SSH完成)并且可以访问互联网,因此它可以安装Ruby和Chef。
  • 厨师服务器中的客户端及其对应的私钥。该客户机由jclouds用于对Chef Server REST API执行操作。
  • 验证器证书。该证书将被上传到节点,以便它可以在Chef Server中自行注册。

在这种情况下,由于未使用jclouds ComputeService,您必须手动实例化SSH客户端才能连接到虚拟机,但它应该非常简单。

在你提到的例子中,当使用ChefSolo时,Git repo被克隆,但由于你有一个Chef Server,所以你需要做的唯一事情就是配置连接和所需的运行列表和属性。

一个最小的程序要做到这一点就需要下面的依赖关系:

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

而且它可能是类似以下内容:

更新:我改变配置来匹配提供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(); 
} 
+0

真棒,真棒答案@Ignasi巴雷拉 - 的感谢和+1(我希望** **我可以更给予好评吧) - 几个简单的followups:(1)可'vmIp'是完全合格的域名我的虚拟机的名称(例如:myapp01.me.example.com),还是*有*作为VIP?如果*有*作为VIP,是否有用于解析VIP的JClouds-Chef API (2)我假设客户端是在我们的厨师服务器上注册的厨师客户端? – IAmYourFaja

+0

(3)我对“验证器”的概念并不熟悉 - 任何可以提供快速关于这些是什么,它们所服务的功能,以及我如何确定这个域的值(验证者的名字)应该是什么?再次感谢! – IAmYourFaja

+1

(1)您应该能够使用VM的FQDN,作为只要你运行jcl的DNS大声程序可以解决它。 (2)是的,客户端是必须存在于Chef Server中的客户端。厨师的客户是“api消费者”。 (3)验证器是所有Chef Server安装中的“特殊客户端”,knife-bootstrap用于在首次运行时注册Chef Server中的节点。 jclouds-chef的作用与knife-bootstrap相同。 –

相关问题