mirror of https://github.com/apache/jclouds.git
openstack-nova: Adding Admin Actions client to allow extra actions to be performed on servers
This commit is contained in:
parent
e95e6df805
commit
7678c6e776
|
@ -23,6 +23,7 @@ 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.nova.v1_1.extensions.AdminActionsAsyncClient;
|
||||
import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPAsyncClient;
|
||||
import org.jclouds.openstack.nova.v1_1.extensions.HostAdministrationAsyncClient;
|
||||
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairAsyncClient;
|
||||
|
@ -145,4 +146,11 @@ public interface NovaAsyncClient {
|
|||
Optional<ServerWithSecurityGroupsAsyncClient> getServerExtraDataExtensionForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to Server Admin Actions features.
|
||||
*/
|
||||
@Delegate
|
||||
Optional<AdminActionsAsyncClient> getAdminActionsExtensionForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ 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.nova.v1_1.extensions.AdminActionsClient;
|
||||
import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient;
|
||||
import org.jclouds.openstack.nova.v1_1.extensions.HostAdministrationClient;
|
||||
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
|
||||
|
@ -148,4 +149,12 @@ public interface NovaClient {
|
|||
Optional<ServerWithSecurityGroupsClient> getServerExtraDataExtensionForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
|
||||
/**
|
||||
* Provides asynchronous access to Server Admin Actions features.
|
||||
*/
|
||||
@Delegate
|
||||
Optional<AdminActionsClient> getAdminActionsExtensionForZone(
|
||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ public class NovaRestClientModule extends RestClientModule<NovaClient, NovaAsync
|
|||
.put(VolumeClient.class, VolumeAsyncClient.class)
|
||||
.put(VirtualInterfaceClient.class, VirtualInterfaceAsyncClient.class)
|
||||
.put(ServerWithSecurityGroupsClient.class, ServerWithSecurityGroupsAsyncClient.class)
|
||||
.put(AdminActionsClient.class, AdminActionsAsyncClient.class)
|
||||
.build();
|
||||
|
||||
public NovaRestClientModule() {
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* 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.nova.v1_1.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
|
||||
/**
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
public enum BackupType {
|
||||
DAILY, WEEKLY;
|
||||
|
||||
public String value() {
|
||||
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value();
|
||||
}
|
||||
|
||||
public static BackupType fromValue(String backupType) {
|
||||
return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(backupType, "backupType")));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/**
|
||||
* 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.nova.v1_1.extensions;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
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.concurrent.Timeout;
|
||||
import org.jclouds.openstack.filters.AuthenticateRequest;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.BackupType;
|
||||
import org.jclouds.openstack.nova.v1_1.functions.ParseImageIdFromLocationHeader;
|
||||
import org.jclouds.openstack.nova.v1_1.options.CreateBackupOfServerOptions;
|
||||
import org.jclouds.openstack.services.Extension;
|
||||
import org.jclouds.openstack.services.ServiceType;
|
||||
import org.jclouds.rest.annotations.ExceptionParser;
|
||||
import org.jclouds.rest.annotations.Payload;
|
||||
import org.jclouds.rest.annotations.PayloadParam;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Provide access to Admin Server Actions via REST API
|
||||
*
|
||||
* @author Adam Lowe
|
||||
* @see org.jclouds.openstack.nova.v1_1.extensions.AdminActionsClient
|
||||
*/
|
||||
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS)
|
||||
@SkipEncoding( { '/', '=' })
|
||||
@RequestFilters(AuthenticateRequest.class)
|
||||
@Path("/servers/{id}/action")
|
||||
public interface AdminActionsAsyncClient {
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#suspendServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("{\"suspend\":null}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> suspendServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#resumeServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("{\"resume\":null}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> resumeServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#migrateServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("{\"migrate\":null}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> migrateServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#suspendServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("{\"lock\":null}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> lockServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#unlockServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("{\"unlock\":null}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> unlockServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#resetNetworkOfServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("{\"resetNetwork\":null}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> resetNetworkOfServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#createBackupOfServer
|
||||
*/
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("%7B\"createBackup\":%7B\"name\":\"{name}\",\"backup_type\":\"{backup_type}\",\"rotation\":{rotation}%7D%7D")
|
||||
@ExceptionParser(MapHttp4xxCodesToExceptions.class)
|
||||
@ResponseParser(ParseImageIdFromLocationHeader.class)
|
||||
ListenableFuture<String> createBackupOfServer(@PathParam("id") String id,
|
||||
@PayloadParam("name") String imageName,
|
||||
@PayloadParam("backup_type") BackupType backupType,
|
||||
@PayloadParam("rotation") int rotation,
|
||||
CreateBackupOfServerOptions... options);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#pauseServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("{\"pause\":null}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> pauseServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#unpauseServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("{\"unpause\":null}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> unpauseServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#suspendServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Payload("{\"injectNetworkInfo\":null}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> injectNetworkInfoIntoServer(@PathParam("id") String id);
|
||||
|
||||
/**
|
||||
* @see AdminActionsClient#migrateServer(String)
|
||||
*/
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
@Payload("%7B\"os-migrateLive\":%7B\"host\":\"{host}\",\"block_migration\":\"{bm}\",\"disk_over_commit\":\"{doc}\"%7D%7D")
|
||||
ListenableFuture<Boolean> liveMigrateServer(@PathParam("id") String id,
|
||||
@PayloadParam("host") String host,
|
||||
@PayloadParam("bm") boolean blockMigration,
|
||||
@PayloadParam("doc") boolean diskOverCommit);
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* 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.nova.v1_1.extensions;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.BackupType;
|
||||
import org.jclouds.openstack.nova.v1_1.options.CreateBackupOfServerOptions;
|
||||
import org.jclouds.openstack.services.Extension;
|
||||
import org.jclouds.openstack.services.ServiceType;
|
||||
|
||||
/**
|
||||
* Provide additional actions for servers:
|
||||
* 'suspend', 'resume', 'migrate', 'lock', 'unlock', 'resetNetwork', 'createBackup', 'pause', 'migrateLive',
|
||||
* 'injectNetworkInfo', 'unpause'
|
||||
*
|
||||
* @author Adam Lowe
|
||||
* @see org.jclouds.openstack.nova.v1_1.extensions.AdminActionsAsyncClient
|
||||
*/
|
||||
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS)
|
||||
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
||||
public interface AdminActionsClient {
|
||||
|
||||
/**
|
||||
* Suspend a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean suspendServer(String id);
|
||||
|
||||
/**
|
||||
* Resume a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean resumeServer(String id);
|
||||
|
||||
/**
|
||||
* Migrate a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean migrateServer(String id);
|
||||
|
||||
/**
|
||||
* Lock a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean lockServer(String id);
|
||||
|
||||
/**
|
||||
* Unlock a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean unlockServer(String id);
|
||||
|
||||
/**
|
||||
* Reset network of a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean resetNetworkOfServer(String id);
|
||||
|
||||
/**
|
||||
* Create backup of a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
* @param imageName the name of the image to create
|
||||
* @param backupType the type of backup
|
||||
* @param rotation the number of images to retain (0 to simply overwrite)
|
||||
* @param options optional rotation and/or metadata parameters
|
||||
* @return the id of the newly created image
|
||||
*/
|
||||
String createBackupOfServer(String id, String imageName, BackupType backupType, int rotation, CreateBackupOfServerOptions... options);
|
||||
|
||||
/**
|
||||
* Pause a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean pauseServer(String id);
|
||||
|
||||
/**
|
||||
* Unpause a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean unpauseServer(String id);
|
||||
|
||||
|
||||
/**
|
||||
* Live migrate a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean liveMigrateServer(String id, String host, boolean blockMigration, boolean diskOverCommit);
|
||||
|
||||
/**
|
||||
* Inject network info into a server.
|
||||
*
|
||||
* @param id id of the server
|
||||
*/
|
||||
Boolean injectNetworkInfoIntoServer(String id);
|
||||
}
|
|
@ -85,5 +85,8 @@ public interface ExtensionNamespaces {
|
|||
* Instance rescue mode
|
||||
*/
|
||||
public static final String RESCUE = "http://docs.openstack.org/ext/rescue/api/v1.1";
|
||||
|
||||
/**
|
||||
* Admin Action extension
|
||||
*/
|
||||
public static final String ADMIN_ACTIONS = "http://docs.openstack.org/ext/admin-actions/api/v1.1";
|
||||
}
|
||||
|
|
|
@ -72,6 +72,8 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
|
|||
URI.create("http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1"))
|
||||
.put(URI.create(ExtensionNamespaces.CREATESERVEREXT),
|
||||
URI.create("http://docs.openstack.org/compute/ext/createserverext/api/v1.1"))
|
||||
.put(URI.create(ExtensionNamespaces.ADMIN_ACTIONS),
|
||||
URI.create("http://docs.openstack.org/compute/ext/admin-actions/api/v1.1"))
|
||||
.build();
|
||||
|
||||
@Inject
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* 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.nova.v1_1.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 CreateBackupOfServerOptions implements MapBinder {
|
||||
public static final CreateBackupOfServerOptions NONE = new CreateBackupOfServerOptions();
|
||||
|
||||
@Inject
|
||||
protected BindToJsonPayload jsonBinder;
|
||||
|
||||
private Map<String, String> metadata = ImmutableMap.of();
|
||||
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
|
||||
Map<String, Object> data = Maps.newHashMap();
|
||||
data.putAll(postParams);
|
||||
data.put("metadata", metadata);
|
||||
return jsonBinder.bindToRequest(request, ImmutableMap.of("createBackup", data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
|
||||
throw new IllegalStateException("createBackupOfServer is a POST operation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
if (!(object instanceof CreateBackupOfServerOptions)) return false;
|
||||
final CreateBackupOfServerOptions other = CreateBackupOfServerOptions.class.cast(object);
|
||||
return equal(metadata, other.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(metadata);
|
||||
}
|
||||
|
||||
protected ToStringHelper string() {
|
||||
return toStringHelper("").add("metadata", metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string().toString();
|
||||
}
|
||||
|
||||
/** @see #getMetadata() */
|
||||
public CreateBackupOfServerOptions metadata(Map<String, String> metadata) {
|
||||
this.metadata = metadata;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra image properties to include
|
||||
*/
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
/**
|
||||
* @see CreateBackupOfServerOptions#getMetadata()
|
||||
*/
|
||||
public static CreateBackupOfServerOptions metadata(Map<String, String> metadata) {
|
||||
return new CreateBackupOfServerOptions().metadata(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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.nova.v1_1.extensions;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.BackupType;
|
||||
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
|
||||
import org.jclouds.openstack.nova.v1_1.options.CreateBackupOfServerOptions;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
|
||||
/**
|
||||
* Tests parsing and guice wiring of AdminActionsClient
|
||||
*
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Test(groups = "unit", testName = "AdminActionsClientExpectTest")
|
||||
public class AdminActionsClientExpectTest extends BaseNovaClientExpectTest {
|
||||
|
||||
public void testSuspend() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "suspend").build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.suspendServer("1"));
|
||||
}
|
||||
|
||||
public void testSuspendFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "suspend").build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.suspendServer("1"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void testSuspendFailsNotAuthorized() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "suspend").build(),
|
||||
standardResponseBuilder(403).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
client.suspendServer("1");
|
||||
}
|
||||
|
||||
public void testResume() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "resume").build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.resumeServer("1"));
|
||||
}
|
||||
|
||||
public void testResumeFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "resume").build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.resumeServer("1"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void testResumeFailsNotAuthorized() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "resume").build(),
|
||||
standardResponseBuilder(403).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
client.resumeServer("1");
|
||||
}
|
||||
|
||||
public void testLock() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "lock").build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.lockServer("1"));
|
||||
}
|
||||
|
||||
public void testLockFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "lock").build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.lockServer("1"));
|
||||
}
|
||||
|
||||
public void testUnlock() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "unlock").build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.unlockServer("1"));
|
||||
}
|
||||
|
||||
public void testUnlockFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "unlock").build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.unlockServer("1"));
|
||||
}
|
||||
|
||||
public void testPause() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "pause").build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.pauseServer("1"));
|
||||
}
|
||||
|
||||
public void testPauseFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "pause").build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.pauseServer("1"));
|
||||
}
|
||||
|
||||
public void testUnpause() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "unpause").build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.unpauseServer("1"));
|
||||
}
|
||||
|
||||
public void testUnpauseFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "unpause").build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.unpauseServer("1"));
|
||||
}
|
||||
|
||||
public void testMigrateServer() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "migrate").build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.migrateServer("1"));
|
||||
}
|
||||
|
||||
|
||||
public void testMigrateServerFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "migrate").build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.migrateServer("1"));
|
||||
}
|
||||
|
||||
public void testResetNetworkOfServer() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "resetNetwork").build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.resetNetworkOfServer("1"));
|
||||
}
|
||||
|
||||
public void testResetNetworkOfServerFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "resetNetwork").build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.resetNetworkOfServer("1"));
|
||||
}
|
||||
|
||||
public void testInjectNetworkInfoIntoServer() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "injectNetworkInfo").build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.injectNetworkInfoIntoServer("1"));
|
||||
}
|
||||
|
||||
public void testInjectNetworkInfoIntoServerFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "injectNetworkInfo").build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.injectNetworkInfoIntoServer("1"));
|
||||
}
|
||||
|
||||
public void testBackupServer() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardRequestBuilder(endpoint).method("POST")
|
||||
.payload(payloadFromStringWithContentType("{\"createBackup\":{\"backup_type\":\"weekly\",\"rotation\":\"3\",\"name\":\"mybackup\",\"metadata\":{\"some\":\"data or other\"}}}", MediaType.APPLICATION_JSON)).build(),
|
||||
standardResponseBuilder(202).headers(ImmutableMultimap.of("Location", "http://172.16.89.149:8774/v2/images/1976b3b3-409a-468d-b16c-a9172c341b46")).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
String imageId = client.createBackupOfServer("1", "mybackup", BackupType.WEEKLY, 3, CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("some", "data or other")));
|
||||
assertEquals(imageId, "1976b3b3-409a-468d-b16c-a9172c341b46");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||
public void testBackupServerFailNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardRequestBuilder(endpoint).method("POST")
|
||||
.payload(payloadFromStringWithContentType("{\"createBackup\":{\"backup_type\":\"weekly\",\"rotation\":\"3\",\"name\":\"mybackup\",\"metadata\":{\"some\":\"data or other\"}}}", MediaType.APPLICATION_JSON)).build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
client.createBackupOfServer("1", "mybackup", BackupType.WEEKLY, 3, CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("some", "data or other")));
|
||||
}
|
||||
|
||||
public void testLiveMigrateServer() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "GONNAOVERWRITE")
|
||||
.payload(payloadFromStringWithContentType("{\"os-migrateLive\":{\"host\":\"bighost\",\"block_migration\":\"true\",\"disk_over_commit\":\"false\"}}", MediaType.APPLICATION_JSON)).build(),
|
||||
standardResponseBuilder(202).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertTrue(client.liveMigrateServer("1", "bighost", true, false));
|
||||
}
|
||||
|
||||
public void testLiveMigrateServerFailsNotFound() {
|
||||
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
|
||||
AdminActionsClient client = requestsSendResponses(
|
||||
keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||
standardActionRequestBuilderVoidResponse(endpoint, "GONNAOVERWRITE")
|
||||
.payload(payloadFromStringWithContentType("{\"os-migrateLive\":{\"host\":\"bighost\",\"block_migration\":\"true\",\"disk_over_commit\":\"false\"}}", MediaType.APPLICATION_JSON)).build(),
|
||||
standardResponseBuilder(404).build()
|
||||
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
|
||||
|
||||
assertFalse(client.liveMigrateServer("1", "bighost", true, false));
|
||||
}
|
||||
|
||||
protected HttpRequest.Builder standardActionRequestBuilderVoidResponse(URI endpoint, String actionName) {
|
||||
return HttpRequest.builder().method("POST")
|
||||
.headers(ImmutableMultimap.of("X-Auth-Token", authToken))
|
||||
.payload(payloadFromStringWithContentType("{\"" + actionName + "\":null}", MediaType.APPLICATION_JSON))
|
||||
.endpoint(endpoint);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
/**
|
||||
* 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.nova.v1_1.extensions;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.BackupType;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Image;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.features.ExtensionClient;
|
||||
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
|
||||
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
|
||||
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
|
||||
import org.jclouds.openstack.nova.v1_1.options.CreateBackupOfServerOptions;
|
||||
import org.testng.annotations.AfterGroups;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeGroups;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Tests behavior of HostAdministrationClient
|
||||
*
|
||||
* TODO test migration methods
|
||||
*
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Test(groups = "live", testName = "AdminActionsClientLiveTest", singleThreaded = true)
|
||||
public class AdminActionsClientLiveTest extends BaseNovaClientLiveTest {
|
||||
private ImageClient imageClient;
|
||||
private ServerClient serverClient;
|
||||
private ExtensionClient extensionClient;
|
||||
private Optional<AdminActionsClient> clientOption;
|
||||
private String zone;
|
||||
|
||||
private String testServerId;
|
||||
private String backupImageId;
|
||||
|
||||
@BeforeGroups(groups = {"integration", "live"})
|
||||
@Override
|
||||
public void setupContext() {
|
||||
super.setupContext();
|
||||
zone = Iterables.getLast(novaContext.getApi().getConfiguredZones(), "nova");
|
||||
serverClient = novaContext.getApi().getServerClientForZone(zone);
|
||||
extensionClient = novaContext.getApi().getExtensionClientForZone(zone);
|
||||
imageClient = novaContext.getApi().getImageClientForZone(zone);
|
||||
clientOption = novaContext.getApi().getAdminActionsExtensionForZone(zone);
|
||||
if (clientOption.isPresent()) {
|
||||
testServerId = createServerInZone(zone).getId();
|
||||
}
|
||||
}
|
||||
|
||||
@AfterGroups(groups = "live", alwaysRun = true)
|
||||
@Override
|
||||
protected void tearDown() {
|
||||
if (clientOption.isPresent()) {
|
||||
if (testServerId != null) {
|
||||
assertTrue(novaContext.getApi().getServerClientForZone(zone).deleteServer(testServerId));
|
||||
}
|
||||
if (backupImageId != null) {
|
||||
imageClient.deleteImage(backupImageId);
|
||||
}
|
||||
}
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@AfterMethod(alwaysRun = true)
|
||||
public void ensureServerIsActiveAgain() {
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
|
||||
}
|
||||
|
||||
public void testSuspendAndResume() {
|
||||
if (clientOption.isPresent()) {
|
||||
AdminActionsClient client = clientOption.get();
|
||||
|
||||
// Suspend-resume
|
||||
try {
|
||||
client.resumeServer(testServerId);
|
||||
fail("Resumed an active server!");
|
||||
} catch (HttpResponseException e) {
|
||||
}
|
||||
assertTrue(client.suspendServer(testServerId));
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.SUSPENDED);
|
||||
try {
|
||||
client.suspendServer(testServerId);
|
||||
fail("Suspended an already suspended server!");
|
||||
} catch (HttpResponseException e) {
|
||||
}
|
||||
assertTrue(client.resumeServer(testServerId));
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
|
||||
try {
|
||||
client.resumeServer(testServerId);
|
||||
fail("Resumed an already resumed server!");
|
||||
} catch (HttpResponseException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testLockAndUnlock() {
|
||||
if (clientOption.isPresent()) {
|
||||
AdminActionsClient client = clientOption.get();
|
||||
|
||||
// TODO should we be able to double-lock (as it were)
|
||||
assertTrue(client.unlockServer(testServerId));
|
||||
assertTrue(client.unlockServer(testServerId));
|
||||
assertTrue(client.lockServer(testServerId));
|
||||
assertTrue(client.lockServer(testServerId));
|
||||
assertTrue(client.unlockServer(testServerId));
|
||||
assertTrue(client.unlockServer(testServerId));
|
||||
}
|
||||
}
|
||||
|
||||
public void testResetNetworkAndInjectNetworkInfo() {
|
||||
if (clientOption.isPresent()) {
|
||||
AdminActionsClient client = clientOption.get();
|
||||
assertTrue(client.resetNetworkOfServer(testServerId));
|
||||
assertTrue(client.injectNetworkInfoIntoServer(testServerId));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPauseAndUnpause() {
|
||||
if (clientOption.isPresent()) {
|
||||
AdminActionsClient client = clientOption.get();
|
||||
|
||||
// Unlock and lock (double-checking error contitions too)
|
||||
try {
|
||||
client.unpauseServer(testServerId);
|
||||
fail("Unpaused active server!");
|
||||
} catch (HttpResponseException e) {
|
||||
}
|
||||
assertTrue(client.pauseServer(testServerId));
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.PAUSED);
|
||||
try {
|
||||
client.pauseServer(testServerId);
|
||||
fail("paused a paused server!");
|
||||
} catch (HttpResponseException e) {
|
||||
}
|
||||
assertTrue(client.unpauseServer(testServerId));
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
|
||||
try {
|
||||
client.unpauseServer(testServerId);
|
||||
fail("Unpaused a server we just unpaused!");
|
||||
} catch (HttpResponseException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateBackupOfServer() throws InterruptedException {
|
||||
if (clientOption.isPresent()) {
|
||||
backupImageId = clientOption.get().createBackupOfServer(testServerId, "jclouds-test-backup", BackupType.DAILY, 0,
|
||||
CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("test", "metadata")));
|
||||
|
||||
assertNotNull(backupImageId);
|
||||
|
||||
// If we don't have extended task status, we'll have to wait here!
|
||||
if (extensionClient.getExtensionByAlias("OS-EXT-STS") == null) {
|
||||
Thread.sleep(30000);
|
||||
}
|
||||
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
|
||||
|
||||
Image backupImage = imageClient.getImage(backupImageId);
|
||||
assertEquals(backupImage.getId(), backupImageId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -83,15 +83,19 @@ public class BaseNovaClientLiveTest extends BaseComputeServiceContextLiveTest {
|
|||
protected Server createServerInZone(String zoneId) {
|
||||
ServerClient serverClient = novaContext.getApi().getServerClientForZone(zoneId);
|
||||
Server server = serverClient.createServer("test", imageIdForZone(zoneId), flavorRefForZone(zoneId));
|
||||
blockUntilServerActive(server.getId(), serverClient);
|
||||
blockUntilServerInState(server.getId(), serverClient, Status.ACTIVE);
|
||||
return server;
|
||||
}
|
||||
|
||||
private void blockUntilServerActive(String serverId, ServerClient client) {
|
||||
/**
|
||||
* Will block until the requested server is in the correct state, if Extended Server Status extension is loaded
|
||||
* this will continue to block while any task is in progress.
|
||||
*/
|
||||
protected void blockUntilServerInState(String serverId, ServerClient client, Status status) {
|
||||
Server currentDetails = null;
|
||||
for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != Status.ACTIVE; currentDetails = client
|
||||
for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != status || currentDetails.getTaskState() != null; currentDetails = client
|
||||
.getServer(serverId)) {
|
||||
System.out.printf("blocking on status active%n%s%n", currentDetails);
|
||||
System.out.printf("blocking on status %s%n%s%n", status, currentDetails);
|
||||
try {
|
||||
Thread.sleep(5 * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
|
|
|
@ -1,123 +1,281 @@
|
|||
{"extensions": [
|
||||
{
|
||||
"extensions": [{
|
||||
"updated": "2011-06-09T00:00:00+00:00",
|
||||
"name": "Multinic",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/multinic/api/v1.1",
|
||||
"alias": "NMN",
|
||||
"description": "Multiple network support"
|
||||
}, {
|
||||
"updated": "2011-06-29T00:00:00+00:00",
|
||||
"name": "Hosts",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/hosts/api/v1.1",
|
||||
"alias": "os-hosts",
|
||||
"description": "Host administration"
|
||||
}, {
|
||||
"updated": "2011-03-25T00:00:00+00:00",
|
||||
"name": "Volumes",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/volumes/api/v1.1",
|
||||
"alias": "os-volumes",
|
||||
"description": "Volumes support"
|
||||
}, {
|
||||
"updated": "2011-05-25 16:12:21.656723",
|
||||
"name": "Admin Controller",
|
||||
"links": [],
|
||||
"namespace": "https:TODO/",
|
||||
"alias": "ADMIN",
|
||||
"description": "The Admin API Extension"
|
||||
}, {
|
||||
"updated": "2011-08-08T00:00:00+00:00",
|
||||
"name": "Quotas",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/quotas-sets/api/v1.1",
|
||||
"alias": "os-quota-sets",
|
||||
"description": "Quotas management support"
|
||||
}, {
|
||||
"updated": "2011-08-24T00:00:00+00:00",
|
||||
"name": "VolumeTypes",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/volume_types/api/v1.1",
|
||||
"alias": "os-volume-types",
|
||||
"description": "Volume types support"
|
||||
}, {
|
||||
"updated": "2011-06-23T00:00:00+00:00",
|
||||
"name": "FlavorExtraSpecs",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/flavor_extra_specs/api/v1.1",
|
||||
"alias": "os-flavor-extra-specs",
|
||||
"description": "Instance type (flavor) extra specs"
|
||||
}, {
|
||||
"updated": "2011-09-14T00:00:00+00:00",
|
||||
"name": "FlavorExtraData",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/flavor_extra_data/api/v1.1",
|
||||
"alias": "os-flavor-extra-data",
|
||||
"description": "Provide additional data for flavors"
|
||||
}, {
|
||||
"updated": "2011-08-17T00:00:00+00:00",
|
||||
"name": "VirtualInterfaces",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/virtual_interfaces/api/v1.1",
|
||||
"alias": "virtual_interfaces",
|
||||
"description": "Virtual interface support"
|
||||
}, {
|
||||
"updated": "2011-07-19T00:00:00+00:00",
|
||||
"name": "Createserverext",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/createserverext/api/v1.1",
|
||||
"alias": "os-create-server-ext",
|
||||
"description": "Extended support to the Create Server v1.1 API"
|
||||
}, {
|
||||
"updated": "2011-08-08T00:00:00+00:00",
|
||||
"name": "Keypairs",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/keypairs/api/v1.1",
|
||||
"alias": "os-keypairs",
|
||||
"description": "Keypair Support"
|
||||
}, {
|
||||
"updated": "2011-08-25T00:00:00+00:00",
|
||||
"name": "VSAs",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/vsa/api/v1.1",
|
||||
"alias": "zadr-vsa",
|
||||
"description": "Virtual Storage Arrays support"
|
||||
}, {
|
||||
"updated": "2011-08-19T00:00:00+00:00",
|
||||
"name": "SimpleTenantUsage",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/os-simple-tenant-usage/api/v1.1",
|
||||
"alias": "os-simple-tenant-usage",
|
||||
"description": "Simple tenant usage extension"
|
||||
}, {
|
||||
"updated": "2011-08-18T00:00:00+00:00",
|
||||
"name": "Rescue",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/rescue/api/v1.1",
|
||||
"alias": "os-rescue",
|
||||
"description": "Instance rescue mode"
|
||||
}, {
|
||||
"updated": "2011-07-21T00:00:00+00:00",
|
||||
"name": "SecurityGroups",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/securitygroups/api/v1.1",
|
||||
"alias": "security_groups",
|
||||
"description": "Security group support"
|
||||
}, {
|
||||
"updated": "2011-06-16T00:00:00+00:00",
|
||||
"name": "Floating_ips",
|
||||
"links": [],
|
||||
"namespace": "https://docs.openstack.org/ext/floating_ips/api/v1.1",
|
||||
"alias": "os-floating-ips",
|
||||
"description": "Floating IPs support"
|
||||
}, {
|
||||
"updated": "2011-06-16T00:00:00+00:00",
|
||||
"name": "Users",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/users/api/v1.1",
|
||||
"alias": "os-users",
|
||||
"description": "Users support"
|
||||
}
|
||||
]
|
||||
}
|
||||
"updated": "2011-09-27T00:00:00+00:00",
|
||||
"name": "DiskConfig",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/disk_config/api/v1.1",
|
||||
"alias": "OS-DCF",
|
||||
"description": "Disk Management Extension"
|
||||
},
|
||||
{
|
||||
"updated": "2011-06-29T00:00:00+00:00",
|
||||
"name": "Hosts",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/hosts/api/v1.1",
|
||||
"alias": "os-hosts",
|
||||
"description": "Admin-only host administration"
|
||||
},
|
||||
{
|
||||
"updated": "2011-07-19T00:00:00+00:00",
|
||||
"name": "SchedulerHints",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/scheduler-hints/api/v2",
|
||||
"alias": "os-scheduler-hints",
|
||||
"description": "Pass arbitrary key/value pairs to the scheduler"
|
||||
},
|
||||
{
|
||||
"updated": "2011-08-08T00:00:00+00:00",
|
||||
"name": "Quotas",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1",
|
||||
"alias": "os-quota-sets",
|
||||
"description": "Quotas management support"
|
||||
},
|
||||
{
|
||||
"updated": "2011-12-23T00:00:00+00:00",
|
||||
"name": "Floating_ip_dns",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/ext/floating_ip_dns/api/v1.1",
|
||||
"alias": "os-floating-ip-dns",
|
||||
"description": "Floating IP DNS support"
|
||||
},
|
||||
{
|
||||
"updated": "2011-09-14T00:00:00+00:00",
|
||||
"name": "FlavorExtraData",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1",
|
||||
"alias": "OS-FLV-EXT-DATA",
|
||||
"description": "Provide additional data for flavors"
|
||||
},
|
||||
{
|
||||
"updated": "2011-06-23T00:00:00+00:00",
|
||||
"name": "FlavorExtraSpecs",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/flavor_extra_specs/api/v1.1",
|
||||
"alias": "os-flavor-extra-specs",
|
||||
"description": "Instance type (flavor) extra specs"
|
||||
},
|
||||
{
|
||||
"updated": "2011-08-17T00:00:00+00:00",
|
||||
"name": "VirtualInterfaces",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1",
|
||||
"alias": "virtual_interfaces",
|
||||
"description": "Virtual interface support"
|
||||
},
|
||||
{
|
||||
"updated": "2011-12-23T00:00:00+00:00",
|
||||
"name": "Accounts",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/accounts/api/v1.1",
|
||||
"alias": "os-accounts",
|
||||
"description": "Admin-only access to accounts"
|
||||
},
|
||||
{
|
||||
"updated": "2011-03-25T00:00:00+00:00",
|
||||
"name": "Volumes",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/volumes/api/v1.1",
|
||||
"alias": "os-volumes",
|
||||
"description": "Volumes support"
|
||||
},
|
||||
{
|
||||
"updated": "2011-11-03T00:00:00+00:00",
|
||||
"name": "ExtendedStatus",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/extended_status/api/v1.1",
|
||||
"alias": "OS-EXT-STS",
|
||||
"description": "Extended Status support"
|
||||
},
|
||||
{
|
||||
"updated": "2011-12-23T00:00:00+00:00",
|
||||
"name": "Consoles",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/os-consoles/api/v2",
|
||||
"alias": "os-consoles",
|
||||
"description": "Interactive Console support."
|
||||
},
|
||||
{
|
||||
"updated": "2011-07-21T00:00:00+00:00",
|
||||
"name": "SecurityGroups",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/securitygroups/api/v1.1",
|
||||
"alias": "security_groups",
|
||||
"description": "Security group support"
|
||||
},
|
||||
{
|
||||
"updated": "2012-01-12T00:00:00+00:00",
|
||||
"name": "Aggregates",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/aggregates/api/v1.1",
|
||||
"alias": "os-aggregates",
|
||||
"description": "Admin-only aggregate administration"
|
||||
},
|
||||
{
|
||||
"updated": "2011-07-19T00:00:00+00:00",
|
||||
"name": "Createserverext",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/createserverext/api/v1.1",
|
||||
"alias": "os-create-server-ext",
|
||||
"description": "Extended support to the Create Server v1.1 API"
|
||||
},
|
||||
{
|
||||
"updated": "2011-09-01T00:00:00+00:00",
|
||||
"name": "DeferredDelete",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/deferred-delete/api/v1.1",
|
||||
"alias": "os-deferred-delete",
|
||||
"description": "Instance deferred delete"
|
||||
},
|
||||
{
|
||||
"updated": "2011-12-21T00:00:00+00:00",
|
||||
"name": "ServerDiagnostics",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/server-diagnostics/api/v1.1",
|
||||
"alias": "os-server-diagnostics",
|
||||
"description": "Allow Admins to view server diagnostics through server action"
|
||||
},
|
||||
{
|
||||
"updated": "2011-12-23T00:00:00+00:00",
|
||||
"name": "Networks",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/networks/api/v1.1",
|
||||
"alias": "os-networks",
|
||||
"description": "Admin-only Network Management Extension"
|
||||
},
|
||||
{
|
||||
"updated": "2011-11-03T00:00:00+00:00",
|
||||
"name": "ExtendedServerAttributes",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/extended_status/api/v1.1",
|
||||
"alias": "OS-EXT-SRV-ATTR",
|
||||
"description": "Extended Server Attributes support."
|
||||
},
|
||||
{
|
||||
"updated": "2011-08-08T00:00:00+00:00",
|
||||
"name": "Keypairs",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/keypairs/api/v1.1",
|
||||
"alias": "os-keypairs",
|
||||
"description": "Keypair Support"
|
||||
},
|
||||
{
|
||||
"updated": "2011-08-24T00:00:00+00:00",
|
||||
"name": "VolumeTypes",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/volume_types/api/v1.1",
|
||||
"alias": "os-volume-types",
|
||||
"description": "Volume types support"
|
||||
},
|
||||
{
|
||||
"updated": "2011-08-19T00:00:00+00:00",
|
||||
"name": "SimpleTenantUsage",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1",
|
||||
"alias": "os-simple-tenant-usage",
|
||||
"description": "Simple tenant usage extension"
|
||||
},
|
||||
{
|
||||
"updated": "2012-01-04T00:00:00+00:00",
|
||||
"name": "Floating_ip_pools",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/floating_ip_pools/api/v1.1",
|
||||
"alias": "os-floating-ip-pools",
|
||||
"description": "Floating IPs support"
|
||||
},
|
||||
{
|
||||
"updated": "2012-01-23T00:00:00+00:00",
|
||||
"name": "ServerStartStop",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/servers/api/v1.1",
|
||||
"alias": "os-server-start-stop",
|
||||
"description": "Start/Stop instance compute API support"
|
||||
},
|
||||
{
|
||||
"updated": "2012-03-12T00:00:00+00:00",
|
||||
"name": "QuotaClasses",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1",
|
||||
"alias": "os-quota-class-sets",
|
||||
"description": "Quota classes management support"
|
||||
},
|
||||
{
|
||||
"updated": "2012-01-19T00:00:00+00:00",
|
||||
"name": "Certificates",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/certificates/api/v1.1",
|
||||
"alias": "os-certificates",
|
||||
"description": "Certificates support"
|
||||
},
|
||||
{
|
||||
"updated": "2011-08-18T00:00:00+00:00",
|
||||
"name": "Rescue",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1",
|
||||
"alias": "os-rescue",
|
||||
"description": "Instance rescue mode"
|
||||
},
|
||||
{
|
||||
"updated": "2012-01-19T00:00:00+00:00",
|
||||
"name": "FlavorManage",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/flavor_manage/api/v1.1",
|
||||
"alias": "os-flavor-manage",
|
||||
"description": "\n Flavor create/delete API support\n "
|
||||
},
|
||||
{
|
||||
"updated": "2011-12-16T00:00:00+00:00",
|
||||
"name": "Cloudpipe",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/cloudpipe/api/v1.1",
|
||||
"alias": "os-cloudpipe",
|
||||
"description": "Adds actions to create cloudpipe instances.\n\n When running with the Vlan network mode, you need a mechanism to route\n from the public Internet to your vlans. This mechanism is known as a\n cloudpipe.\n\n At the time of creating this class, only OpenVPN is supported. Support for\n a SSH Bastion host is forthcoming.\n "
|
||||
},
|
||||
{
|
||||
"updated": "2011-06-09T00:00:00+00:00",
|
||||
"name": "Multinic",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/multinic/api/v1.1",
|
||||
"alias": "NMN",
|
||||
"description": "Multiple network support"
|
||||
},
|
||||
{
|
||||
"updated": "2011-08-08T00:00:00+00:00",
|
||||
"name": "Users",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/users/api/v1.1",
|
||||
"alias": "os-users",
|
||||
"description": "Allow admins to acces user information"
|
||||
},
|
||||
{
|
||||
"updated": "2011-09-20T00:00:00+00:00",
|
||||
"name": "AdminActions",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/admin-actions/api/v1.1",
|
||||
"alias": "os-admin-actions",
|
||||
"description": "Enable admin-only server actions\n\n Actions include: pause,unpause, suspend, resume, migrate,\n resetNetwork, injectNetworkInfo, lock, unlock, createBackup\n "
|
||||
},
|
||||
{
|
||||
"updated": "2011-12-21T00:00:00+00:00",
|
||||
"name": "ServerActionList",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/server-actions-list/api/v1.1",
|
||||
"alias": "os-server-action-list",
|
||||
"description": "Allow Admins to view pending server actions"
|
||||
},
|
||||
{
|
||||
"updated": "2011-12-08T00:00:00+00:00",
|
||||
"name": "Console_output",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/os-console-output/api/v2",
|
||||
"alias": "os-console-output",
|
||||
"description": "Console log output support, with tailing ability."
|
||||
},
|
||||
{
|
||||
"updated": "2011-06-16T00:00:00+00:00",
|
||||
"name": "Floating_ips",
|
||||
"links": [],
|
||||
"namespace": "http://docs.openstack.org/compute/ext/floating_ips/api/v1.1",
|
||||
"alias": "os-floating-ips",
|
||||
"description": "Floating IPs support"}
|
||||
]}
|
Loading…
Reference in New Issue