You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@jclouds.apache.org by Andrea Turli <no...@github.com> on 2017/01/10 10:13:28 UTC

[jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

- add ApiMetadata and ProviderMetadata
- add skeleton for PacketApi with ProjectApi only
- add XAuthTokenToRequest filter
- add HttpApiModule and ParserModule
- add ProjectApi feature with Mock and Live Tests
You can view, comment on, or merge this pull request online at:

  https://github.com/jclouds/jclouds-labs/pull/340

-- Commit Summary --

  * add ApiMetadata and ProviderMetadata

-- File Changes --

    A packet/src/main/java/org/jclouds/packet/PacketApi.java (40)
    A packet/src/main/java/org/jclouds/packet/PacketApiMetadata.java (85)
    A packet/src/main/java/org/jclouds/packet/PacketProviderMetadata.java (77)
    A packet/src/main/java/org/jclouds/packet/config/PacketComputeParserModule.java (30)
    A packet/src/main/java/org/jclouds/packet/config/PacketHttpApiModule.java (61)
    A packet/src/main/java/org/jclouds/packet/features/ProjectApi.java (47)
    A packet/src/main/java/org/jclouds/packet/filters/AddXAuthTokenToRequest.java (47)
    A packet/src/main/java/org/jclouds/packet/handlers/PacketErrorHandler.java (63)
    A packet/src/test/java/org/jclouds/packet/PacketProviderMetadataTest.java (29)
    A packet/src/test/java/org/jclouds/packet/compute/internal/BasePacketApiLiveTest.java (73)
    A packet/src/test/java/org/jclouds/packet/compute/internal/BasePacketApiMockTest.java (145)
    A packet/src/test/java/org/jclouds/packet/features/ProjectApiLiveTest.java (49)
    A packet/src/test/java/org/jclouds/packet/features/ProjectApiMockTest.java (54)
    A packet/src/test/resources/logback-test.xml (42)
    A packet/src/test/resources/projects.json (1)

-- Patch Links --

https://github.com/jclouds/jclouds-labs/pull/340.patch
https://github.com/jclouds/jclouds-labs/pull/340.diff

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
@nacx I'm adding pagination as well, agreed better sooner than later

re PublicKey I think it was a typo from my first PR, this provider is not using them in the domain objects.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340#issuecomment-271652378

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
andreaturli commented on this pull request.



> +      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseHttpApiMetadata.defaultProperties();
+      properties.put(TEMPLATE, "osFamily=UBUNTU,os64Bit=true,osVersionMatches=14.*");
+      properties.put(TIMEOUT_NODE_RUNNING, 300000); // 5 mins
+      return properties;
+   }
+
+   public static class Builder extends BaseHttpApiMetadata.Builder<PacketApi, Builder> {
+
+      protected Builder() {
+         id("packet")
+                 .name("Packet API")
+                 .identityName("We can use project Id")

it should simple say `project id`, agreed

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Ignasi Barrera <no...@github.com>.
nacx requested changes on this pull request.

Thanks @andreaturli! This looks like a great start.

Apart from the comments, we should add:

* Pagination
* The adapter for PublicKey.

> +   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   public PacketApiMetadata() {
+      this(new Builder());
+   }
+
+   protected PacketApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseHttpApiMetadata.defaultProperties();
+      properties.put(TEMPLATE, "osFamily=UBUNTU,os64Bit=true,osVersionMatches=14.*");

Ccan we default to a more modern version?

> +      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseHttpApiMetadata.defaultProperties();
+      properties.put(TEMPLATE, "osFamily=UBUNTU,os64Bit=true,osVersionMatches=14.*");
+      properties.put(TIMEOUT_NODE_RUNNING, 300000); // 5 mins
+      return properties;
+   }
+
+   public static class Builder extends BaseHttpApiMetadata.Builder<PacketApi, Builder> {
+
+      protected Builder() {
+         id("packet")
+                 .name("Packet API")
+                 .identityName("We can use project Id")

Let's say what needs to be put as the identity. Users will read this to know what to put, so let's be concrete and pick one option.

> +      properties.put(TEMPLATE, "osFamily=UBUNTU,os64Bit=true,osVersionMatches=14.*");
+      properties.put(TIMEOUT_NODE_RUNNING, 300000); // 5 mins
+      return properties;
+   }
+
+   public static class Builder extends BaseHttpApiMetadata.Builder<PacketApi, Builder> {
+
+      protected Builder() {
+         id("packet")
+                 .name("Packet API")
+                 .identityName("We can use project Id")
+                 .credentialName("Must be Token")
+                 .documentation(URI.create("https://www.packet.net/help/api/#"))
+                 .defaultEndpoint("https://api.packet.net")
+                 .defaultProperties(PacketApiMetadata.defaultProperties())
+                 .view(typeToken(ComputeServiceContext.class))

Comment this out until the ComputeService interface is implemented.

> +
+    public static Properties defaultProperties() {
+        final Properties properties = PacketApiMetadata.defaultProperties();
+        return properties;
+    }
+
+    public static class Builder extends BaseProviderMetadata.Builder {
+
+        protected Builder() {
+            id("packet")
+                    .name("Packet Compute Services")
+                    .apiMetadata(new PacketApiMetadata())
+                    .homepage(URI.create("https://www.packet.net/"))
+                    .console(URI.create("https://app.packet.net/portal"))
+                    .endpoint("https://api.packet.net")
+                    .defaultProperties(PacketProviderMetadata.defaultProperties());

Do we know which regions are available so we can put the iso codes here?

> +import org.jclouds.location.suppliers.implicit.FirstRegion;
+import org.jclouds.packet.PacketApi;
+import org.jclouds.packet.handlers.PacketErrorHandler;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.HttpApiModule;
+
+import com.google.inject.Scopes;
+
+@ConfiguresHttpApi
+public class PacketHttpApiModule extends HttpApiModule<PacketApi> {
+
+   @Override
+   protected void configure() {
+      install(new PacketComputeParserModule());
+      super.configure();
+   }

We could remove this if we add the parser module to the list of modules in the api metadata. Better to have the complete list there?

> +   @Override
+   protected void configure() {
+      install(new PacketComputeParserModule());
+      super.configure();
+   }
+
+   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(PacketErrorHandler.class);
+   }
+
+   @Override
+   protected void bindRetryHandlers() {
+      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class);

Hmmmm, this means we are going to retry 4xx errors. Is that what we want? Those usually are bad requests that will always fail. Retrying should be done by default just for server errors.

> +   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(PacketErrorHandler.class);
+   }
+
+   @Override
+   protected void bindRetryHandlers() {
+      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class);
+   }
+
+   @Override
+   protected void installLocations() {
+      install(new LocationModule());
+      bind(ImplicitLocationSupplier.class).to(FirstRegion.class).in(Scopes.SINGLETON);

Move the binding to the configure method and remove this override?

> +import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+
+@Path("/projects")
+@Consumes(MediaType.APPLICATION_JSON)
+@RequestFilters(AddXAuthTokenToRequest.class)
+public interface ProjectApi {
+
+    /**
+     * List all projects
+     */
+    @Named("project:list")
+    @GET
+    @SelectJson("projects")
+    @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
+    List<Project> list();

Since Packet supports pagination, we should add it as soon as possible, to set the foundation for all the APIs. I'd configure this list to support pagination right in this PR.
Looking at the docs, it works very very similar to the DigitalOcean2 one, so you could take it as an example (for example the [ActionApi](https://github.com/jclouds/jclouds/blob/master/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/features/ActionApi.java) class, which is a small one) and get it working soon.

> +import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequestFilter;
+import org.jclouds.location.Provider;
+
+import com.google.common.base.Supplier;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@Singleton
+public class AddXAuthTokenToRequest implements HttpRequestFilter {
+
+    private final Supplier<Credentials> creds;
+
+    @Inject
+    public AddXAuthTokenToRequest(@Provider Supplier<Credentials> creds) {

Remove the public modifier.

> +import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequestFilter;
+import org.jclouds.location.Provider;
+
+import com.google.common.base.Supplier;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@Singleton
+public class AddXAuthTokenToRequest implements HttpRequestFilter {
+
+    private final Supplier<Credentials> creds;
+
+    @Inject
+    public AddXAuthTokenToRequest(@Provider Supplier<Credentials> creds) {
+        this.creds = checkNotNull(creds, "creds");

The check is redundant. Injection will fail if it is not present.

> + */
+@Singleton
+public class PacketErrorHandler implements HttpErrorHandler {
+
+   public void handleError(HttpCommand command, HttpResponse response) {
+      // it is important to always read fully and close streams
+      byte[] data = closeClientButKeepContentStream(response);
+      String message = data != null ? new String(data) : null;
+
+      Exception exception = message != null ? new HttpResponseException(command, response, message)
+              : new HttpResponseException(command, response);
+      message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+              response.getStatusLine());
+      switch (response.getStatusCode()) {
+         case 400:
+            break;

400 errors are Bad Request errors which are usually populated as IllegalArgumentException errors.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340#pullrequestreview-15923697

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
andreaturli commented on this pull request.



> +      properties.put(TEMPLATE, "osFamily=UBUNTU,os64Bit=true,osVersionMatches=14.*");
+      properties.put(TIMEOUT_NODE_RUNNING, 300000); // 5 mins
+      return properties;
+   }
+
+   public static class Builder extends BaseHttpApiMetadata.Builder<PacketApi, Builder> {
+
+      protected Builder() {
+         id("packet")
+                 .name("Packet API")
+                 .identityName("We can use project Id")
+                 .credentialName("Must be Token")
+                 .documentation(URI.create("https://www.packet.net/help/api/#"))
+                 .defaultEndpoint("https://api.packet.net")
+                 .defaultProperties(PacketApiMetadata.defaultProperties())
+                 .view(typeToken(ComputeServiceContext.class))

ok

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Ignasi Barrera <no...@github.com>.
nacx approved this pull request.





-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340#pullrequestreview-16118691

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Ignasi Barrera <no...@github.com>.
nacx commented on this pull request.



> +   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(PacketErrorHandler.class);
+   }
+
+   @Override
+   protected void bindRetryHandlers() {
+      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class);
+   }
+
+   @Override
+   protected void installLocations() {
+      install(new LocationModule());
+      bind(ImplicitLocationSupplier.class).to(FirstRegion.class).in(Scopes.SINGLETON);

That's what the method of the parent class installs. If you don't override it, it will already get installed.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Ignasi Barrera <no...@github.com>.
Nice! +1!

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340#issuecomment-271846415

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Ignasi Barrera <no...@github.com>.
nacx requested changes on this pull request.

This looks great @andreaturli! Just a few final comments.

> @@ -107,6 +107,11 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.apache.jclouds.labs</groupId>
+            <artifactId>cloudsigma2</artifactId>
+            <version>2.1.0-SNAPSHOT</version>
+        </dependency>

Remove this

> @@ -50,12 +56,7 @@ protected void bindErrorHandlers() {
 
    @Override
    protected void bindRetryHandlers() {
-      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class);
+      bind(HttpRetryHandler.class).annotatedWith(ServerError.class).to(BackoffLimitedRetryHandler.class);

This is [the default handler](https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/http/handlers/DelegatingRetryHandler.java#L56) bound for server errors, so there is no need to override this method to set it.

> @@ -43,8 +43,6 @@ public void handleError(HttpCommand command, HttpResponse response) {
       message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
               response.getStatusLine());
       switch (response.getStatusCode()) {
-         case 400:
-            break;

If we don't handle this, we will propagate a generic `HttpResponseException` for bad requests. The common pattern is to handle it and encapsulate it in an `IllealArgumentException`.

>  
-      assertEquals(size(projects), 1); 
+      assertEquals(size(projects), 1);
       assertEquals(server.getRequestCount(), 1);
       assertSent(server, "GET", "/projects");
    }

Change the test to something like [this](https://github.com/jclouds/jclouds/blob/master/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/features/ActionApiMockTest.java#L37-L48), to also verify that pagination works.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340#pullrequestreview-16103425

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
Closed #340.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340#event-919140102

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
andreaturli commented on this pull request.



> +   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(PacketErrorHandler.class);
+   }
+
+   @Override
+   protected void bindRetryHandlers() {
+      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class);
+   }
+
+   @Override
+   protected void installLocations() {
+      install(new LocationModule());
+      bind(ImplicitLocationSupplier.class).to(FirstRegion.class).in(Scopes.SINGLETON);

what about the LocationModule then?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
ok thanks, merging!

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340#issuecomment-271874692

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
@andreaturli pushed 1 commit.

a64d73b  add pagination to Project API


-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340/files/4ce88bff4bb288d6d83351b28d941f4f8641d24e..a64d73b7b153ec3639450b5efc371a600eb09870

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
merged at [master](http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/070fe653)

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340#issuecomment-271875353

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
@andreaturli pushed 1 commit.

2b4840b  fix typo


-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340/files/a64d73b7b153ec3639450b5efc371a600eb09870..2b4840bf717719e31d448d60c315bb477bed50cd

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
@andreaturli pushed 1 commit.

0315649  test pagination


-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340/files/2b4840bf717719e31d448d60c315bb477bed50cd..031564949f567d96fdc7ac10d5c3b2d0c2a5c83c

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
andreaturli commented on this pull request.



> +
+    public static Properties defaultProperties() {
+        final Properties properties = PacketApiMetadata.defaultProperties();
+        return properties;
+    }
+
+    public static class Builder extends BaseProviderMetadata.Builder {
+
+        protected Builder() {
+            id("packet")
+                    .name("Packet Compute Services")
+                    .apiMetadata(new PacketApiMetadata())
+                    .homepage(URI.create("https://www.packet.net/"))
+                    .console(URI.create("https://app.packet.net/portal"))
+                    .endpoint("https://api.packet.net")
+                    .defaultProperties(PacketProviderMetadata.defaultProperties());

yes, good idea, they have NJ, CA, NL and JP

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
andreaturli commented on this pull request.



> +import org.jclouds.location.suppliers.implicit.FirstRegion;
+import org.jclouds.packet.PacketApi;
+import org.jclouds.packet.handlers.PacketErrorHandler;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.HttpApiModule;
+
+import com.google.inject.Scopes;
+
+@ConfiguresHttpApi
+public class PacketHttpApiModule extends HttpApiModule<PacketApi> {
+
+   @Override
+   protected void configure() {
+      install(new PacketComputeParserModule());
+      super.configure();
+   }

ok, I've seen both patterns in jclouds, I will move that to ApiMetadata

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
andreaturli commented on this pull request.



> +   @Override
+   protected void configure() {
+      install(new PacketComputeParserModule());
+      super.configure();
+   }
+
+   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(PacketErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(PacketErrorHandler.class);
+   }
+
+   @Override
+   protected void bindRetryHandlers() {
+      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class);

ok will change it


-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
rebuild please

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340#issuecomment-271844332

Re: [jclouds/jclouds-labs] Add skeleton for ApiMetadata and ProviderMetadata (#340)

Posted by Andrea Turli <no...@github.com>.
andreaturli commented on this pull request.



> +   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   public PacketApiMetadata() {
+      this(new Builder());
+   }
+
+   protected PacketApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseHttpApiMetadata.defaultProperties();
+      properties.put(TEMPLATE, "osFamily=UBUNTU,os64Bit=true,osVersionMatches=14.*");

yes they offer ubuntu 16.04 LTS, will update

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/jclouds/jclouds-labs/pull/340