mirror of https://github.com/apache/jclouds.git
Merge pull request #963 from rackspace/openstack-cinder
Added support for the OpenStack Cinder Block Storage API.
This commit is contained in:
commit
6a1a468e4e
|
@ -0,0 +1,122 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-project</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<relativePath>../../project/pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>org.jclouds.labs</groupId>
|
||||
<artifactId>openstack-cinder</artifactId>
|
||||
<name>jclouds openstack-cinder api</name>
|
||||
<description>jclouds components to access an implementation of OpenStack Cinder</description>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<properties>
|
||||
<!-- keystone endpoint -->
|
||||
<test.openstack-cinder.endpoint>http://localhost:5000/v2.0/</test.openstack-cinder.endpoint>
|
||||
<!-- keystone version -->
|
||||
<test.openstack-cinder.api-version>1</test.openstack-cinder.api-version>
|
||||
<test.openstack-cinder.build-version></test.openstack-cinder.build-version>
|
||||
<test.openstack-cinder.identity>FIXME_IDENTITY</test.openstack-cinder.identity>
|
||||
<test.openstack-cinder.credential>FIXME_CREDENTIALS</test.openstack-cinder.credential>
|
||||
<test.jclouds.keystone.credential-type>passwordCredentials</test.jclouds.keystone.credential-type>
|
||||
|
||||
<jclouds.osgi.export>org.jclouds.openstack.cinder.v1*;version="${project.version}"</jclouds.osgi.export>
|
||||
<jclouds.osgi.import>
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</jclouds.osgi.import>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jclouds.api</groupId>
|
||||
<artifactId>openstack-keystone</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jclouds.api</groupId>
|
||||
<artifactId>openstack-keystone</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>live</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>integration</id>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<test.openstack-cinder.endpoint>${test.openstack-cinder.endpoint}</test.openstack-cinder.endpoint>
|
||||
<test.openstack-cinder.api-version>${test.openstack-cinder.api-version}</test.openstack-cinder.api-version>
|
||||
<test.openstack-cinder.build-version>${test.openstack-cinder.build-version}</test.openstack-cinder.build-version>
|
||||
<test.openstack-cinder.identity>${test.openstack-cinder.identity}</test.openstack-cinder.identity>
|
||||
<test.openstack-cinder.credential>${test.openstack-cinder.credential}</test.openstack-cinder.credential>
|
||||
<test.jclouds.keystone.credential-type>${test.jclouds.keystone.credential-type}</test.jclouds.keystone.credential-type>
|
||||
<jclouds.blobstore.httpstream.url>${jclouds.blobstore.httpstream.url}</jclouds.blobstore.httpstream.url>
|
||||
<jclouds.blobstore.httpstream.md5>${jclouds.blobstore.httpstream.md5}</jclouds.blobstore.httpstream.md5>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.location.Zone;
|
||||
import org.jclouds.location.functions.ZoneToEndpoint;
|
||||
import org.jclouds.openstack.cinder.v1.features.SnapshotApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeTypeApi;
|
||||
import org.jclouds.openstack.v2_0.features.ExtensionApi;
|
||||
import org.jclouds.rest.annotations.Delegate;
|
||||
import org.jclouds.rest.annotations.EndpointParam;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* Provides synchronous access to Cinder.
|
||||
*
|
||||
* @see CinderAsyncApi
|
||||
* @see <a href="http://api.openstack.org/">API Doc</a>
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
|
||||
public interface CinderApi {
|
||||
/**
|
||||
* @return the Zone codes configured
|
||||
*/
|
||||
@Provides
|
||||
@Zone
|
||||
Set<String> getConfiguredZones();
|
||||
|
||||
/**
|
||||
* Provides synchronous access to Extension features.
|
||||
*/
|
||||
@Delegate
|
||||
ExtensionApi getExtensionApiForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
/**
|
||||
* Provides synchronous access to Volume features.
|
||||
*/
|
||||
@Delegate
|
||||
VolumeApi getVolumeApiForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
/**
|
||||
* Provides synchronous access to VolumeType features.
|
||||
*/
|
||||
@Delegate
|
||||
VolumeTypeApi getVolumeTypeApiForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
/**
|
||||
* Provides synchronous access to Snapshot features.
|
||||
*/
|
||||
@Delegate
|
||||
SnapshotApi getSnapshotApiForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1;
|
||||
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.apis.ApiMetadata;
|
||||
import org.jclouds.openstack.cinder.v1.config.CinderParserModule;
|
||||
import org.jclouds.openstack.cinder.v1.config.CinderRestClientModule;
|
||||
import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
|
||||
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
|
||||
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ZoneModule;
|
||||
import org.jclouds.openstack.v2_0.ServiceType;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.rest.internal.BaseRestApiMetadata;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ApiMetadata} for Cinder v1 API
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class CinderApiMetadata extends BaseRestApiMetadata {
|
||||
|
||||
private static final long serialVersionUID = 4525672099385581765L;
|
||||
|
||||
public static final TypeToken<RestContext<CinderApi, CinderAsyncApi>> CONTEXT_TOKEN = new TypeToken<RestContext<CinderApi, CinderAsyncApi>>() {
|
||||
private static final long serialVersionUID = -2850937833892503251L;
|
||||
};
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().fromApiMetadata(this);
|
||||
}
|
||||
|
||||
public CinderApiMetadata() {
|
||||
this(new Builder());
|
||||
}
|
||||
|
||||
protected CinderApiMetadata(Builder builder) {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
|
||||
properties.setProperty(SERVICE_TYPE, ServiceType.BLOCK_STORAGE);
|
||||
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
public static class Builder extends BaseRestApiMetadata.Builder {
|
||||
|
||||
protected Builder() {
|
||||
super(CinderApi.class, CinderAsyncApi.class);
|
||||
id("openstack-cinder")
|
||||
.name("OpenStack Cinder Folsom API")
|
||||
.identityName("${tenantName}:${userName} or ${userName}, if your keystone supports a default tenant")
|
||||
.credentialName("${password}")
|
||||
.endpointName("Keystone base URL ending in /v2.0/")
|
||||
.documentation(URI.create("http://api.openstack.org/"))
|
||||
.version("1")
|
||||
.defaultEndpoint("http://localhost:5000/v2.0/")
|
||||
.defaultProperties(CinderApiMetadata.defaultProperties())
|
||||
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
|
||||
.add(KeystoneAuthenticationModule.class)
|
||||
.add(ZoneModule.class)
|
||||
.add(CinderParserModule.class)
|
||||
.add(CinderRestClientModule.class)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CinderApiMetadata build() {
|
||||
return new CinderApiMetadata(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder fromApiMetadata(ApiMetadata in) {
|
||||
super.fromApiMetadata(in);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.location.Zone;
|
||||
import org.jclouds.location.functions.ZoneToEndpoint;
|
||||
import org.jclouds.openstack.cinder.v1.features.SnapshotAsyncApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeAsyncApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeTypeAsyncApi;
|
||||
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
|
||||
import org.jclouds.rest.annotations.Delegate;
|
||||
import org.jclouds.rest.annotations.EndpointParam;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to Cinder via its REST API.
|
||||
*
|
||||
* @see CinderApi
|
||||
* @see <a href="http://api.openstack.org/">API Doc</a>
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public interface CinderAsyncApi {
|
||||
/**
|
||||
* @return the Zone codes configured
|
||||
*/
|
||||
@Provides
|
||||
@Zone
|
||||
Set<String> getConfiguredZones();
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to Extension features.
|
||||
*/
|
||||
@Delegate
|
||||
ExtensionAsyncApi getExtensionApiForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to Volume features.
|
||||
*/
|
||||
@Delegate
|
||||
VolumeAsyncApi getVolumeApiForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to VolumeType features.
|
||||
*/
|
||||
@Delegate
|
||||
VolumeTypeAsyncApi getVolumeTypeApiForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to Snapshot features.
|
||||
*/
|
||||
@Delegate
|
||||
SnapshotAsyncApi getSnapshotApiForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.config;
|
||||
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.json.config.GsonModule.DateAdapter;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
/**
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class CinderParserModule extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.config;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.annotation.ClientError;
|
||||
import org.jclouds.http.annotation.Redirection;
|
||||
import org.jclouds.http.annotation.ServerError;
|
||||
import org.jclouds.json.config.GsonModule.DateAdapter;
|
||||
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
|
||||
import org.jclouds.openstack.cinder.v1.CinderApi;
|
||||
import org.jclouds.openstack.cinder.v1.CinderAsyncApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.SnapshotApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.SnapshotAsyncApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeAsyncApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeTypeApi;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeTypeAsyncApi;
|
||||
import org.jclouds.openstack.cinder.v1.handlers.CinderErrorHandler;
|
||||
import org.jclouds.openstack.v2_0.features.ExtensionApi;
|
||||
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
|
||||
import org.jclouds.rest.ConfiguresRestClient;
|
||||
import org.jclouds.rest.config.RestClientModule;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* Configures the Cinder connection.
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@ConfiguresRestClient
|
||||
public class CinderRestClientModule<S extends CinderApi, A extends CinderAsyncApi> extends RestClientModule<S, A> {
|
||||
|
||||
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
|
||||
.put(ExtensionApi.class, ExtensionAsyncApi.class)
|
||||
.put(VolumeApi.class, VolumeAsyncApi.class)
|
||||
.put(VolumeTypeApi.class, VolumeTypeAsyncApi.class)
|
||||
.put(SnapshotApi.class, SnapshotAsyncApi.class)
|
||||
.build();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public CinderRestClientModule() {
|
||||
super(TypeToken.class.cast(TypeToken.of(CinderApi.class)), TypeToken.class.cast(TypeToken.of(CinderAsyncApi.class)), DELEGATE_MAP);
|
||||
}
|
||||
|
||||
protected CinderRestClientModule(TypeToken<S> syncClientType, TypeToken<A> asyncClientType, Map<Class<?>, Class<?>> sync2Async) {
|
||||
super(syncClientType, asyncClientType, sync2Async);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
|
||||
super.configure();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public Multimap<URI, URI> aliases() {
|
||||
return ImmutableMultimap.<URI, URI>builder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindErrorHandlers() {
|
||||
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(CinderErrorHandler.class);
|
||||
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(CinderErrorHandler.class);
|
||||
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(CinderErrorHandler.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* 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.openstack.cinder.v1.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
|
||||
/**
|
||||
* An Openstack Cinder Volume Snapshot.
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class Snapshot {
|
||||
|
||||
public static Builder<?> builder() {
|
||||
return new ConcreteBuilder();
|
||||
}
|
||||
|
||||
public Builder<?> toBuilder() {
|
||||
return new ConcreteBuilder().fromSnapshot(this);
|
||||
}
|
||||
|
||||
public static abstract class Builder<T extends Builder<T>> {
|
||||
protected abstract T self();
|
||||
|
||||
protected String id;
|
||||
protected String volumeId;
|
||||
protected Volume.Status status;
|
||||
protected int size;
|
||||
protected Date created;
|
||||
protected String name;
|
||||
protected String description;
|
||||
|
||||
/**
|
||||
* @see Snapshot#getId()
|
||||
*/
|
||||
public T id(String id) {
|
||||
this.id = id;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Snapshot#getVolumeId()
|
||||
*/
|
||||
public T volumeId(String volumeId) {
|
||||
this.volumeId = volumeId;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Snapshot#getStatus()
|
||||
*/
|
||||
public T status(Volume.Status status) {
|
||||
this.status = status;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Snapshot#getSize()
|
||||
*/
|
||||
public T size(int size) {
|
||||
this.size = size;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Snapshot#getCreated()
|
||||
*/
|
||||
public T created(Date created) {
|
||||
this.created = created;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Snapshot#getName()
|
||||
*/
|
||||
public T name(String name) {
|
||||
this.name = name;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Snapshot#getDescription()
|
||||
*/
|
||||
public T description(String description) {
|
||||
this.description = description;
|
||||
return self();
|
||||
}
|
||||
|
||||
public Snapshot build() {
|
||||
return new Snapshot(id, volumeId, status, size, created, name, description);
|
||||
}
|
||||
|
||||
public T fromSnapshot(Snapshot in) {
|
||||
return this
|
||||
.id(in.getId())
|
||||
.volumeId(in.getVolumeId())
|
||||
.status(in.getStatus())
|
||||
.size(in.getSize())
|
||||
.created(in.getCreated())
|
||||
.name(in.getName())
|
||||
.description(in.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||
@Override
|
||||
protected ConcreteBuilder self() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private final String id;
|
||||
@Named("volume_id")
|
||||
private final String volumeId;
|
||||
private final Volume.Status status;
|
||||
private final int size;
|
||||
@Named("created_at")
|
||||
private final Date created;
|
||||
@Named("display_name")
|
||||
private final String name;
|
||||
@Named("display_description")
|
||||
private final String description;
|
||||
|
||||
@ConstructorProperties({
|
||||
"id", "volume_id", "status", "size", "created_at", "display_name", "display_description"
|
||||
})
|
||||
protected Snapshot(String id, String volumeId, Volume.Status status, int size, @Nullable Date created, @Nullable String name, @Nullable String description) {
|
||||
this.id = checkNotNull(id, "id");
|
||||
this.volumeId = checkNotNull(volumeId, "volumeId");
|
||||
this.status = checkNotNull(status, "status");
|
||||
this.size = size;
|
||||
this.created = created;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The id of this snapshot
|
||||
*/
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The id of the Volume this snapshot was taken from
|
||||
*/
|
||||
public String getVolumeId() {
|
||||
return this.volumeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The status of this snapshot
|
||||
*/
|
||||
public Volume.Status getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The size in GB of the volume this snapshot was taken from
|
||||
*/
|
||||
public int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The data the snapshot was taken
|
||||
*/
|
||||
@Nullable
|
||||
public Date getCreated() {
|
||||
return this.created;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of this snapshot - as displayed in the openstack console
|
||||
*/
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The description of this snapshot - as displayed in the openstack console
|
||||
*/
|
||||
@Nullable
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(id, volumeId, status, size, created, name, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
Snapshot that = Snapshot.class.cast(obj);
|
||||
return Objects.equal(this.id, that.id)
|
||||
&& Objects.equal(this.volumeId, that.volumeId)
|
||||
&& Objects.equal(this.status, that.status)
|
||||
&& Objects.equal(this.size, that.size)
|
||||
&& Objects.equal(this.created, that.created)
|
||||
&& Objects.equal(this.name, that.name)
|
||||
&& Objects.equal(this.description, that.description);
|
||||
}
|
||||
|
||||
protected ToStringHelper string() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id).add("volumeId", volumeId).add("status", status).add("size", size).add("created", created).add("name", name).add("description", description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string().toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* 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.openstack.cinder.v1.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* An Openstack Cinder Volume.
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class Volume {
|
||||
|
||||
public static enum Status {
|
||||
CREATING, AVAILABLE, ATTACHING, IN_USE, DELETING, ERROR, ERROR_DELETING, UNRECOGNIZED;
|
||||
|
||||
public String value() {
|
||||
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value();
|
||||
}
|
||||
|
||||
public static Status fromValue(String status) {
|
||||
try {
|
||||
return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(status, "status")));
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
return UNRECOGNIZED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Builder<?> builder() {
|
||||
return new ConcreteBuilder();
|
||||
}
|
||||
|
||||
public Builder<?> toBuilder() {
|
||||
return new ConcreteBuilder().fromVolume(this);
|
||||
}
|
||||
|
||||
public static abstract class Builder<T extends Builder<T>> {
|
||||
protected abstract T self();
|
||||
|
||||
protected String id;
|
||||
protected Volume.Status status;
|
||||
protected int size;
|
||||
protected String zone;
|
||||
protected Date created;
|
||||
protected Set<VolumeAttachment> attachments = ImmutableSet.of();
|
||||
protected String volumeType;
|
||||
protected String snapshotId;
|
||||
protected String name;
|
||||
protected String description;
|
||||
protected Map<String, String> metadata = ImmutableMap.of();
|
||||
|
||||
/**
|
||||
* @see Volume#getId()
|
||||
*/
|
||||
public T id(String id) {
|
||||
this.id = id;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getStatus()
|
||||
*/
|
||||
public T status(Volume.Status status) {
|
||||
this.status = status;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getSize()
|
||||
*/
|
||||
public T size(int size) {
|
||||
this.size = size;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getZone()
|
||||
*/
|
||||
public T zone(String zone) {
|
||||
this.zone = zone;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getCreated()
|
||||
*/
|
||||
public T created(Date created) {
|
||||
this.created = created;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getAttachments()
|
||||
*/
|
||||
public T attachments(Set<VolumeAttachment> attachments) {
|
||||
this.attachments = ImmutableSet.copyOf(checkNotNull(attachments, "attachments"));
|
||||
return self();
|
||||
}
|
||||
|
||||
public T attachments(VolumeAttachment... in) {
|
||||
return attachments(ImmutableSet.copyOf(in));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getVolumeType()
|
||||
*/
|
||||
public T volumeType(String volumeType) {
|
||||
this.volumeType = volumeType;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getSnapshotId()
|
||||
*/
|
||||
public T snapshotId(String snapshotId) {
|
||||
this.snapshotId = snapshotId;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getName()
|
||||
*/
|
||||
public T name(String name) {
|
||||
this.name = name;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getDescription()
|
||||
*/
|
||||
public T description(String description) {
|
||||
this.description = description;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Volume#getMetadata()
|
||||
*/
|
||||
public T metadata(Map<String, String> metadata) {
|
||||
this.metadata = ImmutableMap.copyOf(checkNotNull(metadata, "metadata"));
|
||||
return self();
|
||||
}
|
||||
|
||||
public Volume build() {
|
||||
return new Volume(id, status, size, zone, created, attachments, volumeType, snapshotId, name, description, metadata);
|
||||
}
|
||||
|
||||
public T fromVolume(Volume in) {
|
||||
return this
|
||||
.id(in.getId())
|
||||
.status(in.getStatus())
|
||||
.size(in.getSize())
|
||||
.zone(in.getZone())
|
||||
.created(in.getCreated())
|
||||
.attachments(in.getAttachments())
|
||||
.volumeType(in.getVolumeType())
|
||||
.snapshotId(in.getSnapshotId())
|
||||
.name(in.getName())
|
||||
.description(in.getDescription())
|
||||
.metadata(in.getMetadata());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||
@Override
|
||||
protected ConcreteBuilder self() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private final String id;
|
||||
private final Volume.Status status;
|
||||
private final int size;
|
||||
@Named("availability_zone")
|
||||
private final String zone;
|
||||
@Named("created_at")
|
||||
private final Date created;
|
||||
private final Set<VolumeAttachment> attachments;
|
||||
@Named("volume_type")
|
||||
private final String volumeType;
|
||||
@Named("snapshot_id")
|
||||
private final String snapshotId;
|
||||
@Named("display_name")
|
||||
private final String name;
|
||||
@Named("display_description")
|
||||
private final String description;
|
||||
private final Map<String, String> metadata;
|
||||
|
||||
@ConstructorProperties({
|
||||
"id", "status", "size", "availability_zone", "created_at", "attachments", "volume_type", "snapshot_id", "display_name", "display_description", "metadata"
|
||||
})
|
||||
protected Volume(String id, Volume.Status status, int size, String zone, Date created, @Nullable Set<VolumeAttachment> attachments, @Nullable String volumeType, @Nullable String snapshotId, @Nullable String name, @Nullable String description, @Nullable Map<String, String> metadata) {
|
||||
this.id = checkNotNull(id, "id");
|
||||
this.status = checkNotNull(status, "status");
|
||||
this.size = size;
|
||||
this.zone = checkNotNull(zone, "zone");
|
||||
this.created = checkNotNull(created, "created");
|
||||
this.attachments = attachments == null ? ImmutableSet.<VolumeAttachment>of() : ImmutableSet.copyOf(attachments);
|
||||
this.volumeType = volumeType;
|
||||
this.snapshotId = snapshotId;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.metadata = metadata == null ? ImmutableMap.<String, String>of() : ImmutableMap.copyOf(metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id of this volume
|
||||
*/
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the status of this volume
|
||||
*/
|
||||
public Volume.Status getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size in GB of this volume
|
||||
*/
|
||||
public int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the availabilityZone containing this volume
|
||||
*/
|
||||
public String getZone() {
|
||||
return this.zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the time this volume was created
|
||||
*/
|
||||
public Date getCreated() {
|
||||
return this.created;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the set of attachments (to Servers)
|
||||
*/
|
||||
public Set<VolumeAttachment> getAttachments() {
|
||||
return this.attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type of this volume
|
||||
*/
|
||||
@Nullable
|
||||
public String getVolumeType() {
|
||||
return this.volumeType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSnapshotId() {
|
||||
return this.snapshotId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of this volume - as displayed in the openstack console
|
||||
*/
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the description of this volume - as displayed in the openstack console
|
||||
*/
|
||||
@Nullable
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(id, status, size, zone, created, attachments, volumeType, snapshotId, name, description, metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
Volume that = Volume.class.cast(obj);
|
||||
return Objects.equal(this.id, that.id)
|
||||
&& Objects.equal(this.status, that.status)
|
||||
&& Objects.equal(this.size, that.size)
|
||||
&& Objects.equal(this.zone, that.zone)
|
||||
&& Objects.equal(this.created, that.created)
|
||||
&& Objects.equal(this.attachments, that.attachments)
|
||||
&& Objects.equal(this.volumeType, that.volumeType)
|
||||
&& Objects.equal(this.snapshotId, that.snapshotId)
|
||||
&& Objects.equal(this.name, that.name)
|
||||
&& Objects.equal(this.description, that.description)
|
||||
&& Objects.equal(this.metadata, that.metadata);
|
||||
}
|
||||
|
||||
protected ToStringHelper string() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id).add("status", status).add("size", size).add("zone", zone).add("created", created).add("attachments", attachments).add("volumeType", volumeType).add("snapshotId", snapshotId).add("name", name).add("description", description).add("metadata", metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string().toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* 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.openstack.cinder.v1.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
|
||||
/**
|
||||
* An OpenStack Cinder Volume Attachment (describes how Volumes are attached to Servers).
|
||||
*/
|
||||
public class VolumeAttachment {
|
||||
|
||||
public static Builder<?> builder() {
|
||||
return new ConcreteBuilder();
|
||||
}
|
||||
|
||||
public Builder<?> toBuilder() {
|
||||
return new ConcreteBuilder().fromVolumeAttachment(this);
|
||||
}
|
||||
|
||||
public abstract static class Builder<T extends Builder<T>> {
|
||||
protected abstract T self();
|
||||
|
||||
protected String id;
|
||||
protected String volumeId;
|
||||
protected String serverId;
|
||||
protected String device;
|
||||
|
||||
/**
|
||||
* @see VolumeAttachment#getId()
|
||||
*/
|
||||
public T id(String id) {
|
||||
this.id = id;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see VolumeAttachment#getVolumeId()
|
||||
*/
|
||||
public T volumeId(String volumeId) {
|
||||
this.volumeId = volumeId;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see VolumeAttachment#getServerId()
|
||||
*/
|
||||
public T serverId(String serverId) {
|
||||
this.serverId = serverId;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see VolumeAttachment#getDevice()
|
||||
*/
|
||||
public T device(String device) {
|
||||
this.device = device;
|
||||
return self();
|
||||
}
|
||||
|
||||
public VolumeAttachment build() {
|
||||
return new VolumeAttachment(id, volumeId, serverId, device);
|
||||
}
|
||||
|
||||
public T fromVolumeAttachment(VolumeAttachment in) {
|
||||
return this
|
||||
.id(in.getId())
|
||||
.volumeId(in.getVolumeId())
|
||||
.serverId(in.getServerId())
|
||||
.device(in.getDevice());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||
@Override
|
||||
protected ConcreteBuilder self() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private final String id;
|
||||
@Named("volume_id")
|
||||
private final String volumeId;
|
||||
@Named("server_id")
|
||||
private final String serverId;
|
||||
private final String device;
|
||||
|
||||
@ConstructorProperties({
|
||||
"id", "volume_id", "server_id", "device"
|
||||
})
|
||||
protected VolumeAttachment(String id, String volumeId, @Nullable String serverId, @Nullable String device) {
|
||||
this.id = checkNotNull(id, "id");
|
||||
this.volumeId = checkNotNull(volumeId, "volumeId");
|
||||
this.serverId = serverId;
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the attachment id (typically the same as #getVolumeId())
|
||||
*/
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id of the volume attached
|
||||
*/
|
||||
public String getVolumeId() {
|
||||
return this.volumeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id of the server the volume is attached to
|
||||
*/
|
||||
@Nullable
|
||||
public String getServerId() {
|
||||
return this.serverId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the device name (e.g. "/dev/vdc")
|
||||
*/
|
||||
@Nullable
|
||||
public String getDevice() {
|
||||
return this.device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(id, volumeId, serverId, device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
VolumeAttachment that = VolumeAttachment.class.cast(obj);
|
||||
return Objects.equal(this.id, that.id)
|
||||
&& Objects.equal(this.volumeId, that.volumeId)
|
||||
&& Objects.equal(this.serverId, that.serverId)
|
||||
&& Objects.equal(this.device, that.device);
|
||||
}
|
||||
|
||||
protected ToStringHelper string() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id).add("volumeId", volumeId).add("serverId", serverId).add("device", device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string().toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* 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.openstack.cinder.v1.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* An Openstack Cinder Volume Type.
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class VolumeType {
|
||||
|
||||
public static Builder<?> builder() {
|
||||
return new ConcreteBuilder();
|
||||
}
|
||||
|
||||
public Builder<?> toBuilder() {
|
||||
return new ConcreteBuilder().fromVolumeType(this);
|
||||
}
|
||||
|
||||
public static abstract class Builder<T extends Builder<T>> {
|
||||
protected abstract T self();
|
||||
|
||||
protected String id;
|
||||
protected String name;
|
||||
protected Date created;
|
||||
protected Date updated;
|
||||
protected Map<String, String> extraSpecs = ImmutableMap.of();
|
||||
|
||||
/**
|
||||
* @see VolumeType#getId()
|
||||
*/
|
||||
public T id(String id) {
|
||||
this.id = id;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see VolumeType#getName()
|
||||
*/
|
||||
public T name(String name) {
|
||||
this.name = name;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see VolumeType#getCreated()
|
||||
*/
|
||||
public T created(Date created) {
|
||||
this.created = created;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see VolumeType#getUpdated()
|
||||
*/
|
||||
public T updated(Date updated) {
|
||||
this.updated = updated;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see VolumeType#getExtraSpecs()
|
||||
*/
|
||||
public T extraSpecs(Map<String, String> extraSpecs) {
|
||||
this.extraSpecs = ImmutableMap.copyOf(checkNotNull(extraSpecs, "extraSpecs"));
|
||||
return self();
|
||||
}
|
||||
|
||||
public VolumeType build() {
|
||||
return new VolumeType(id, name, created, updated, extraSpecs);
|
||||
}
|
||||
|
||||
public T fromVolumeType(VolumeType in) {
|
||||
return this
|
||||
.id(in.getId())
|
||||
.name(in.getName())
|
||||
.created(in.getCreated().orNull())
|
||||
.updated(in.getUpdated().orNull())
|
||||
.extraSpecs(in.getExtraSpecs());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||
@Override
|
||||
protected ConcreteBuilder self() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private final String id;
|
||||
private final String name;
|
||||
@Named("created_at")
|
||||
private final Optional<Date> created;
|
||||
@Named("updated_at")
|
||||
private final Optional<Date> updated;
|
||||
@Named("extra_specs")
|
||||
private final Map<String, String> extraSpecs;
|
||||
|
||||
@ConstructorProperties({
|
||||
"id", "name", "created_at", "updated_at", "extra_specs"
|
||||
})
|
||||
protected VolumeType(String id, String name, @Nullable Date created, @Nullable Date updated, Map<String, String> extraSpecs) {
|
||||
this.id = checkNotNull(id, "id");
|
||||
this.name = checkNotNull(name, "name");
|
||||
this.created = Optional.fromNullable(created);
|
||||
this.updated = Optional.fromNullable(updated);
|
||||
this.extraSpecs = ImmutableMap.copyOf(checkNotNull(extraSpecs, "extraSpecs"));
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Date the VolumeType was created
|
||||
*/
|
||||
public Optional<Date> getCreated() {
|
||||
return this.created;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Date the VolumeType as last updated - absent if no updates have taken place
|
||||
*/
|
||||
public Optional<Date> getUpdated() {
|
||||
return this.updated;
|
||||
}
|
||||
|
||||
public Map<String, String> getExtraSpecs() {
|
||||
return this.extraSpecs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(id, name, created, updated, extraSpecs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
VolumeType that = VolumeType.class.cast(obj);
|
||||
return Objects.equal(this.id, that.id)
|
||||
&& Objects.equal(this.name, that.name)
|
||||
&& Objects.equal(this.created, that.created)
|
||||
&& Objects.equal(this.updated, that.updated)
|
||||
&& Objects.equal(this.extraSpecs, that.extraSpecs);
|
||||
}
|
||||
|
||||
protected ToStringHelper string() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id).add("name", name).add("created", created).add("updated", updated).add("extraSpecs", extraSpecs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string().toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package org.jclouds.openstack.cinder.v1.features;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.openstack.cinder.v1.domain.Snapshot;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateSnapshotOptions;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
|
||||
/**
|
||||
* Provides synchronous access to Volume Snapshots via their REST API.
|
||||
*
|
||||
* @see SnapshotAsyncApi
|
||||
* @see <a href="http://api.openstack.org/">API Doc</a>
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
||||
public interface SnapshotApi {
|
||||
/**
|
||||
* Returns a summary list of Snapshots.
|
||||
*
|
||||
* @return The list of Snapshots
|
||||
*/
|
||||
FluentIterable<? extends Snapshot> list();
|
||||
|
||||
/**
|
||||
* Returns a detailed list of Snapshots.
|
||||
*
|
||||
* @return The list of Snapshots
|
||||
*/
|
||||
FluentIterable<? extends Snapshot> listInDetail();
|
||||
|
||||
/**
|
||||
* Return data about the given Snapshot.
|
||||
*
|
||||
* @param snapshotId Id of the Snapshot
|
||||
* @return Details of a specific Snapshot
|
||||
*/
|
||||
Snapshot get(String snapshotId);
|
||||
|
||||
/**
|
||||
* Creates a new Snapshot
|
||||
*
|
||||
* @param volumeId The Volume Id from which to create the Snapshot
|
||||
* @param options See CreateSnapshotOptions
|
||||
* @return The new Snapshot
|
||||
*/
|
||||
Snapshot create(String volumeId, CreateSnapshotOptions... options);
|
||||
|
||||
/**
|
||||
* Delete a Snapshot.
|
||||
*
|
||||
* @param snapshotId Id of the Snapshot
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
boolean delete(String snapshotId);
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.features;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.openstack.cinder.v1.domain.Snapshot;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateSnapshotOptions;
|
||||
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
|
||||
import org.jclouds.rest.annotations.ExceptionParser;
|
||||
import org.jclouds.rest.annotations.MapBinder;
|
||||
import org.jclouds.rest.annotations.PayloadParam;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to Snapshots.
|
||||
*
|
||||
* @see SnapshotApi
|
||||
* @see <a href="http://api.openstack.org/">API Doc</a>
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@SkipEncoding({'/', '='})
|
||||
@RequestFilters(AuthenticateRequest.class)
|
||||
public interface SnapshotAsyncApi {
|
||||
/**
|
||||
* @see SnapshotApi#list()
|
||||
*/
|
||||
@GET
|
||||
@Path("/snapshots")
|
||||
@SelectJson("snapshots")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends FluentIterable<? extends Snapshot>> list();
|
||||
|
||||
/**
|
||||
* @see SnapshotApi#listInDetail()
|
||||
*/
|
||||
@GET
|
||||
@Path("/snapshots/detail")
|
||||
@SelectJson("snapshots")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends FluentIterable<? extends Snapshot>> listInDetail();
|
||||
|
||||
/**
|
||||
* @see SnapshotApi#get(String)
|
||||
*/
|
||||
@GET
|
||||
@Path("/snapshots/{id}")
|
||||
@SelectJson("snapshot")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends Snapshot> get(@PathParam("id") String snapshotId);
|
||||
|
||||
/**
|
||||
* @see SnapshotApi#create(String, CreateSnapshotOptions...)
|
||||
*/
|
||||
@POST
|
||||
@Path("/snapshots")
|
||||
@SelectJson("snapshot")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@MapBinder(CreateSnapshotOptions.class)
|
||||
ListenableFuture<? extends Snapshot> create(@PayloadParam("volume_id") String volumeId, CreateSnapshotOptions... options);
|
||||
|
||||
/**
|
||||
* @see SnapshotApi#delete(String)
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/snapshots/{id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> delete(@PathParam("id") String snapshotId);
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package org.jclouds.openstack.cinder.v1.features;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.openstack.cinder.v1.domain.Volume;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateVolumeOptions;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
|
||||
/**
|
||||
* Provides synchronous access to Volumes.
|
||||
*
|
||||
* This API strictly handles creating and managing Volumes. To attach a Volume to a Server you need to use the
|
||||
* @see VolumeAttachmentApi
|
||||
*
|
||||
* @see VolumeAsyncApi
|
||||
* @see <a href="http://api.openstack.org/">API Doc</a>
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
||||
public interface VolumeApi {
|
||||
/**
|
||||
* Returns a summary list of Volumes.
|
||||
*
|
||||
* @return The list of Volumes
|
||||
*/
|
||||
FluentIterable<? extends Volume> list();
|
||||
|
||||
/**
|
||||
* Returns a detailed list of Volumes.
|
||||
*
|
||||
* @return The list of Volumes
|
||||
*/
|
||||
FluentIterable<? extends Volume> listInDetail();
|
||||
|
||||
/**
|
||||
* Return data about the given Volume.
|
||||
*
|
||||
* @param volumeId Id of the Volume
|
||||
* @return Details of a specific Volume
|
||||
*/
|
||||
Volume get(String volumeId);
|
||||
|
||||
/**
|
||||
* Creates a new Volume
|
||||
*
|
||||
* @param volumeId Id of the Volume
|
||||
* @param options See CreateVolumeOptions
|
||||
* @return The new Volume
|
||||
*/
|
||||
Volume create(int sizeGB, CreateVolumeOptions... options);
|
||||
|
||||
/**
|
||||
* Delete a Volume.
|
||||
*
|
||||
* @param volumeId Id of the Volume
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
boolean delete(String volumeId);
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.features;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.openstack.cinder.v1.domain.Volume;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateVolumeOptions;
|
||||
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
|
||||
import org.jclouds.rest.annotations.ExceptionParser;
|
||||
import org.jclouds.rest.annotations.MapBinder;
|
||||
import org.jclouds.rest.annotations.PayloadParam;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to Volumes.
|
||||
*
|
||||
* @see VolumeApi
|
||||
* @see <a href="http://api.openstack.org/">API Doc</a>
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@SkipEncoding({'/', '='})
|
||||
@RequestFilters(AuthenticateRequest.class)
|
||||
public interface VolumeAsyncApi {
|
||||
/**
|
||||
* @see VolumeApi#list()
|
||||
*/
|
||||
@GET
|
||||
@Path("/volumes")
|
||||
@SelectJson("volumes")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends FluentIterable<? extends Volume>> list();
|
||||
|
||||
/**
|
||||
* @see VolumeApi#listInDetail()
|
||||
*/
|
||||
@GET
|
||||
@Path("/volumes/detail")
|
||||
@SelectJson("volumes")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends FluentIterable<? extends Volume>> listInDetail();
|
||||
|
||||
/**
|
||||
* @see VolumeApi#get(String)
|
||||
*/
|
||||
@GET
|
||||
@Path("/volumes/{id}")
|
||||
@SelectJson("volume")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends Volume> get(@PathParam("id") String volumeId);
|
||||
|
||||
/**
|
||||
* @see VolumeApi#create(int, CreateVolumeOptions...)
|
||||
*/
|
||||
@POST
|
||||
@Path("/volumes")
|
||||
@SelectJson("volume")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@MapBinder(CreateVolumeOptions.class)
|
||||
ListenableFuture<? extends Volume> create(@PayloadParam("size") int sizeGB, CreateVolumeOptions... options);
|
||||
|
||||
/**
|
||||
* @see VolumeApi#delete(String)
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/volumes/{id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> delete(@PathParam("id") String volumeId);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package org.jclouds.openstack.cinder.v1.features;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.openstack.cinder.v1.domain.VolumeType;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
|
||||
/**
|
||||
* Provides synchronous access to Volumes via their REST API.
|
||||
*
|
||||
* @see VolumeAsyncApi
|
||||
* @see <a href="http://api.openstack.org/">API Doc</a>
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
||||
public interface VolumeTypeApi {
|
||||
/**
|
||||
* Returns a summary list of VolumeTypes.
|
||||
*
|
||||
* @return The list of VolumeTypes
|
||||
*/
|
||||
FluentIterable<? extends VolumeType> list();
|
||||
|
||||
/**
|
||||
* Return data about the given VolumeType.
|
||||
*
|
||||
* @param volumeTypeId Id of the VolumeType
|
||||
* @return Details of a specific VolumeType
|
||||
*/
|
||||
VolumeType get(String volumeTypeId);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.features;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.openstack.cinder.v1.domain.VolumeType;
|
||||
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
|
||||
import org.jclouds.rest.annotations.ExceptionParser;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to VolumeTypes.
|
||||
*
|
||||
* @see VolumeTypeApi
|
||||
* @see <a href="http://api.openstack.org/">API Doc</a>
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@SkipEncoding({'/', '='})
|
||||
@RequestFilters(AuthenticateRequest.class)
|
||||
public interface VolumeTypeAsyncApi {
|
||||
/**
|
||||
* @see VolumeTypeApi#list()
|
||||
*/
|
||||
@GET
|
||||
@Path("/types")
|
||||
@SelectJson("volume_types")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends FluentIterable<? extends VolumeType>> list();
|
||||
|
||||
/**
|
||||
* @see VolumeTypeApi#get(String)
|
||||
*/
|
||||
@GET
|
||||
@Path("/types/{id}")
|
||||
@SelectJson("volume_type")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends VolumeType> get(@PathParam("id") String volumeTypeId);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.handlers;
|
||||
|
||||
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.InsufficientResourcesException;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* This will parse and set an appropriate exception on the command object.
|
||||
*
|
||||
* @author Everett Toews
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class CinderErrorHandler 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:
|
||||
if (message.contains("quota exceeded"))
|
||||
exception = new InsufficientResourcesException(message, exception);
|
||||
else if (message.contains("Invalid volume"))
|
||||
exception = new IllegalStateException(message, exception);
|
||||
break;
|
||||
case 401:
|
||||
case 403:
|
||||
exception = new AuthorizationException(message, exception);
|
||||
break;
|
||||
case 404:
|
||||
if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
|
||||
exception = new ResourceNotFoundException(message, exception);
|
||||
}
|
||||
break;
|
||||
case 413:
|
||||
exception = new InsufficientResourcesException(message, exception);
|
||||
break;
|
||||
}
|
||||
command.setException(exception);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.options;
|
||||
|
||||
import static com.google.common.base.Objects.equal;
|
||||
import static com.google.common.base.Objects.toStringHelper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.MapBinder;
|
||||
import org.jclouds.rest.binders.BindToJsonPayload;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
public class CreateSnapshotOptions implements MapBinder {
|
||||
public static final CreateSnapshotOptions NONE = new CreateSnapshotOptions();
|
||||
|
||||
@Inject
|
||||
private BindToJsonPayload jsonBinder;
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
private boolean force = false;
|
||||
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
|
||||
Map<String, Object> data = Maps.newHashMap(postParams);
|
||||
if (name != null)
|
||||
data.put("display_name", name);
|
||||
if (description != null)
|
||||
data.put("display_description", description);
|
||||
if (force)
|
||||
data.put("force", "true");
|
||||
return jsonBinder.bindToRequest(request, ImmutableMap.of("snapshot", data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
|
||||
throw new IllegalStateException("CreateSnapshot is a POST operation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
if (!(object instanceof CreateSnapshotOptions)) return false;
|
||||
final CreateSnapshotOptions other = CreateSnapshotOptions.class.cast(object);
|
||||
return equal(name, other.name) && equal(description, other.description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(name, description);
|
||||
}
|
||||
|
||||
protected ToStringHelper string() {
|
||||
return toStringHelper("").add("name", name).add("description", description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string().toString();
|
||||
}
|
||||
|
||||
public CreateSnapshotOptions name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CreateSnapshotOptions description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CreateSnapshotOptions force() {
|
||||
this.force = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public boolean isForce() {
|
||||
return force;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
/**
|
||||
* @see CreateSnapshotOptions#getName()
|
||||
*/
|
||||
public static CreateSnapshotOptions name(String name) {
|
||||
return new CreateSnapshotOptions().name(name);
|
||||
}
|
||||
/**
|
||||
* @see CreateSnapshotOptions#getDescription()
|
||||
*/
|
||||
public static CreateSnapshotOptions description(String description) {
|
||||
return new CreateSnapshotOptions().description(description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CreateSnapshotOptions#isForce()
|
||||
*/
|
||||
public static CreateSnapshotOptions force() {
|
||||
return new CreateSnapshotOptions().force();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.options;
|
||||
|
||||
import static com.google.common.base.Objects.equal;
|
||||
import static com.google.common.base.Objects.toStringHelper;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeTypeApi;
|
||||
import org.jclouds.rest.MapBinder;
|
||||
import org.jclouds.rest.binders.BindToJsonPayload;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
public class CreateVolumeOptions implements MapBinder {
|
||||
public static final CreateVolumeOptions NONE = new CreateVolumeOptions();
|
||||
|
||||
@Inject
|
||||
private BindToJsonPayload jsonBinder;
|
||||
|
||||
protected String name;
|
||||
protected String description;
|
||||
protected String volumeType;
|
||||
protected String availabilityZone;
|
||||
protected String snapshotId;
|
||||
protected Map<String, String> metadata = ImmutableMap.of();
|
||||
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
|
||||
Map<String, Object> image = Maps.newHashMap();
|
||||
image.putAll(postParams);
|
||||
if (name != null)
|
||||
image.put("display_name", name);
|
||||
if (description != null)
|
||||
image.put("display_description", description);
|
||||
if (volumeType != null)
|
||||
image.put("volume_type", volumeType);
|
||||
if (availabilityZone != null)
|
||||
image.put("availability_zone", availabilityZone);
|
||||
if (snapshotId != null)
|
||||
image.put("snapshot_id", snapshotId);
|
||||
if (!metadata.isEmpty())
|
||||
image.put("metadata", metadata);
|
||||
return jsonBinder.bindToRequest(request, ImmutableMap.of("volume", image));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
|
||||
throw new IllegalStateException("CreateVolume is a POST operation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
if (!(object instanceof CreateVolumeOptions)) return false;
|
||||
final CreateVolumeOptions other = CreateVolumeOptions.class.cast(object);
|
||||
return equal(volumeType, other.volumeType) && equal(availabilityZone, other.availabilityZone) && equal(snapshotId, other.snapshotId)
|
||||
&& equal(name, other.name) && equal(description, other.description) && equal(metadata, other.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(volumeType, availabilityZone, snapshotId, name, description, metadata);
|
||||
}
|
||||
|
||||
protected ToStringHelper string() {
|
||||
return toStringHelper("").add("volumeType", volumeType).add("availabilityZone", availabilityZone)
|
||||
.add("snapshotId", snapshotId).add("name", name).add("description", description).add("metadata", metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom cloud server metadata can also be supplied at launch time. This
|
||||
* metadata is stored in the API system where it is retrievable by querying
|
||||
* the API for server status. The maximum size of the metadata key and value
|
||||
* is each 255 bytes and the maximum number of key-value pairs that can be
|
||||
* supplied per volume is 5.
|
||||
*/
|
||||
public CreateVolumeOptions metadata(Map<String, String> metadata) {
|
||||
checkNotNull(metadata, "metadata");
|
||||
checkArgument(metadata.size() <= 5,
|
||||
"you cannot have more then 5 metadata values. You specified: " + metadata.size());
|
||||
for (Entry<String, String> entry : metadata.entrySet()) {
|
||||
checkArgument(
|
||||
entry.getKey().getBytes().length < 255,
|
||||
String.format("maximum length of metadata key is 255 bytes. Key specified %s is %d bytes",
|
||||
entry.getKey(), entry.getKey().getBytes().length));
|
||||
checkArgument(entry.getKey().getBytes().length < 255, String.format(
|
||||
"maximum length of metadata value is 255 bytes. Value specified for %s (%s) is %d bytes",
|
||||
entry.getKey(), entry.getValue(), entry.getValue().getBytes().length));
|
||||
}
|
||||
this.metadata = ImmutableMap.copyOf(metadata);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name The name of the Volume
|
||||
*/
|
||||
public CreateVolumeOptions name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param description A description of the Volume
|
||||
*/
|
||||
public CreateVolumeOptions description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see VolumeTypeApi#list()
|
||||
*
|
||||
* @param volumeType The type of Volume to create
|
||||
*/
|
||||
public CreateVolumeOptions volumeType(String volumeType) {
|
||||
this.volumeType = volumeType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param availabilityZone The optional availability zone in which to create a Volume
|
||||
*/
|
||||
public CreateVolumeOptions availabilityZone(String availabilityZone) {
|
||||
this.availabilityZone = availabilityZone;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param snapshotId The optional snapshot from which to create a Volume
|
||||
*/
|
||||
public CreateVolumeOptions snapshotId(String snapshotId) {
|
||||
this.snapshotId = snapshotId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getVolumeType() {
|
||||
return volumeType;
|
||||
}
|
||||
|
||||
public String getAvailabilityZone() {
|
||||
return availabilityZone;
|
||||
}
|
||||
|
||||
public String getSnapshotId() {
|
||||
return snapshotId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
/**
|
||||
* @see CreateVolumeOptions#getName()
|
||||
*/
|
||||
public static CreateVolumeOptions name(String name) {
|
||||
return new CreateVolumeOptions().name(name);
|
||||
}
|
||||
/**
|
||||
* @see CreateVolumeOptions#getDescription()
|
||||
*/
|
||||
public static CreateVolumeOptions description(String description) {
|
||||
return new CreateVolumeOptions().description(description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CreateVolumeOptions#getVolumeType()
|
||||
*/
|
||||
public static CreateVolumeOptions volumeType(String volumeType) {
|
||||
return new CreateVolumeOptions().volumeType(volumeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CreateVolumeOptions#getAvailabilityZone()
|
||||
*/
|
||||
public static CreateVolumeOptions availabilityZone(String availabilityZone) {
|
||||
return new CreateVolumeOptions().availabilityZone(availabilityZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CreateVolumeOptions#getSnapshotId()
|
||||
*/
|
||||
public static CreateVolumeOptions snapshotId(String snapshotId) {
|
||||
return new CreateVolumeOptions().snapshotId(snapshotId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CreateVolumeOptions#getMetadata()
|
||||
*/
|
||||
public static CreateVolumeOptions metadata(Map<String, String> metadata) {
|
||||
return new CreateVolumeOptions().metadata(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.jclouds.openstack.cinder.v1.CinderApiMetadata
|
|
@ -0,0 +1,303 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.features;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.date.DateService;
|
||||
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.openstack.cinder.v1.domain.Snapshot;
|
||||
import org.jclouds.openstack.cinder.v1.domain.Volume;
|
||||
import org.jclouds.openstack.cinder.v1.internal.BaseCinderApiExpectTest;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateSnapshotOptions;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Tests SnapshotApi Guice wiring and parsing
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Test(groups = "unit", testName = "SnapshotApiExpectTest")
|
||||
public class SnapshotApiExpectTest extends BaseCinderApiExpectTest {
|
||||
private DateService dateService = new SimpleDateFormatDateService();
|
||||
|
||||
public void testListSnapshots() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/snapshot_list_simple.json")).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
Set<? extends Snapshot> snapshots = api.list().toImmutableSet();
|
||||
assertEquals(snapshots, ImmutableSet.of(testSnapshot()));
|
||||
}
|
||||
|
||||
public void testListSnapshotsFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
Set<? extends Snapshot> snapshots = api.list().toImmutableSet();
|
||||
assertTrue(snapshots.isEmpty());
|
||||
}
|
||||
|
||||
public void testListSnapshotsInDetail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots/detail");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/snapshot_list_details.json")).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
Set<? extends Snapshot> snapshots = api.listInDetail().toImmutableSet();
|
||||
assertEquals(snapshots, ImmutableSet.of(testSnapshot()));
|
||||
|
||||
// double-check individual fields
|
||||
Snapshot snappy = Iterables.getOnlyElement(snapshots);
|
||||
assertEquals(snappy.getId(), "67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
assertEquals(snappy.getVolumeId(), "ea6f70ef-2784-40b9-9d14-d7f33c507c3f");
|
||||
assertEquals(snappy.getStatus(), Volume.Status.AVAILABLE);
|
||||
assertEquals(snappy.getDescription(), "jclouds test snapshot");
|
||||
assertEquals(snappy.getName(), "jclouds-test-snapshot");
|
||||
assertEquals(snappy.getSize(), 1);
|
||||
}
|
||||
|
||||
public void testListSnapshotsInDetailFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots/detail");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
Set<? extends Snapshot> snapshots = api.listInDetail().toImmutableSet();
|
||||
assertTrue(snapshots.isEmpty());
|
||||
}
|
||||
|
||||
public void testGetSnapshot() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots/67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/snapshot_get.json")).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
Snapshot snapshot = api.get("67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
assertEquals(snapshot, testSnapshot());
|
||||
}
|
||||
|
||||
public void testGetSnapshotFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots/67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
assertNull(api.get("67d03df1-ce5d-4ba7-adbe-492ceb80170b"));
|
||||
}
|
||||
|
||||
public void testCreateSnapshot() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint)
|
||||
.method("POST")
|
||||
.payload(payloadFromResourceWithContentType("/snapshot_create.json", MediaType.APPLICATION_JSON))
|
||||
.build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/snapshot_create_response.json")).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
CreateSnapshotOptions options = CreateSnapshotOptions.Builder
|
||||
.name("jclouds-test-snapshot")
|
||||
.description("jclouds test snapshot")
|
||||
.force();
|
||||
|
||||
Snapshot snapshot = api.create("ea6f70ef-2784-40b9-9d14-d7f33c507c3f", options);
|
||||
assertEquals(snapshot, testSnapshotCreate());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||
public void testCreateSnapshotVolumeNotFoundFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint)
|
||||
.method("POST")
|
||||
.payload(payloadFromResourceWithContentType("/snapshot_create.json", MediaType.APPLICATION_JSON))
|
||||
.build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
CreateSnapshotOptions options = CreateSnapshotOptions.Builder
|
||||
.name("jclouds-test-snapshot")
|
||||
.description("jclouds test snapshot")
|
||||
.force();
|
||||
|
||||
api.create("ea6f70ef-2784-40b9-9d14-d7f33c507c3f", options);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testCreateSnapshotVolumeIllegalStateFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint)
|
||||
.method("POST")
|
||||
.payload(payloadFromResourceWithContentType("/snapshot_create.json", MediaType.APPLICATION_JSON))
|
||||
.build(),
|
||||
HttpResponse.builder()
|
||||
.statusCode(400)
|
||||
.payload("{\"badRequest\": {\"message\": \"Invalid volume: must be available\", \"code\": 400}}")
|
||||
.build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
CreateSnapshotOptions options = CreateSnapshotOptions.Builder
|
||||
.name("jclouds-test-snapshot")
|
||||
.description("jclouds test snapshot")
|
||||
.force();
|
||||
|
||||
api.create("ea6f70ef-2784-40b9-9d14-d7f33c507c3f", options);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void testCreateSnapshotFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint)
|
||||
.method("POST")
|
||||
.payload(payloadFromResourceWithContentType("/snapshot_create.json", MediaType.APPLICATION_JSON))
|
||||
.build(),
|
||||
HttpResponse.builder().statusCode(401).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
CreateSnapshotOptions options = CreateSnapshotOptions.Builder
|
||||
.name("jclouds-test-snapshot")
|
||||
.description("jclouds test snapshot")
|
||||
.force();
|
||||
|
||||
api.create("ea6f70ef-2784-40b9-9d14-d7f33c507c3f", options);
|
||||
}
|
||||
|
||||
public void testDeleteSnapshot() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots/67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).method("DELETE").build(),
|
||||
HttpResponse.builder().statusCode(200).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
assertTrue(api.delete("67d03df1-ce5d-4ba7-adbe-492ceb80170b"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void testDeleteSnapshotFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots/67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).method("DELETE").build(),
|
||||
HttpResponse.builder().statusCode(401).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
api.delete("67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
}
|
||||
|
||||
public void testDeleteSnapshotNotFoundFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots/67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).method("DELETE").build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
assertFalse(api.delete("67d03df1-ce5d-4ba7-adbe-492ceb80170b"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testDeleteSnapshotIllegalStateFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/snapshots/67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
SnapshotApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).method("DELETE").build(),
|
||||
HttpResponse.builder()
|
||||
.statusCode(400)
|
||||
.payload("{\"badRequest\": {\"message\": \"Invalid volume: Volume Snapshot status must be available or error\", \"code\": 400}}")
|
||||
.build()
|
||||
).getSnapshotApiForZone("RegionOne");
|
||||
|
||||
api.delete("67d03df1-ce5d-4ba7-adbe-492ceb80170b");
|
||||
}
|
||||
|
||||
protected Snapshot testSnapshotCreate() {
|
||||
return Snapshot.builder()
|
||||
.id("67d03df1-ce5d-4ba7-adbe-492ceb80170b")
|
||||
.volumeId("ea6f70ef-2784-40b9-9d14-d7f33c507c3f")
|
||||
.description("jclouds test snapshot")
|
||||
.status(Volume.Status.CREATING)
|
||||
.name("jclouds-test-snapshot")
|
||||
.size(1)
|
||||
.created(dateService.iso8601DateParse("2012-11-02T16:23:27.000000"))
|
||||
.build();
|
||||
}
|
||||
|
||||
protected Snapshot testSnapshot() {
|
||||
return Snapshot.builder()
|
||||
.id("67d03df1-ce5d-4ba7-adbe-492ceb80170b")
|
||||
.volumeId("ea6f70ef-2784-40b9-9d14-d7f33c507c3f")
|
||||
.description("jclouds test snapshot")
|
||||
.status(Volume.Status.AVAILABLE)
|
||||
.name("jclouds-test-snapshot")
|
||||
.size(1)
|
||||
.created(dateService.iso8601DateParse("2012-11-02T16:23:27.000000"))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.features;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.openstack.cinder.v1.domain.Snapshot;
|
||||
import org.jclouds.openstack.cinder.v1.domain.Volume;
|
||||
import org.jclouds.openstack.cinder.v1.internal.BaseCinderApiLiveTest;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateSnapshotOptions;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateVolumeOptions;
|
||||
import org.jclouds.predicates.RetryablePredicate;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Tests behavior of VolumeApi
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Test(groups = "live", testName = "VolumeApiLiveTest", singleThreaded = true)
|
||||
public class VolumeAndSnapshotApiLiveTest extends BaseCinderApiLiveTest {
|
||||
private static final String name = System.getProperty("user.name").replace('.','-').toLowerCase();
|
||||
|
||||
private String zone;
|
||||
|
||||
private VolumeApi volumeApi;
|
||||
private SnapshotApi snapshotApi;
|
||||
|
||||
private Volume testVolume;
|
||||
private Snapshot testSnapshot;
|
||||
|
||||
@BeforeClass(groups = {"integration", "live"})
|
||||
@Override
|
||||
public void setupContext() {
|
||||
super.setupContext();
|
||||
zone = Iterables.getLast(cinder.getApi().getConfiguredZones(), "nova");
|
||||
volumeApi = cinder.getApi().getVolumeApiForZone(zone);
|
||||
snapshotApi = cinder.getApi().getSnapshotApiForZone(zone);
|
||||
}
|
||||
|
||||
@AfterClass(groups = { "integration", "live" })
|
||||
@Override
|
||||
protected void tearDownContext() {
|
||||
if (testSnapshot != null) {
|
||||
assertTrue(snapshotApi.delete(testSnapshot.getId()));
|
||||
assertTrue(new RetryablePredicate<SnapshotApi>(new Predicate<SnapshotApi>() {
|
||||
@Override
|
||||
public boolean apply(SnapshotApi snapshotApi) {
|
||||
return snapshotApi.get(testSnapshot.getId()) == null;
|
||||
}
|
||||
}, 30 * 1000L).apply(snapshotApi));
|
||||
}
|
||||
|
||||
if (testVolume != null) {
|
||||
assertTrue(volumeApi.delete(testVolume.getId()));
|
||||
assertTrue(new RetryablePredicate<VolumeApi>(new Predicate<VolumeApi>() {
|
||||
@Override
|
||||
public boolean apply(VolumeApi volumeApi) {
|
||||
return volumeApi.get(testVolume.getId()) == null;
|
||||
}
|
||||
}, 30 * 1000L).apply(volumeApi));
|
||||
}
|
||||
|
||||
super.tearDownContext();
|
||||
}
|
||||
|
||||
public void testCreateVolume() {
|
||||
CreateVolumeOptions options = CreateVolumeOptions.Builder
|
||||
.name(name)
|
||||
.description("description of test volume")
|
||||
.availabilityZone(zone);
|
||||
testVolume = volumeApi.create(100, options);
|
||||
|
||||
assertTrue(new RetryablePredicate<VolumeApi>(new Predicate<VolumeApi>() {
|
||||
@Override
|
||||
public boolean apply(VolumeApi volumeApi) {
|
||||
return volumeApi.get(testVolume.getId()).getStatus() == Volume.Status.AVAILABLE;
|
||||
}
|
||||
}, 600 * 1000L).apply(volumeApi));
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateVolume")
|
||||
public void testListVolumes() {
|
||||
Set<? extends Volume> volumes = volumeApi.list().toImmutableSet();
|
||||
assertNotNull(volumes);
|
||||
boolean foundIt = false;
|
||||
for (Volume vol : volumes) {
|
||||
Volume details = volumeApi.get(vol.getId());
|
||||
assertNotNull(details);
|
||||
if (Objects.equal(details.getId(), testVolume.getId())) {
|
||||
foundIt = true;
|
||||
}
|
||||
}
|
||||
assertTrue(foundIt, "Failed to find the volume we created in list() response");
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateVolume")
|
||||
public void testListVolumesInDetail() {
|
||||
Set<? extends Volume> volumes = volumeApi.listInDetail().toImmutableSet();
|
||||
assertNotNull(volumes);
|
||||
boolean foundIt = false;
|
||||
for (Volume vol : volumes) {
|
||||
Volume details = volumeApi.get(vol.getId());
|
||||
assertNotNull(details);
|
||||
assertNotNull(details.getId());
|
||||
assertNotNull(details.getCreated());
|
||||
assertTrue(details.getSize() > -1);
|
||||
|
||||
assertEquals(details.getId(), vol.getId());
|
||||
assertEquals(details.getSize(), vol.getSize());
|
||||
assertEquals(details.getName(), vol.getName());
|
||||
assertEquals(details.getDescription(), vol.getDescription());
|
||||
assertEquals(details.getCreated(), vol.getCreated());
|
||||
if (Objects.equal(details.getId(), testVolume.getId())) {
|
||||
foundIt = true;
|
||||
}
|
||||
}
|
||||
assertTrue(foundIt, "Failed to find the volume we previously created in listInDetail() response");
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateVolume")
|
||||
public void testCreateSnapshot() {
|
||||
testSnapshot = snapshotApi.create(
|
||||
testVolume.getId(),
|
||||
CreateSnapshotOptions.Builder.name("jclouds-live-test").description(
|
||||
"jclouds live test snapshot").force());
|
||||
assertNotNull(testSnapshot);
|
||||
assertNotNull(testSnapshot.getId());
|
||||
final String snapshotId = testSnapshot.getId();
|
||||
assertNotNull(testSnapshot.getStatus());
|
||||
assertTrue(testSnapshot.getSize() > -1);
|
||||
assertNotNull(testSnapshot.getCreated());
|
||||
|
||||
assertTrue(new RetryablePredicate<VolumeApi>(new Predicate<VolumeApi>() {
|
||||
@Override
|
||||
public boolean apply(VolumeApi volumeApi) {
|
||||
return snapshotApi.get(snapshotId).getStatus() == Volume.Status.AVAILABLE;
|
||||
}
|
||||
}, 1200 * 1000L).apply(volumeApi));
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateSnapshot")
|
||||
public void testListSnapshots() {
|
||||
Set<? extends Snapshot> snapshots = snapshotApi.list().toImmutableSet();
|
||||
assertNotNull(snapshots);
|
||||
boolean foundIt = false;
|
||||
for (Snapshot snap : snapshots) {
|
||||
Snapshot details = snapshotApi.get(snap.getId());
|
||||
if (Objects.equal(snap.getVolumeId(), testVolume.getId())) {
|
||||
foundIt = true;
|
||||
}
|
||||
assertNotNull(details);
|
||||
assertEquals(details.getId(), snap.getId());
|
||||
assertEquals(details.getVolumeId(), snap.getVolumeId());
|
||||
}
|
||||
assertTrue(foundIt, "Failed to find the snapshot we previously created in listSnapshots() response");
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateSnapshot")
|
||||
public void testListSnapshotsInDetail() {
|
||||
Set<? extends Snapshot> snapshots = snapshotApi.listInDetail().toImmutableSet();
|
||||
assertNotNull(snapshots);
|
||||
boolean foundIt = false;
|
||||
for (Snapshot snap : snapshots) {
|
||||
Snapshot details = snapshotApi.get(snap.getId());
|
||||
if (Objects.equal(snap.getVolumeId(), testVolume.getId())) {
|
||||
foundIt = true;
|
||||
assertSame(details, testSnapshot);
|
||||
}
|
||||
assertSame(details, snap);
|
||||
}
|
||||
|
||||
assertTrue(foundIt, "Failed to find the snapshot we created in listSnapshotsInDetail() response");
|
||||
}
|
||||
|
||||
private void assertSame(Snapshot a, Snapshot b) {
|
||||
assertNotNull(a);
|
||||
assertNotNull(b);
|
||||
assertEquals(a.getId(), b.getId());
|
||||
assertEquals(a.getDescription(), b.getDescription());
|
||||
assertEquals(a.getName(), b.getName());
|
||||
assertEquals(a.getVolumeId(), b.getVolumeId());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.features;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.date.DateService;
|
||||
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.openstack.cinder.v1.domain.Volume;
|
||||
import org.jclouds.openstack.cinder.v1.domain.VolumeAttachment;
|
||||
import org.jclouds.openstack.cinder.v1.internal.BaseCinderApiExpectTest;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateVolumeOptions;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Tests VolumeApi Guice wiring and parsing
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Test(groups = "unit", testName = "VolumeApiExpectTest")
|
||||
public class VolumeApiExpectTest extends BaseCinderApiExpectTest {
|
||||
private DateService dateService = new SimpleDateFormatDateService();
|
||||
|
||||
public void testListVolumes() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_list_simple.json")).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
Set<? extends Volume> volumes = api.list().toImmutableSet();
|
||||
assertEquals(volumes, ImmutableSet.of(testVolume()));
|
||||
}
|
||||
|
||||
public void testListVolumesFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
Set<? extends Volume> volumes = api.list().toImmutableSet();
|
||||
assertTrue(volumes.isEmpty());
|
||||
}
|
||||
|
||||
public void testListVolumesInDetail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes/detail");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_list_details.json")).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
Set<? extends Volume> volumes = api.listInDetail().toImmutableSet();
|
||||
assertEquals(volumes, ImmutableSet.of(testVolume()));
|
||||
}
|
||||
|
||||
public void testListVolumesInDetailFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes/detail");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
Set<? extends Volume> volumes = api.listInDetail().toImmutableSet();
|
||||
assertTrue(volumes.isEmpty());
|
||||
}
|
||||
|
||||
public void testCreateVolume() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint)
|
||||
.method("POST")
|
||||
.payload(payloadFromResourceWithContentType("/volume_create.json", MediaType.APPLICATION_JSON))
|
||||
.build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_create_response.json")).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
CreateVolumeOptions options = CreateVolumeOptions.Builder
|
||||
.name("jclouds-test-volume")
|
||||
.description("description of test volume");
|
||||
Volume volume = api.create(1, options);
|
||||
assertEquals(volume, testVolumeCreate());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||
public void testCreateVolumeFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint)
|
||||
.endpoint(endpoint)
|
||||
.method("POST")
|
||||
.payload(payloadFromResourceWithContentType("/volume_create.json", MediaType.APPLICATION_JSON))
|
||||
.build(),
|
||||
HttpResponse.builder().statusCode(404).payload(payloadFromResource("/volume_create_response.json")).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
CreateVolumeOptions options = CreateVolumeOptions.Builder
|
||||
.name("jclouds-test-volume")
|
||||
.description("description of test volume");
|
||||
api.create(1, options);
|
||||
}
|
||||
|
||||
public void testGetVolume() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes/60761c60-0f56-4499-b522-ff13e120af10");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_get.json")).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
Volume volume = api.get("60761c60-0f56-4499-b522-ff13e120af10");
|
||||
assertEquals(volume, testVolume());
|
||||
// double-check equals()
|
||||
assertEquals(volume.getName(), "test");
|
||||
assertEquals(volume.getZone(), "nova");
|
||||
assertEquals(volume.getStatus(), Volume.Status.IN_USE);
|
||||
assertEquals(volume.getDescription(), "This is a test volume");
|
||||
assertEquals(Iterables.getOnlyElement(volume.getAttachments()), testAttachment());
|
||||
}
|
||||
|
||||
public void testGetVolumeFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes/60761c60-0f56-4499-b522-ff13e120af10");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
assertNull(api.get("60761c60-0f56-4499-b522-ff13e120af10"));
|
||||
}
|
||||
|
||||
public void testDeleteVolume() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes/60761c60-0f56-4499-b522-ff13e120af10");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).method("DELETE").build(),
|
||||
HttpResponse.builder().statusCode(202).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
assertTrue(api.delete("60761c60-0f56-4499-b522-ff13e120af10"));
|
||||
}
|
||||
|
||||
public void testDeleteVolumeFail() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/volumes/60761c60-0f56-4499-b522-ff13e120af10");
|
||||
VolumeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).method("DELETE").build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getVolumeApiForZone("RegionOne");
|
||||
|
||||
assertFalse(api.delete("60761c60-0f56-4499-b522-ff13e120af10"));
|
||||
}
|
||||
|
||||
protected Volume testVolumeCreate() {
|
||||
return Volume.builder()
|
||||
.id("60761c60-0f56-4499-b522-ff13e120af10")
|
||||
.size(1)
|
||||
.name("jclouds-test-volume")
|
||||
.zone("nova")
|
||||
.status(Volume.Status.CREATING)
|
||||
.volumeType("None")
|
||||
.description("description of test volume")
|
||||
.created(dateService.iso8601DateParse("2012-10-29T20:53:28.000000"))
|
||||
.build();
|
||||
}
|
||||
|
||||
protected Volume testVolume() {
|
||||
return Volume.builder()
|
||||
.id("60761c60-0f56-4499-b522-ff13e120af10")
|
||||
.size(1)
|
||||
.name("test")
|
||||
.zone("nova")
|
||||
.status(Volume.Status.IN_USE)
|
||||
.volumeType("None")
|
||||
.description("This is a test volume")
|
||||
.attachments(ImmutableSet.of(testAttachment()))
|
||||
.created(dateService.iso8601DateParse("2012-10-29T20:53:28.000000"))
|
||||
.build();
|
||||
}
|
||||
|
||||
protected VolumeAttachment testAttachment() {
|
||||
return VolumeAttachment.builder()
|
||||
.id("60761c60-0f56-4499-b522-ff13e120af10")
|
||||
.volumeId("60761c60-0f56-4499-b522-ff13e120af10")
|
||||
.serverId("0229a1c1-d54a-4836-8527-2ab28b42e2bb")
|
||||
.device("/dev/vdc")
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.features;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.date.DateService;
|
||||
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.openstack.cinder.v1.domain.VolumeType;
|
||||
import org.jclouds.openstack.cinder.v1.internal.BaseCinderApiExpectTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Tests Guice wiring and parsing of VolumeTypeApi
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Test(groups = "unit", testName = "VolumeTypeApiExpectTest")
|
||||
public class VolumeTypeApiExpectTest extends BaseCinderApiExpectTest {
|
||||
private DateService dateService = new SimpleDateFormatDateService();
|
||||
|
||||
public void testListVolumeTypes() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/types");
|
||||
VolumeTypeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_type_list_simple.json")).build()
|
||||
).getVolumeTypeApiForZone("RegionOne");
|
||||
|
||||
Set<? extends VolumeType> types = api.list().toImmutableSet();
|
||||
assertEquals(types, ImmutableSet.of(testVolumeType()));
|
||||
}
|
||||
|
||||
public void testGetVolumeType() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/types/1");
|
||||
VolumeTypeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_type_get.json")).build()
|
||||
).getVolumeTypeApiForZone("RegionOne");
|
||||
|
||||
VolumeType type = api.get("1");
|
||||
assertEquals(type, testVolumeType());
|
||||
}
|
||||
|
||||
public void testGetVolumeTypeFailNotFound() {
|
||||
URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/types/X");
|
||||
VolumeTypeApi api = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess,
|
||||
authenticatedGET().endpoint(endpoint).build(),
|
||||
HttpResponse.builder().statusCode(404).build()
|
||||
).getVolumeTypeApiForZone("RegionOne");
|
||||
|
||||
assertNull(api.get("X"));
|
||||
}
|
||||
|
||||
public VolumeType testVolumeType() {
|
||||
return VolumeType.builder()
|
||||
.id("1")
|
||||
.name("jclouds-test-1")
|
||||
.created(dateService.iso8601SecondsDateParse("2012-05-10 12:33:06"))
|
||||
.extraSpecs(ImmutableMap.of("test", "value1", "test1", "wibble"))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.features;
|
||||
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.openstack.cinder.v1.domain.VolumeType;
|
||||
import org.jclouds.openstack.cinder.v1.internal.BaseCinderApiLiveTest;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeGroups;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Tests behavior of VolumeTypeApi.
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Test(groups = "live", testName = "VolumeTypeApiLiveTest", singleThreaded = true)
|
||||
public class VolumeTypeApiLiveTest extends BaseCinderApiLiveTest {
|
||||
private VolumeTypeApi volumeTypeApi;
|
||||
private String zone;
|
||||
|
||||
@BeforeGroups(groups = {"integration", "live"})
|
||||
@Override
|
||||
public void setupContext() {
|
||||
super.setupContext();
|
||||
zone = Iterables.getLast(cinder.getApi().getConfiguredZones(), "nova");
|
||||
volumeTypeApi = cinder.getApi().getVolumeTypeApiForZone(zone);
|
||||
}
|
||||
|
||||
@AfterClass(groups = { "integration", "live" })
|
||||
@Override
|
||||
protected void tearDownContext() {
|
||||
super.tearDownContext();
|
||||
}
|
||||
|
||||
public void testListAndGetVolumeTypes() {
|
||||
Set<? extends VolumeType> volumeTypes = volumeTypeApi.list().toImmutableSet();
|
||||
assertNotNull(volumeTypes);
|
||||
|
||||
for (VolumeType vt : volumeTypes) {
|
||||
VolumeType details = volumeTypeApi.get(vt.getId());
|
||||
assertNotNull(details);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.internal;
|
||||
|
||||
import org.jclouds.openstack.cinder.v1.CinderApi;
|
||||
|
||||
/**
|
||||
* Base class for writing Volume Rest Api Expect tests
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class BaseCinderApiExpectTest extends BaseCinderExpectTest<CinderApi> {
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.internal;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.apis.BaseContextLiveTest;
|
||||
import org.jclouds.openstack.cinder.v1.CinderApi;
|
||||
import org.jclouds.openstack.cinder.v1.CinderApiMetadata;
|
||||
import org.jclouds.openstack.cinder.v1.CinderAsyncApi;
|
||||
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.testng.annotations.BeforeGroups;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Tests behavior of CinderApi
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class BaseCinderApiLiveTest extends BaseContextLiveTest<RestContext<CinderApi, CinderAsyncApi>> {
|
||||
|
||||
public BaseCinderApiLiveTest() {
|
||||
provider = "openstack-cinder";
|
||||
}
|
||||
|
||||
protected RestContext<CinderApi, CinderAsyncApi> cinder;
|
||||
|
||||
@BeforeGroups(groups = { "integration", "live" })
|
||||
@Override
|
||||
public void setupContext() {
|
||||
super.setupContext();
|
||||
cinder = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties setupProperties() {
|
||||
Properties props = super.setupProperties();
|
||||
setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
|
||||
return props;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TypeToken<RestContext<CinderApi, CinderAsyncApi>> contextType() {
|
||||
return CinderApiMetadata.CONTEXT_TOKEN;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* 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.openstack.cinder.v1.internal;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture;
|
||||
import org.jclouds.rest.internal.BaseRestApiExpectTest;
|
||||
|
||||
/**
|
||||
* Base class for writing Nova Expect tests
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BaseCinderExpectTest<T> extends BaseRestApiExpectTest<T> {
|
||||
protected HttpRequest keystoneAuthWithUsernameAndPassword;
|
||||
protected HttpRequest keystoneAuthWithUsernameAndPasswordAndTenantName;
|
||||
protected HttpRequest keystoneAuthWithAccessKeyAndSecretKeyAndTenantName;
|
||||
protected String authToken;
|
||||
protected HttpResponse responseWithKeystoneAccess;
|
||||
protected HttpRequest extensionsOfNovaRequest;
|
||||
protected HttpResponse extensionsOfNovaResponse;
|
||||
protected HttpResponse unmatchedExtensionsOfNovaResponse;
|
||||
protected HttpRequest keystoneAuthWithAccessKeyAndSecretKeyAndTenantId;
|
||||
protected String identityWithTenantId;
|
||||
|
||||
public BaseCinderExpectTest() {
|
||||
provider = "openstack-cinder";
|
||||
keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPassword(identity,
|
||||
credential);
|
||||
keystoneAuthWithUsernameAndPasswordAndTenantName = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPasswordAndTenantName(identity,
|
||||
credential);
|
||||
keystoneAuthWithAccessKeyAndSecretKeyAndTenantName = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKeyAndTenantName(identity,
|
||||
credential);
|
||||
keystoneAuthWithAccessKeyAndSecretKeyAndTenantId = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKeyAndTenantId(identity,
|
||||
credential);
|
||||
|
||||
authToken = KeystoneFixture.INSTANCE.getAuthToken();
|
||||
responseWithKeystoneAccess = KeystoneFixture.INSTANCE.responseWithAccess();
|
||||
// now, createContext arg will need tenant prefix
|
||||
identityWithTenantId = KeystoneFixture.INSTANCE.getTenantId() + ":" + identity;
|
||||
identity = KeystoneFixture.INSTANCE.getTenantName() + ":" + identity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpRequestComparisonType compareHttpRequestAsType(HttpRequest input) {
|
||||
return HttpRequestComparisonType.JSON;
|
||||
}
|
||||
|
||||
protected HttpRequest.Builder<?> authenticatedGET() {
|
||||
return HttpRequest.builder()
|
||||
.method("GET")
|
||||
.addHeader("Accept", MediaType.APPLICATION_JSON)
|
||||
.addHeader("X-Auth-Token", authToken);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"snapshot":{"display_name":"jclouds-test-snapshot","volume_id":"ea6f70ef-2784-40b9-9d14-d7f33c507c3f","display_description":"jclouds test snapshot","force":"true"}}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"snapshot": {
|
||||
"status": "creating",
|
||||
"display_name": "jclouds-test-snapshot",
|
||||
"created_at": "2012-11-02T16:23:27.000000",
|
||||
"display_description": "jclouds test snapshot",
|
||||
"volume_id": "ea6f70ef-2784-40b9-9d14-d7f33c507c3f",
|
||||
"id": "67d03df1-ce5d-4ba7-adbe-492ceb80170b",
|
||||
"size": 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"snapshot": {
|
||||
"status": "available",
|
||||
"display_name": "jclouds-test-snapshot",
|
||||
"created_at": "2012-11-02T16:23:27.000000",
|
||||
"display_description": "jclouds test snapshot",
|
||||
"os-extended-snapshot-attributes:progress": "100%",
|
||||
"volume_id": "ea6f70ef-2784-40b9-9d14-d7f33c507c3f",
|
||||
"os-extended-snapshot-attributes:project_id": "cc03fd4f503f4d9c986b381b8abe6af5",
|
||||
"id": "67d03df1-ce5d-4ba7-adbe-492ceb80170b",
|
||||
"size": 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"snapshots": [
|
||||
{
|
||||
"status": "available",
|
||||
"display_name": "jclouds-test-snapshot",
|
||||
"created_at": "2012-11-02T16:23:27.000000",
|
||||
"display_description": "jclouds test snapshot",
|
||||
"os-extended-snapshot-attributes:progress": "100%",
|
||||
"volume_id": "ea6f70ef-2784-40b9-9d14-d7f33c507c3f",
|
||||
"os-extended-snapshot-attributes:project_id": "cc03fd4f503f4d9c986b381b8abe6af5",
|
||||
"id": "67d03df1-ce5d-4ba7-adbe-492ceb80170b",
|
||||
"size": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"snapshots": [
|
||||
{
|
||||
"status": "available",
|
||||
"display_name": "jclouds-test-snapshot",
|
||||
"created_at": "2012-11-02T16:23:27.000000",
|
||||
"display_description": "jclouds test snapshot",
|
||||
"volume_id": "ea6f70ef-2784-40b9-9d14-d7f33c507c3f",
|
||||
"id": "67d03df1-ce5d-4ba7-adbe-492ceb80170b",
|
||||
"size": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"volume":{"display_name":"jclouds-test-volume","display_description":"description of test volume","size":1}}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"volume": {
|
||||
"status": "creating",
|
||||
"display_name": "jclouds-test-volume",
|
||||
"attachments": [],
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2012-10-29T20:53:28.000000",
|
||||
"display_description": "description of test volume",
|
||||
"volume_type": "None",
|
||||
"snapshot_id": null,
|
||||
"metadata": {},
|
||||
"id": "60761c60-0f56-4499-b522-ff13e120af10",
|
||||
"size": 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"volume": {
|
||||
"status": "in-use",
|
||||
"display_name": "test",
|
||||
"attachments": [
|
||||
{
|
||||
"device": "/dev/vdc",
|
||||
"server_id": "0229a1c1-d54a-4836-8527-2ab28b42e2bb",
|
||||
"id": "60761c60-0f56-4499-b522-ff13e120af10",
|
||||
"volume_id": "60761c60-0f56-4499-b522-ff13e120af10"
|
||||
}
|
||||
],
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2012-10-29T20:53:28.000000",
|
||||
"display_description": "This is a test volume",
|
||||
"volume_type": "None",
|
||||
"snapshot_id": null,
|
||||
"metadata": {},
|
||||
"id": "60761c60-0f56-4499-b522-ff13e120af10",
|
||||
"size": 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"volumes": [
|
||||
{
|
||||
"status": "in-use",
|
||||
"display_name": "test",
|
||||
"attachments": [
|
||||
{
|
||||
"device": "/dev/vdc",
|
||||
"server_id": "0229a1c1-d54a-4836-8527-2ab28b42e2bb",
|
||||
"id": "60761c60-0f56-4499-b522-ff13e120af10",
|
||||
"volume_id": "60761c60-0f56-4499-b522-ff13e120af10"
|
||||
}
|
||||
],
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2012-10-29T20:53:28.000000",
|
||||
"display_description": "This is a test volume",
|
||||
"volume_type": "None",
|
||||
"snapshot_id": null,
|
||||
"metadata": {},
|
||||
"id": "60761c60-0f56-4499-b522-ff13e120af10",
|
||||
"size": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"volumes": [
|
||||
{
|
||||
"status": "in-use",
|
||||
"display_name": "test",
|
||||
"attachments": [
|
||||
{
|
||||
"device": "/dev/vdc",
|
||||
"server_id": "0229a1c1-d54a-4836-8527-2ab28b42e2bb",
|
||||
"id": "60761c60-0f56-4499-b522-ff13e120af10",
|
||||
"volume_id": "60761c60-0f56-4499-b522-ff13e120af10"
|
||||
}
|
||||
],
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2012-10-29T20:53:28.000000",
|
||||
"display_description": "This is a test volume",
|
||||
"volume_type": "None",
|
||||
"snapshot_id": null,
|
||||
"metadata": {},
|
||||
"id": "60761c60-0f56-4499-b522-ff13e120af10",
|
||||
"size": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"volume_type": {
|
||||
"name": "jclouds-test-1",
|
||||
"deleted": false,
|
||||
"created_at": "2012-05-10 12:33:06",
|
||||
"updated_at": null,
|
||||
"extra_specs": {
|
||||
"test": "value1",
|
||||
"test1": "wibble"
|
||||
},
|
||||
"deleted_at": null,
|
||||
"id": 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"volume_types": [
|
||||
{
|
||||
"name": "jclouds-test-1",
|
||||
"deleted": false,
|
||||
"created_at": "2012-05-10 12:33:06",
|
||||
"updated_at": null,
|
||||
"extra_specs": {
|
||||
"test": "value1",
|
||||
"test1": "wibble"
|
||||
},
|
||||
"deleted_at": null,
|
||||
"id": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -18,7 +18,8 @@
|
|||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>jclouds-project</artifactId>
|
||||
|
@ -61,5 +62,6 @@
|
|||
<module>fgcp-de</module>
|
||||
<module>abiquo</module>
|
||||
<module>oauth</module>
|
||||
<module>openstack-cinder</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
Loading…
Reference in New Issue