mirror of https://github.com/apache/jclouds.git
Added support for the OpenStack Folsom Cinder Block Storage API.
This commit is contained in:
parent
851e7bf6ec
commit
3292701883
|
@ -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
|
specific language governing permissions and limitations
|
||||||
under the License.
|
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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>jclouds-project</artifactId>
|
<artifactId>jclouds-project</artifactId>
|
||||||
|
@ -61,5 +62,6 @@
|
||||||
<module>fgcp-de</module>
|
<module>fgcp-de</module>
|
||||||
<module>abiquo</module>
|
<module>abiquo</module>
|
||||||
<module>oauth</module>
|
<module>oauth</module>
|
||||||
|
<module>openstack-cinder</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
|
|
Loading…
Reference in New Issue