Merge pull request #75 from jsonking/master

Issue 158: Changes to support shutting down a virtual guest. Improved price from item function
This commit is contained in:
Adrian Cole 2011-09-20 15:49:22 -07:00
commit 6f01848608
10 changed files with 204 additions and 59 deletions

View File

@ -1,46 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.compute.functions;
import com.google.common.base.Function;
import org.jclouds.softlayer.domain.ProductItem;
import org.jclouds.softlayer.domain.ProductItemPrice;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Returns the ProductItemPrice for the ProductItem.
* @author Jason King
*/
public class ProductItemPriceFromProductItem implements Function<ProductItem,ProductItemPrice> {
/**
*
* @param productItem the productItem to use
* @return the productItemPrice
* @throws java.util.NoSuchElementException if not only 1 price
*/
@Override
public ProductItemPrice apply(ProductItem productItem) {
Set<ProductItemPrice> prices = productItem.getPrices();
if(prices.size()!=1) throw new NoSuchElementException();
return prices.iterator().next();
}
}

View File

@ -19,7 +19,11 @@
package org.jclouds.softlayer.compute.functions;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import org.jclouds.softlayer.domain.ProductItem;
import org.jclouds.softlayer.domain.ProductItemPrice;
import java.util.NoSuchElementException;
public class ProductItems {
@ -46,4 +50,19 @@ public class ProductItems {
}
};
}
/**
* Creates a function to get the ProductItemPrice for the ProductItem.
* Currently returns the first price.
* This will need to be changed if more than one price is returned.
*/
public static Function<ProductItem,ProductItemPrice> price() {
return new Function<ProductItem,ProductItemPrice>() {
@Override
public ProductItemPrice apply(ProductItem productItem) {
if(productItem.getPrices().size()<1) throw new NoSuchElementException("ProductItem has no prices:"+productItem);
return Iterables.get(productItem.getPrices(), 0);
}
};
}
}

View File

@ -0,0 +1,101 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.emptyToNull;
/**
*
* @author Jason King
* @see <a href= "http://sldn.softlayer.com/reference/datatypes/SoftLayer_Billing_Item_Virtual_Guest"
* />
*/
public class BillingItemVirtualGuest implements Comparable<BillingItemVirtualGuest> {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private long id = -1;
public Builder id(long id) {
this.id = id;
return this;
}
public static Builder fromBillingItemVirtualGuest(BillingItemVirtualGuest in) {
return BillingItemVirtualGuest.builder().id(in.getId());
}
}
private long id = -1;
// for deserializer
BillingItemVirtualGuest() {
}
public BillingItemVirtualGuest(long id) {
this.id = id;
}
@Override
public int compareTo(BillingItemVirtualGuest arg0) {
return new Long(id).compareTo(arg0.getId());
}
/**
* @return The unique identifier for this billing item.
*/
public long getId() {
return id;
}
public Builder toBuilder() {
return Builder.fromBillingItemVirtualGuest(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BillingItemVirtualGuest other = (BillingItemVirtualGuest) obj;
if (id != other.id)
return false;
return true;
}
@Override
public String toString() {
return "[id=" + id + "]";
}
}

View File

@ -86,6 +86,8 @@ public class VirtualGuest implements Comparable<VirtualGuest> {
private String primaryBackendIpAddress;
private String primaryIpAddress;
private BillingItemVirtualGuest billingItem;
// for deserializer
VirtualGuest() {
@ -95,7 +97,7 @@ public class VirtualGuest implements Comparable<VirtualGuest> {
String fullyQualifiedDomainName, String hostname, long id, Date lastVerifiedDate, int maxCpu,
String maxCpuUnits, int maxMemory, Date metricPollDate, Date modifyDate, String notes,
boolean privateNetworkOnly, int startCpus, int statusId, String uuid, String primaryBackendIpAddress,
String primaryIpAddress) {
String primaryIpAddress,BillingItemVirtualGuest billingItem) {
this.accountId = accountId;
this.createDate = createDate;
this.dedicatedAccountHostOnly = dedicatedAccountHostOnly;
@ -116,6 +118,7 @@ public class VirtualGuest implements Comparable<VirtualGuest> {
this.uuid = uuid;
this.primaryBackendIpAddress = primaryBackendIpAddress;
this.primaryIpAddress = primaryIpAddress;
this.billingItem = billingItem;
}
@Override
@ -266,6 +269,13 @@ public class VirtualGuest implements Comparable<VirtualGuest> {
return primaryIpAddress;
}
/**
* @return The billing item for a CloudLayer Compute Instance.
*/
public BillingItemVirtualGuest getBillingItem() {
return billingItem;
}
@Override
public int hashCode() {
final int prime = 31;
@ -290,6 +300,7 @@ public class VirtualGuest implements Comparable<VirtualGuest> {
result = prime * result + startCpus;
result = prime * result + statusId;
result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
result = prime * result + ((billingItem == null) ? 0 : billingItem.hashCode());
return result;
}
@ -378,6 +389,8 @@ public class VirtualGuest implements Comparable<VirtualGuest> {
return false;
} else if (!uuid.equals(other.uuid))
return false;
if (!billingItem.equals(other.billingItem))
return false;
return true;
}

View File

@ -48,7 +48,7 @@ import com.google.common.util.concurrent.ListenableFuture;
@RequestFilters(BasicAuthentication.class)
@Path("/v{jclouds.api-version}")
public interface VirtualGuestAsyncClient {
public static String GUEST_MASK = "powerState;networkVlans;operatingSystem.passwords;datacenter";
public static String GUEST_MASK = "powerState;networkVlans;operatingSystem.passwords;datacenter;virtualGuests.billingItem";
/**
* @see VirtualGuestClient#listVirtualGuests
@ -114,4 +114,13 @@ public interface VirtualGuestAsyncClient {
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> resumeVirtualGuest(@PathParam("id") long id);
/**
* @see VirtualGuestClient#cancelService
*/
@GET
@Path("/SoftLayer_Billing_Item/{id}/cancelService.json")
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Boolean> cancelService(@PathParam("id") long id);
}

View File

@ -88,4 +88,14 @@ public interface VirtualGuestClient {
* id of the virtual guest
*/
void resumeVirtualGuest(long id);
/**
* Cancel the resource or service for a billing Item
*
* @param id
* The id of the billing item to cancel
* @return true or false
*/
boolean cancelService(long id);
}

View File

@ -18,12 +18,17 @@
*/
package org.jclouds.softlayer.compute.functions;
import com.google.common.collect.ImmutableSet;
import org.jclouds.softlayer.domain.ProductItem;
import org.jclouds.softlayer.domain.ProductItemPrice;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.NoSuchElementException;
import static org.jclouds.softlayer.compute.functions.ProductItems.capacity;
import static org.jclouds.softlayer.compute.functions.ProductItems.description;
import static org.jclouds.softlayer.compute.functions.ProductItems.price;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
@ -35,11 +40,19 @@ import static org.testng.Assert.assertNull;
@Test(groups = "unit")
public class ProductItemsTest {
private ProductItemPrice price;
private ProductItem item;
@BeforeMethod
public void setup() {
item = ProductItem.builder().id(1).capacity(2.0f).description("an item").build();
price = ProductItemPrice.builder().id(1).build();
item = ProductItem.builder().id(1)
.capacity(2.0f)
.description("an item")
.price(price)
.build();
}
@Test
public void testCapacity() {
@ -57,8 +70,27 @@ public class ProductItemsTest {
assertEquals(description().apply(item),"an item");
}
@Test
public void testDescriptionMissing() {
ProductItem item = ProductItem.builder().id(1).build();
assertNull(description().apply(item));
}
@Test
public void testPrice() {
assertEquals(price().apply(item),price);
}
@Test
public void testPriceMultiplePrices() {
ImmutableSet<ProductItemPrice> prices = ImmutableSet.of(price, ProductItemPrice.builder().id(2).build());
ProductItem item2 = ProductItem.builder().prices(prices).build();
assertEquals(price().apply(item2),price);
}
@Test(expectedExceptions = NoSuchElementException.class)
public void testPriceMissing() {
ProductItem noPriceItem = ProductItem.builder().id(1).build();
price().apply(noPriceItem);
}
}

View File

@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.jclouds.softlayer.compute.functions.ProductItemPriceFromProductItem;
import org.jclouds.softlayer.compute.functions.ProductItems;
import org.jclouds.softlayer.domain.*;
import org.jclouds.softlayer.reference.SoftLayerConstants;
@ -119,7 +118,7 @@ public class ProductPackageClientLiveTest extends BaseSoftLayerClientLiveTest {
// capacity is key in GB (1Gb = 1.0f)
Map<Float, ProductItem> ramToProductItem = Maps.uniqueIndex(ramItems, ProductItems.capacity());
ProductItemPrice price = new ProductItemPriceFromProductItem().apply(ramToProductItem.get(1.0f));
ProductItemPrice price = ProductItems.price().apply(ramToProductItem.get(1.0f));
assert new Long(1644L).equals(price.getId());
}
@ -131,7 +130,7 @@ public class ProductPackageClientLiveTest extends BaseSoftLayerClientLiveTest {
// number of cores is the key
Map<Float, ProductItem> coresToProductItem = Maps.uniqueIndex(cpuItems, ProductItems.capacity());
ProductItemPrice price = new ProductItemPriceFromProductItem().apply(coresToProductItem.get(2.0f));
ProductItemPrice price = ProductItems.price().apply(coresToProductItem.get(2.0f));
assert new Long(1963L).equals(price.getId());
}
@ -141,7 +140,7 @@ public class ProductPackageClientLiveTest extends BaseSoftLayerClientLiveTest {
Map<String, ProductItem> osToProductItem = Maps.uniqueIndex(operatingSystems, ProductItems.description());
ProductItemPrice price = new ProductItemPriceFromProductItem().apply(osToProductItem.get("Ubuntu Linux 8 LTS Hardy Heron - Minimal Install (64 bit)"));
ProductItemPrice price = ProductItems.price().apply(osToProductItem.get("Ubuntu Linux 8 LTS Hardy Heron - Minimal Install (64 bit)"));
assert new Long(1693L).equals(price.getId());
}
@ -152,16 +151,16 @@ public class ProductPackageClientLiveTest extends BaseSoftLayerClientLiveTest {
Map<Float, ProductItem> ramToProductItem = Maps.uniqueIndex(ramItems, ProductItems.capacity());
ProductItemPrice ramPrice = new ProductItemPriceFromProductItem().apply(ramToProductItem.get(1.0f));
ProductItemPrice ramPrice = ProductItems.price().apply(ramToProductItem.get(1.0f));
Iterable<ProductItem> cpuItems = Iterables.filter(cloudServerProductPackage.getItems(), Predicates.and(units("PRIVATE_CORE"), capacity(2.0f)));
Map<Float, ProductItem> coresToProductItem = Maps.uniqueIndex(cpuItems, ProductItems.capacity());
ProductItemPrice cpuPrice = new ProductItemPriceFromProductItem().apply(coresToProductItem.get(2.0f));
ProductItemPrice cpuPrice = ProductItems.price().apply(coresToProductItem.get(2.0f));
Iterable<ProductItem> operatingSystems = Iterables.filter(cloudServerProductPackage.getItems(), categoryCode("os"));
Map<String, ProductItem> osToProductItem = Maps.uniqueIndex(operatingSystems, ProductItems.description());
ProductItemPrice osPrice = new ProductItemPriceFromProductItem().apply(osToProductItem.get("Ubuntu Linux 8 LTS Hardy Heron - Minimal Install (64 bit)"));
ProductItemPrice osPrice = ProductItems.price().apply(osToProductItem.get("Ubuntu Linux 8 LTS Hardy Heron - Minimal Install (64 bit)"));
Set<Long> prices = Sets.<Long>newLinkedHashSet();
prices.addAll(SoftLayerConstants.DEFAULT_VIRTUAL_GUEST_PRICES);

View File

@ -47,7 +47,7 @@ public class VirtualGuestAsyncClientTest extends BaseSoftLayerAsyncClientTest<Vi
assertRequestLineEquals(
httpRequest,
"GET https://api.softlayer.com/rest/v3/SoftLayer_Account/VirtualGuests.json?objectMask=powerState%3BnetworkVlans%3BoperatingSystem.passwords%3Bdatacenter HTTP/1.1");
"GET https://api.softlayer.com/rest/v3/SoftLayer_Account/VirtualGuests.json?objectMask=powerState%3BnetworkVlans%3BoperatingSystem.passwords%3Bdatacenter%3BvirtualGuests.billingItem HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
@ -57,7 +57,7 @@ public class VirtualGuestAsyncClientTest extends BaseSoftLayerAsyncClientTest<Vi
assertRequestLineEquals(
httpRequest,
"GET https://api.softlayer.com/rest/v3/SoftLayer_Account/VirtualGuests.json?objectMask=powerState%3BnetworkVlans%3BoperatingSystem.passwords%3Bdatacenter HTTP/1.1");
"GET https://api.softlayer.com/rest/v3/SoftLayer_Account/VirtualGuests.json?objectMask=powerState%3BnetworkVlans%3BoperatingSystem.passwords%3Bdatacenter%3BvirtualGuests.billingItem HTTP/1.1");
// for example, using basic authentication, we should get "only one"
// header
assertNonPayloadHeadersEqual(httpRequest,
@ -78,7 +78,7 @@ public class VirtualGuestAsyncClientTest extends BaseSoftLayerAsyncClientTest<Vi
assertRequestLineEquals(
httpRequest,
"GET https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest/1234.json?objectMask=powerState%3BnetworkVlans%3BoperatingSystem.passwords%3Bdatacenter HTTP/1.1");
"GET https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest/1234.json?objectMask=powerState%3BnetworkVlans%3BoperatingSystem.passwords%3Bdatacenter%3BvirtualGuests.billingItem HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);

View File

@ -23,6 +23,7 @@ import static org.testng.Assert.assertTrue;
import java.util.Set;
import org.jclouds.softlayer.domain.BillingItemVirtualGuest;
import org.jclouds.softlayer.domain.VirtualGuest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
@ -71,6 +72,13 @@ public class VirtualGuestClientLiveTest extends BaseSoftLayerClientLiveTest {
assert vg.getUuid() != null : vg;
assert vg.getPrimaryBackendIpAddress() != null : vg;
assert vg.getPrimaryIpAddress() != null : vg;
checkBillingItem(vg.getBillingItem());
}
private void checkBillingItem(BillingItemVirtualGuest billingItem) {
assert null != billingItem;
assert billingItem.getId() > 0 : billingItem;
}
}