mirror of https://github.com/apache/jclouds.git
Implement setting and retrieving the notes property on Softlayer machines
This commit is contained in:
parent
8cdba226af
commit
06f1b13200
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jclouds.softlayer.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Converts a String into a json string for changing the notes property of an instance
|
||||
* The string is set into the payload of the HttpRequest
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class NotesToJson implements Binder {
|
||||
|
||||
private final Json json;
|
||||
|
||||
@Inject
|
||||
NotesToJson(Json json) {
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
|
||||
checkArgument(input instanceof String);
|
||||
String notes = (String)input;
|
||||
request.setPayload(buildJson(notes));
|
||||
return request;
|
||||
}
|
||||
|
||||
private String buildJson(String notes) {
|
||||
return json.toJson(ImmutableMap.of("parameters", ImmutableList.of(ImmutableMap.of("notes", notes))));
|
||||
}
|
||||
|
||||
}
|
|
@ -25,14 +25,15 @@ import static com.google.common.collect.Iterables.get;
|
|||
import static com.google.common.collect.Iterables.tryFind;
|
||||
import static java.lang.Math.round;
|
||||
import static java.lang.String.format;
|
||||
import static org.jclouds.compute.domain.Volume.Type;
|
||||
import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
|
||||
import static org.jclouds.compute.util.ComputeServiceUtils.getSpace;
|
||||
import static org.jclouds.softlayer.reference.SoftLayerConstants.PROPERTY_SOFTLAYER_VIRTUALGUEST_ACTIVE_TRANSACTIONS_DELAY;
|
||||
import static org.jclouds.softlayer.reference.SoftLayerConstants.PROPERTY_SOFTLAYER_VIRTUALGUEST_LOGIN_DETAILS_DELAY;
|
||||
import static org.jclouds.util.Predicates2.retry;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -48,6 +49,7 @@ import org.jclouds.compute.domain.HardwareBuilder;
|
|||
import org.jclouds.compute.domain.Processor;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.compute.domain.Volume;
|
||||
import org.jclouds.compute.domain.Volume.Type;
|
||||
import org.jclouds.compute.domain.internal.VolumeImpl;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.domain.LoginCredentials;
|
||||
|
@ -75,6 +77,7 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
|
@ -92,6 +95,8 @@ import com.google.common.collect.Sets;
|
|||
public class SoftLayerComputeServiceAdapter implements
|
||||
ComputeServiceAdapter<VirtualGuest, Hardware, OperatingSystem, Datacenter> {
|
||||
|
||||
private static final String USER_META_NOTES = "notes";
|
||||
private static final int USER_META_NOTES_MAX_LENGTH = 1000;
|
||||
private static final String BOOTABLE_DEVICE = "0";
|
||||
public static final String DEFAULT_DISK_TYPE = "LOCAL";
|
||||
public static final int DEFAULT_MAX_PORT_SPEED = 100;
|
||||
|
@ -137,8 +142,9 @@ public class SoftLayerComputeServiceAdapter implements
|
|||
final Datacenter datacenter = Datacenter.builder().name(template.getLocation().getId()).build();
|
||||
final String imageId = template.getImage().getId();
|
||||
int cores = (int) template.getHardware().getProcessors().get(0).getCores();
|
||||
String notes = getNotes(templateOptions);
|
||||
|
||||
VirtualGuest.Builder virtualGuestBuilder = VirtualGuest.builder()
|
||||
VirtualGuest.Builder<?> virtualGuestBuilder = VirtualGuest.builder()
|
||||
.domain(domainName)
|
||||
.hostname(name)
|
||||
.hourlyBillingFlag(hourlyBillingFlag)
|
||||
|
@ -213,6 +219,11 @@ public class SoftLayerComputeServiceAdapter implements
|
|||
api.getVirtualGuestApi().setTags(result.getId(), templateOptions.getTags());
|
||||
}
|
||||
|
||||
// notes
|
||||
if (!Strings.isNullOrEmpty(notes)) {
|
||||
api.getVirtualGuestApi().setNotes(result.getId(), notes);
|
||||
}
|
||||
|
||||
logger.debug(">> awaiting login details for virtualGuest(%s)", result.getId());
|
||||
boolean orderInSystem = loginDetailsTester.apply(result);
|
||||
logger.trace("<< VirtualGuest(%s) complete(%s)", result.getId(), orderInSystem);
|
||||
|
@ -227,10 +238,22 @@ public class SoftLayerComputeServiceAdapter implements
|
|||
}
|
||||
result = api.getVirtualGuestApi().getVirtualGuest(result.getId());
|
||||
Password pwd = get(result.getOperatingSystem().getPasswords(), 0);
|
||||
return new NodeAndInitialCredentials(result, result.getId() + "",
|
||||
return new NodeAndInitialCredentials<VirtualGuest>(result, result.getId() + "",
|
||||
LoginCredentials.builder().user(pwd.getUsername()).password(pwd.getPassword()).build());
|
||||
}
|
||||
|
||||
private String getNotes(SoftLayerTemplateOptions templateOptions) {
|
||||
String notes = null;
|
||||
Map<String, String> meta = templateOptions.getUserMetadata();
|
||||
if (meta != null) {
|
||||
notes = meta.get(USER_META_NOTES);
|
||||
if (!Strings.isNullOrEmpty(notes)) {
|
||||
checkArgument(notes.length() <= USER_META_NOTES_MAX_LENGTH, "'notes' property in user metadata should be long at most " + USER_META_NOTES_MAX_LENGTH + " characters.");
|
||||
}
|
||||
}
|
||||
return notes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Hardware> listHardwareProfiles() {
|
||||
ContainerVirtualGuestConfiguration virtualGuestConfiguration = createObjectOptionsSupplier.get();
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.jclouds.rest.annotations.BinderParam;
|
|||
import org.jclouds.rest.annotations.Fallback;
|
||||
import org.jclouds.rest.annotations.QueryParams;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.softlayer.binders.NotesToJson;
|
||||
import org.jclouds.softlayer.binders.TagToJson;
|
||||
import org.jclouds.softlayer.binders.VirtualGuestToJson;
|
||||
import org.jclouds.softlayer.domain.ContainerVirtualGuestConfiguration;
|
||||
|
@ -53,6 +54,8 @@ public interface VirtualGuestApi {
|
|||
"statusId;operatingSystem.passwords;primaryBackendIpAddress;primaryIpAddress;activeTransactionCount;" +
|
||||
"blockDevices.diskImage;datacenter;tagReferences;privateNetworkOnlyFlag;sshKeys";
|
||||
|
||||
String NOTES_MASK = "id;notes";
|
||||
|
||||
/**
|
||||
* Enables the creation of computing instances on an account.
|
||||
* @param virtualGuest this data type presents the structure in which all virtual guests will be presented.
|
||||
|
@ -63,7 +66,6 @@ public interface VirtualGuestApi {
|
|||
@POST
|
||||
@Path("SoftLayer_Virtual_Guest")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Fallback(Fallbacks.NullOnNotFoundOr404.class)
|
||||
VirtualGuest createVirtualGuest(@BinderParam(VirtualGuestToJson.class) VirtualGuest virtualGuest);
|
||||
|
||||
/**
|
||||
|
@ -138,7 +140,7 @@ public interface VirtualGuestApi {
|
|||
void resumeVirtualGuest(@PathParam("id") long id);
|
||||
|
||||
/**
|
||||
* Resume the guest.
|
||||
* Set the tags on the instance
|
||||
*
|
||||
* @param id
|
||||
* id of the virtual guest
|
||||
|
@ -147,6 +149,34 @@ public interface VirtualGuestApi {
|
|||
@POST
|
||||
@Path("/SoftLayer_Virtual_Guest/{id}/setTags")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Fallback(Fallbacks.FalseOnNotFoundOr404.class)
|
||||
boolean setTags(@PathParam("id") long id, @BinderParam(TagToJson.class) Set<String> tags);
|
||||
|
||||
/**
|
||||
* Set notes (visible in UI)
|
||||
*
|
||||
* @param id id of the virtual guest
|
||||
* @param notes The notes property to set on the machine - visible in UI
|
||||
*/
|
||||
@Named("VirtualGuest:setNotes")
|
||||
@POST
|
||||
@Path("/SoftLayer_Virtual_Guest/{id}/editObject")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
boolean setNotes(@PathParam("id") long id, @BinderParam(NotesToJson.class) String notes);
|
||||
|
||||
/**
|
||||
* Get notes (visible in UI)
|
||||
*
|
||||
* Don't include it in default getObject mask as it can get quite big (up to 1000 chars).
|
||||
* Also no place to put it in NodeMetadata.
|
||||
*
|
||||
* @param id
|
||||
* id of the virtual guest
|
||||
*/
|
||||
@Named("VirtualGuest:getNotes")
|
||||
@GET
|
||||
@Path("/SoftLayer_Virtual_Guest/{id}/getObject")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@QueryParams(keys = "objectMask", values = NOTES_MASK)
|
||||
@Fallback(Fallbacks.NullOnNotFoundOr404.class)
|
||||
VirtualGuest getNotes(@PathParam("id") long id);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jclouds.softlayer.binders;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.json.internal.GsonWrapper;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
@Test(groups = "unit", testName = "NotesToJsonTest")
|
||||
public class NotesToJsonTest {
|
||||
|
||||
private Json json;
|
||||
|
||||
@BeforeClass
|
||||
public void init() {
|
||||
json = new GsonWrapper(new Gson());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVirtualGuestWithNotes() {
|
||||
HttpRequest request = HttpRequest.builder().method("POST").endpoint("https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest").build();
|
||||
NotesToJson binder = new NotesToJson(json);
|
||||
String notes = "some notes";
|
||||
|
||||
request = binder.bindToRequest(request, notes);
|
||||
|
||||
assertEquals(request.getPayload().getRawContent(), "{\"parameters\":[{\"notes\":\"some notes\"}]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVirtualGuestWithoutNotes() {
|
||||
HttpRequest request = HttpRequest.builder().method("POST").endpoint("https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest").build();
|
||||
NotesToJson binder = new NotesToJson(json);
|
||||
request = binder.bindToRequest(request, "");
|
||||
|
||||
assertEquals(request.getPayload().getRawContent(), "{\"parameters\":[{\"notes\":\"\"}]}");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testVirtualGuestNullNotes() {
|
||||
HttpRequest request = HttpRequest.builder().method("POST").endpoint("https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest").build();
|
||||
NotesToJson binder = new NotesToJson(json);
|
||||
binder.bindToRequest(request, null);
|
||||
}
|
||||
}
|
|
@ -85,21 +85,6 @@ public class VirtualGuestApiExpectTest extends BaseSoftLayerApiExpectTest {
|
|||
assertEquals(result, new CreateVirtualGuestResponseTest().expected());
|
||||
}
|
||||
|
||||
public void testCreateVirtualGuestWhenResponseIs4xx() {
|
||||
|
||||
HttpRequest createVirtualGuest = HttpRequest.builder().method("POST")
|
||||
.endpoint("https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest")
|
||||
.addHeader("Accept", "application/json")
|
||||
.addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
|
||||
.payload(payloadFromResourceWithContentType("/virtual_guest_create.json", MediaType.APPLICATION_JSON))
|
||||
.build();
|
||||
|
||||
HttpResponse createVirtualGuestResponse = HttpResponse.builder().statusCode(404).build();
|
||||
SoftLayerApi api = requestSendsResponse(createVirtualGuest, createVirtualGuestResponse);
|
||||
VirtualGuest virtualGuest = createVirtualGuest();
|
||||
assertNull(api.getVirtualGuestApi().createVirtualGuest(virtualGuest));
|
||||
}
|
||||
|
||||
public void testDeleteVirtualGuestWhenResponseIs2xx() {
|
||||
|
||||
HttpRequest deleteVirtualGuest = HttpRequest.builder().method("GET")
|
||||
|
@ -259,18 +244,20 @@ public class VirtualGuestApiExpectTest extends BaseSoftLayerApiExpectTest {
|
|||
assertTrue(api.getVirtualGuestApi().setTags(virtualGuest.getId(), ImmutableSet.of("test1", "test2", "test3")));
|
||||
}
|
||||
|
||||
public void testSetTagsOnVirtualGuestWhenResponseIs4xx() {
|
||||
public void testSetNotesOnVirtualGuestWhenResponseIs2xx() {
|
||||
|
||||
HttpRequest setTagsOnVirtualGuest = HttpRequest.builder().method("POST")
|
||||
.endpoint("https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest/1301396/setTags")
|
||||
HttpRequest setNodesOnVirtualGuest = HttpRequest.builder().method("POST")
|
||||
.endpoint("https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest/1301396/editObject")
|
||||
.addHeader("Accept", "application/json")
|
||||
.addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
|
||||
.payload(payloadFromResourceWithContentType("/virtual_guest_set_tags.json", MediaType.APPLICATION_JSON))
|
||||
.payload(payloadFromResourceWithContentType("/virtual_guest_set_notes.json", MediaType.APPLICATION_JSON))
|
||||
.build();
|
||||
|
||||
HttpResponse setTagsOnVirtualGuestResponse = HttpResponse.builder().statusCode(404).build();
|
||||
SoftLayerApi api = requestSendsResponse(setTagsOnVirtualGuest, setTagsOnVirtualGuestResponse);
|
||||
HttpResponse setNotesOnVirtualGuestResponse = HttpResponse.builder().statusCode(200)
|
||||
.payload("true").build();
|
||||
|
||||
SoftLayerApi api = requestSendsResponse(setNodesOnVirtualGuest, setNotesOnVirtualGuestResponse);
|
||||
VirtualGuest virtualGuest = createVirtualGuest();
|
||||
assertFalse(api.getVirtualGuestApi().setTags(virtualGuest.getId(), ImmutableSet.of("test1", "test2", "test3")));
|
||||
assertTrue(api.getVirtualGuestApi().setNotes(virtualGuest.getId(), "some notes"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.testng.annotations.BeforeClass;
|
|||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.inject.Injector;
|
||||
|
@ -125,6 +126,15 @@ public class VirtualGuestApiLiveTest extends BaseSoftLayerApiLiveTest {
|
|||
}
|
||||
|
||||
@Test(dependsOnMethods = "testSetTagsOnVirtualGuest")
|
||||
public void testSetNotesOnVirtualGuest() throws Exception {
|
||||
// Test with maximum allowed notes length - 1000 characters.
|
||||
String notes = Strings.padStart("", 1000, 'x');
|
||||
assertTrue(virtualGuestApi.setNotes(virtualGuest.getId(), notes));
|
||||
VirtualGuest found = virtualGuestApi.getNotes(virtualGuest.getId());
|
||||
assertEquals(found.getNotes(), notes);
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testSetNotesOnVirtualGuest")
|
||||
public void testPauseVirtualGuest() throws Exception {
|
||||
virtualGuestApi.pauseVirtualGuest(virtualGuest.getId());
|
||||
checkState(retry(new Predicate<VirtualGuest>() {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"parameters":[{"notes":"some notes"}]}
|
Loading…
Reference in New Issue