2014-07-16 27 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相同。 –

相關問題