我使用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();
}
}
}
当我跑步时,我得到:
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
关于这里发生了什么的任何想法?
答案 0 :(得分:3)
为了能够引导您的VM,您将需要以下内容:
在这种情况下,由于未使用jclouds ComputeService,您必须手动实例化SSH客户端以连接到虚拟机,但它应该非常简单。
在您提到的示例中,使用ChefSolo时会克隆Git仓库,但由于您拥有Chef服务器,因此您唯一需要做的就是配置连接以及所需的运行列表和属性。
执行此操作的最小程序需要以下依赖项:
<!-- 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();
}