I am using the excellent JClouds-Chef API to bootstrap and configure VMs in our datacenter.
I have the following code:
String appName = "myapp";
String myRole = "my_app";
String chefGroup = "fizzbuzz";
String endpoint = "https://mychefserver";
String client = "myuser";
String validator = "chef-validator";
String clientCredential = Files.toString(new File("/etc/chef/myuser.pem"), Charsets.UTF_8);
String validatorCredential = Files.toString(new File("/etc/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);
ChefApi api = ctx.unwrapApi(ChefApi.class);
// ChefEnvironmentProvider is a custom class that builds environments.
ChefEnvironmentProvider environmentProvider = new ChefEnvironmentProvider(appName);
Environment devEnv = environmentProvider.provideEnvironment("dev");
Environment testEnv = environmentProvider.provideEnvironment("test");
api.createEnvironment(devEnv);
api.createEnvironment(testEnv);
List<String> runlist = new RunListBuilder().addRole(myRole).build();
// BootstrapConfig bootstrapConfig = BootstrapConfig.builder().environment(devEnv).runList(runlist).build();
BootstrapConfig bootstrapConfig = BootstrapConfig.builder().runList(runlist).build();
String vmIp = "myapp01.example.com";
String vmSshUsername = "myuser";
String vmSshPassword = "12345";
ChefService chef = ctx.getChefService();
chef.updateBootstrapConfigForGroup(chefGroup, bootstrapConfig);
Statement bootstrap = chef.createBootstrapScriptForGroup(chefGroup);
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 {
StringBuilder rawScript = new StringBuilder();
Map<String, String> resolvedFunctions = ScriptBuilder.resolveFunctionDependenciesForStatements(
new HashMap<String, String>(), ImmutableSet.of(bootstrap), OsFamily.UNIX);
ScriptBuilder.writeFunctions(resolvedFunctions, OsFamily.UNIX, rawScript)
rawScript.append(bootstrap.render(OsFamily.UNIX));
ssh.put("/tmp/chef-bootstrap.sh", rawScript.toString());
ExecResponse result = ssh.exec("sudo bash /tmp/chef-bootstrap.sh");
} catch(Throwable t) {
log.error(t.message);
} finally {
ssh.disconnect();
}
When I run this code, I get no exceptions, however if I go into http://mychefserver
and look at the node, I see it's Run List and Recipes are empty. In other words, even though I specifically add a role to the runlist, it doesn't seem to be adding things on the chef server side.
What could be going on here?
Does the role exist in the Chef Server?
Like the environments, it must exist. If not, you'll have to create it first using the ChefApi
in a similar way you are creating the environments.
If the role already exists, check the output of the script executed in the VM and see if it contains errors.