fix issue #1277 some nova installs do not generate passwords

This commit is contained in:
adriancole 2013-01-31 13:56:39 -08:00
parent bdc2fb3a1e
commit e85b7b7cc8
4 changed files with 112 additions and 46 deletions

View File

@ -130,8 +130,8 @@ public class NovaComputeServiceAdapter implements
logger.trace("<< server(%s)", server.getId()); logger.trace("<< server(%s)", server.getId());
ServerInZone serverInZone = new ServerInZone(server, zoneId); ServerInZone serverInZone = new ServerInZone(server, zoneId);
if (!privateKey.isPresent()) if (!privateKey.isPresent() && lightweightServer.getAdminPass().isPresent())
credentialsBuilder.password(lightweightServer.getAdminPass()); credentialsBuilder.password(lightweightServer.getAdminPass().get());
return new NodeAndInitialCredentials<ServerInZone>(serverInZone, serverInZone.slashEncode(), credentialsBuilder return new NodeAndInitialCredentials<ServerInZone>(serverInZone, serverInZone.slashEncode(), credentialsBuilder
.build()); .build());
} }

View File

@ -18,8 +18,6 @@
*/ */
package org.jclouds.openstack.nova.v2_0.domain; package org.jclouds.openstack.nova.v2_0.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.beans.ConstructorProperties; import java.beans.ConstructorProperties;
import java.util.Set; import java.util.Set;
@ -29,6 +27,7 @@ import org.jclouds.openstack.v2_0.domain.Resource;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Optional;
/** /**
* Server Resource with administrative password returned by ServerApi#CreateServer calls * Server Resource with administrative password returned by ServerApi#CreateServer calls
@ -40,21 +39,21 @@ import com.google.common.base.Objects.ToStringHelper;
*/ */
public class ServerCreated extends Resource { public class ServerCreated extends Resource {
public static Builder<?> builder() { public static Builder builder() {
return new ConcreteBuilder(); return new Builder();
} }
public Builder<?> toBuilder() { public Builder toBuilder() {
return new ConcreteBuilder().fromServerCreated(this); return builder().fromServerCreated(this);
} }
public abstract static class Builder<T extends Builder<T>> extends Resource.Builder<T> { public final static class Builder extends Resource.Builder<Builder> {
protected String adminPass; protected String adminPass;
/** /**
* @see ServerCreated#getAdminPass() * @see ServerCreated#getAdminPass()
*/ */
public T adminPass(String adminPass) { public Builder adminPass(String adminPass) {
this.adminPass = adminPass; this.adminPass = adminPass;
return self(); return self();
} }
@ -63,33 +62,30 @@ public class ServerCreated extends Resource {
return new ServerCreated(id, name, links, adminPass); return new ServerCreated(id, name, links, adminPass);
} }
public T fromServerCreated(ServerCreated in) { public Builder fromServerCreated(ServerCreated in) {
return super.fromResource(in) return super.fromResource(in).adminPass(in.getAdminPass().orNull());
.adminPass(in.getAdminPass());
} }
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override @Override
protected ConcreteBuilder self() { protected Builder self() {
return this; return this;
} }
} }
private final String adminPass; private final Optional<String> adminPass;
@ConstructorProperties({ @ConstructorProperties({
"id", "name", "links", "adminPass" "id", "name", "links", "adminPass"
}) })
protected ServerCreated(String id, @Nullable String name, Set<Link> links, String adminPass) { protected ServerCreated(String id, @Nullable String name, Set<Link> links, @Nullable String adminPass) {
super(id, name, links); super(id, name, links);
this.adminPass = checkNotNull(adminPass, "adminPass"); this.adminPass = Optional.fromNullable(adminPass);
} }
/** /**
* @return the administrative password for this server. Note: this is not available in Server responses. * present unless the nova install was configured with the option {@code enable_instance_password=false}
*/ */
public String getAdminPass() { public Optional<String> getAdminPass() {
return this.adminPass; return this.adminPass;
} }
@ -105,10 +101,9 @@ public class ServerCreated extends Resource {
ServerCreated that = ServerCreated.class.cast(obj); ServerCreated that = ServerCreated.class.cast(obj);
return super.equals(that) && Objects.equal(this.adminPass, that.adminPass); return super.equals(that) && Objects.equal(this.adminPass, that.adminPass);
} }
@Override
protected ToStringHelper string() { protected ToStringHelper string() {
return super.string() return super.string().add("adminPass", adminPass.orNull());
.add("adminPass", adminPass);
} }
} }

View File

@ -20,6 +20,7 @@ package org.jclouds.openstack.nova.v2_0.compute;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -51,6 +52,15 @@ import com.google.inject.TypeLiteral;
*/ */
@Test(groups = "unit", testName = "NovaComputeServiceAdapterExpectTest") @Test(groups = "unit", testName = "NovaComputeServiceAdapterExpectTest")
public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceContextExpectTest<Injector> { public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceContextExpectTest<Injector> {
HttpRequest serverDetail = HttpRequest
.builder()
.method("GET")
.endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/71752")
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken).build();
HttpResponse serverDetailResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/server_details.json")).build();
public void testCreateNodeWithGroupEncodedIntoNameWhenSecurityGroupsArePresent() throws Exception { public void testCreateNodeWithGroupEncodedIntoNameWhenSecurityGroupsArePresent() throws Exception {
@ -67,16 +77,6 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted") HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
.payload(payloadFromResourceWithContentType("/new_server.json","application/json; charset=UTF-8")).build(); .payload(payloadFromResourceWithContentType("/new_server.json","application/json; charset=UTF-8")).build();
HttpRequest serverDetail = HttpRequest
.builder()
.method("GET")
.endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/71752")
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken).build();
HttpResponse serverDetailResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/server_details.json")).build();
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder() Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess) .put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
.put(extensionsOfNovaRequest, extensionsOfNovaResponse) .put(extensionsOfNovaRequest, extensionsOfNovaResponse)
@ -117,17 +117,7 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted") HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
.payload(payloadFromResourceWithContentType("/new_server.json","application/json; charset=UTF-8")).build(); .payload(payloadFromResourceWithContentType("/new_server_no_adminpass.json","application/json; charset=UTF-8")).build();
HttpRequest serverDetail = HttpRequest
.builder()
.method("GET")
.endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/71752")
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken).build();
HttpResponse serverDetailResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/server_details.json")).build();
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder() Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess) .put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
@ -156,6 +146,47 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
assertNotNull(server); assertNotNull(server);
assertEquals(server.getCredentials(), LoginCredentials.builder().privateKey("privateKey").build()); assertEquals(server.getCredentials(), LoginCredentials.builder().privateKey("privateKey").build());
} }
/**
* When enable_instance_password is false, then no admin pass is generated.
* However in this case if you don't specify the name of the SSH keypair to
* inject, then you simply cannot log in to the server.
*/
public void testNoKeyPairOrAdminPass() throws Exception {
HttpRequest createServer = HttpRequest
.builder()
.method("POST")
.endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers")
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken)
.payload(payloadFromStringWithContentType(
"{\"server\":{\"name\":\"test-e92\",\"imageRef\":\"1241\",\"flavorRef\":\"100\"}}","application/json"))
.build();
HttpResponse createServerResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
.payload(payloadFromResourceWithContentType("/new_server_no_adminpass.json","application/json; charset=UTF-8")).build();
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
.put(extensionsOfNovaRequest, extensionsOfNovaResponse)
.put(listDetail, listDetailResponse)
.put(listFlavorsDetail, listFlavorsDetailResponse)
.put(createServer, createServerResponse)
.put(serverDetail, serverDetailResponse).build();
Injector forSecurityGroups = requestsSendResponses(requestResponseMap);
Template template = forSecurityGroups.getInstance(TemplateBuilder.class).build();
NovaComputeServiceAdapter adapter = forSecurityGroups.getInstance(NovaComputeServiceAdapter.class);
NodeAndInitialCredentials<ServerInZone> server = adapter.createNodeWithGroupEncodedIntoName("test", "test-e92",
template);
assertNotNull(server);
assertNull(server.getCredentials());
}
@Override @Override
public Injector apply(ComputeServiceContext input) { public Injector apply(ComputeServiceContext input) {

View File

@ -0,0 +1,40 @@
{
"server": {
"status": "BUILD(scheduling)",
"updated": "2012-03-19T06:21:13Z",
"hostId": "",
"user_id": "54297837463082",
"name": "test-e92",
"links": [{
"href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/servers/71752",
"rel": "self"
}, {
"href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/servers/71752",
"rel": "bookmark"
}],
"addresses": {},
"tenant_id": "37936628937291",
"image": {
"id": "1241",
"links": [{
"href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/images/1241",
"rel": "bookmark"
}]
},
"created": "2012-03-19T06:21:13Z",
"uuid": "47491020-6a78-4f63-9475-23195ac4515c",
"accessIPv4": "",
"accessIPv6": "",
"key_name": null,
"flavor": {
"id": "100",
"links": [{
"href": "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/flavors/100",
"rel": "bookmark"
}]
},
"config_drive": "",
"id": 71752,
"metadata": {}
}
}