mirror of https://github.com/apache/jclouds.git
fixed compute service functionality for gogrid
This commit is contained in:
parent
8921dfcdc2
commit
c50541c845
|
@ -92,7 +92,7 @@ public abstract class BaseComputeServiceLiveTest {
|
||||||
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException,
|
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException,
|
||||||
IOException {
|
IOException {
|
||||||
if (tag == null)
|
if (tag == null)
|
||||||
tag = checkNotNull(service, "service");
|
tag = checkNotNull(service, "service") + "alex";
|
||||||
user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
|
user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
|
||||||
password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
|
password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
|
||||||
String secretKeyFile;
|
String secretKeyFile;
|
||||||
|
@ -134,17 +134,7 @@ public abstract class BaseComputeServiceLiveTest {
|
||||||
.getOptions()
|
.getOptions()
|
||||||
.installPrivateKey(keyPair.get("private"))
|
.installPrivateKey(keyPair.get("private"))
|
||||||
.authorizePublicKey(keyPair.get("public"))
|
.authorizePublicKey(keyPair.get("public"))
|
||||||
.runScript(
|
.runScript(buildScript().getBytes());
|
||||||
new StringBuilder()//
|
|
||||||
.append("echo nameserver 208.67.222.222 >> /etc/resolv.conf\n")//
|
|
||||||
.append("cp /etc/apt/sources.list /etc/apt/sources.list.old\n")//
|
|
||||||
.append(
|
|
||||||
"sed 's~us.archive.ubuntu.com~mirror.anl.gov/pub~g' /etc/apt/sources.list.old >/etc/apt/sources.list\n")//
|
|
||||||
.append("apt-get update\n")//
|
|
||||||
.append("apt-get install -f -y --force-yes openjdk-6-jdk\n")//
|
|
||||||
.append("wget -qO/usr/bin/runurl run.alestic.com/runurl\n")//
|
|
||||||
.append("chmod 755 /usr/bin/runurl\n")//
|
|
||||||
.toString().getBytes());
|
|
||||||
nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 2, template).values());
|
nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 2, template).values());
|
||||||
assertEquals(nodes.size(), 2);
|
assertEquals(nodes.size(), 2);
|
||||||
checkNodes();
|
checkNodes();
|
||||||
|
@ -179,6 +169,20 @@ public abstract class BaseComputeServiceLiveTest {
|
||||||
|
|
||||||
protected abstract Template buildTemplate(TemplateBuilder templateBuilder);
|
protected abstract Template buildTemplate(TemplateBuilder templateBuilder);
|
||||||
|
|
||||||
|
protected String buildScript() {
|
||||||
|
return
|
||||||
|
new StringBuilder()//
|
||||||
|
.append("echo nameserver 208.67.222.222 >> /etc/resolv.conf\n")//
|
||||||
|
.append("cp /etc/apt/sources.list /etc/apt/sources.list.old\n")//
|
||||||
|
.append(
|
||||||
|
"sed 's~us.archive.ubuntu.com~mirror.anl.gov/pub~g' /etc/apt/sources.list.old >/etc/apt/sources.list\n")//
|
||||||
|
.append("apt-get update\n")//
|
||||||
|
.append("apt-get install -f -y --force-yes openjdk-6-jdk\n")//
|
||||||
|
.append("wget -qO/usr/bin/runurl run.alestic.com/runurl\n")//
|
||||||
|
.append("chmod 755 /usr/bin/runurl\n")//
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
@Test(enabled = true, dependsOnMethods = "testCreate")
|
@Test(enabled = true, dependsOnMethods = "testCreate")
|
||||||
public void testGet() throws Exception {
|
public void testGet() throws Exception {
|
||||||
Set<? extends NodeMetadata> metadataSet = Sets.newHashSet(client.getNodesWithTag(tag)
|
Set<? extends NodeMetadata> metadataSet = Sets.newHashSet(client.getNodesWithTag(tag)
|
||||||
|
@ -261,7 +265,7 @@ public abstract class BaseComputeServiceLiveTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doCheckKey(NodeMetadata node) throws IOException {
|
protected void doCheckKey(NodeMetadata node) throws IOException {
|
||||||
InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0),
|
InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0),
|
||||||
22);
|
22);
|
||||||
socketTester.apply(socket); // TODO add transitionTo option that accepts a socket conection
|
socketTester.apply(socket); // TODO add transitionTo option that accepts a socket conection
|
||||||
|
|
|
@ -18,9 +18,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.gogrid.config;
|
package org.jclouds.gogrid.config;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.*;
|
||||||
import com.google.common.base.Predicate;
|
|
||||||
import com.google.common.base.Predicates;
|
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
@ -40,10 +38,8 @@ import org.jclouds.domain.LocationScope;
|
||||||
import org.jclouds.domain.internal.LocationImpl;
|
import org.jclouds.domain.internal.LocationImpl;
|
||||||
import org.jclouds.gogrid.GoGridAsyncClient;
|
import org.jclouds.gogrid.GoGridAsyncClient;
|
||||||
import org.jclouds.gogrid.GoGridClient;
|
import org.jclouds.gogrid.GoGridClient;
|
||||||
import org.jclouds.gogrid.domain.Ip;
|
import org.jclouds.gogrid.domain.*;
|
||||||
import org.jclouds.gogrid.domain.PowerCommand;
|
import org.jclouds.gogrid.options.GetIpListOptions;
|
||||||
import org.jclouds.gogrid.domain.Server;
|
|
||||||
import org.jclouds.gogrid.domain.ServerImage;
|
|
||||||
import org.jclouds.gogrid.predicates.ServerLatestJobCompleted;
|
import org.jclouds.gogrid.predicates.ServerLatestJobCompleted;
|
||||||
import org.jclouds.gogrid.util.GoGridUtils;
|
import org.jclouds.gogrid.util.GoGridUtils;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
|
@ -57,6 +53,7 @@ import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
@ -97,6 +94,7 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule {
|
||||||
private final Function<Size, String> sizeToRam;
|
private final Function<Size, String> sizeToRam;
|
||||||
private final Function<Server, NodeMetadata> serverToNodeMetadata;
|
private final Function<Server, NodeMetadata> serverToNodeMetadata;
|
||||||
private RetryablePredicate<Server> serverLatestJobCompleted;
|
private RetryablePredicate<Server> serverLatestJobCompleted;
|
||||||
|
private RetryablePredicate<Server> serverLatestJobCompletedShort;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected GoGridAddNodeWithTagStrategy(GoGridClient client,
|
protected GoGridAddNodeWithTagStrategy(GoGridClient client,
|
||||||
|
@ -108,18 +106,36 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule {
|
||||||
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
|
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
|
||||||
new ServerLatestJobCompleted(client.getJobServices()),
|
new ServerLatestJobCompleted(client.getJobServices()),
|
||||||
800, 20, TimeUnit.SECONDS);
|
800, 20, TimeUnit.SECONDS);
|
||||||
|
this.serverLatestJobCompletedShort = new RetryablePredicate<Server>(
|
||||||
|
new ServerLatestJobCompleted(client.getJobServices()),
|
||||||
|
60, 20, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NodeMetadata execute(String tag, String name, Template template) {
|
public NodeMetadata execute(String tag, String name, Template template) {
|
||||||
Set<Ip> availableIps = client.getIpServices().getUnassignedIpList();
|
Server addedServer = null;
|
||||||
Ip availableIp = Iterables.getLast(availableIps);
|
boolean notStarted = true;
|
||||||
Server addedServer = client.getServerServices().addServer(name, checkNotNull(template.getImage().getId()),
|
int numOfRetries = 20;
|
||||||
|
// lock-free consumption of a shared resource: IP address pool
|
||||||
|
while(notStarted) { // TODO: replace with Predicate-based thread collision avoidance for simplicity
|
||||||
|
Set<Ip> availableIps =
|
||||||
|
client.getIpServices().getIpList(new GetIpListOptions().onlyUnassigned().onlyWithType(IpType.PUBLIC));
|
||||||
|
if(availableIps.size() == 0) throw new RuntimeException("No public IPs available on this account.");
|
||||||
|
int ipIndex = new SecureRandom().nextInt(availableIps.size());
|
||||||
|
Ip availableIp = Iterables.get(availableIps, ipIndex);
|
||||||
|
try {
|
||||||
|
addedServer = client.getServerServices().addServer(name, checkNotNull(template.getImage().getId()),
|
||||||
sizeToRam.apply(template.getSize()), availableIp.getIp());
|
sizeToRam.apply(template.getSize()), availableIp.getIp());
|
||||||
|
notStarted = false;
|
||||||
|
} catch(Exception e) {
|
||||||
|
if(--numOfRetries == 0) Throwables.propagate(e);
|
||||||
|
notStarted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
serverLatestJobCompleted.apply(addedServer);
|
serverLatestJobCompleted.apply(addedServer);
|
||||||
|
|
||||||
client.getServerServices().power(addedServer.getName(), PowerCommand.START);
|
client.getServerServices().power(addedServer.getName(), PowerCommand.START);
|
||||||
serverLatestJobCompleted.apply(addedServer);
|
serverLatestJobCompletedShort.apply(addedServer);
|
||||||
|
|
||||||
addedServer = Iterables.getOnlyElement(
|
addedServer = Iterables.getOnlyElement(
|
||||||
client.getServerServices().getServersByName(addedServer.getName())
|
client.getServerServices().getServersByName(addedServer.getName())
|
||||||
|
@ -132,6 +148,7 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule {
|
||||||
public static class GoGridRebootNodeStrategy implements RebootNodeStrategy {
|
public static class GoGridRebootNodeStrategy implements RebootNodeStrategy {
|
||||||
private final GoGridClient client;
|
private final GoGridClient client;
|
||||||
private RetryablePredicate<Server> serverLatestJobCompleted;
|
private RetryablePredicate<Server> serverLatestJobCompleted;
|
||||||
|
private RetryablePredicate<Server> serverLatestJobCompletedShort;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected GoGridRebootNodeStrategy(GoGridClient client) {
|
protected GoGridRebootNodeStrategy(GoGridClient client) {
|
||||||
|
@ -139,6 +156,9 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule {
|
||||||
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
|
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
|
||||||
new ServerLatestJobCompleted(client.getJobServices()),
|
new ServerLatestJobCompleted(client.getJobServices()),
|
||||||
800, 20, TimeUnit.SECONDS);
|
800, 20, TimeUnit.SECONDS);
|
||||||
|
this.serverLatestJobCompletedShort = new RetryablePredicate<Server>(
|
||||||
|
new ServerLatestJobCompleted(client.getJobServices()),
|
||||||
|
60, 20, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -148,7 +168,7 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule {
|
||||||
client.getServerServices().power(server.getName(), PowerCommand.RESTART);
|
client.getServerServices().power(server.getName(), PowerCommand.RESTART);
|
||||||
serverLatestJobCompleted.apply(server);
|
serverLatestJobCompleted.apply(server);
|
||||||
client.getServerServices().power(server.getName(), PowerCommand.START);
|
client.getServerServices().power(server.getName(), PowerCommand.START);
|
||||||
return serverLatestJobCompleted.apply(server);
|
return serverLatestJobCompletedShort.apply(server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +310,7 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule {
|
||||||
@Override
|
@Override
|
||||||
public NodeMetadata apply(Server from) {
|
public NodeMetadata apply(Server from) {
|
||||||
String locationId = "Unavailable";
|
String locationId = "Unavailable";
|
||||||
String tag = from.getName();
|
String tag = CharMatcher.JAVA_LETTER.retainFrom(from.getName());
|
||||||
Credentials creds = client.getServerServices().getServerCredentialsList().get(from.getName());
|
Credentials creds = client.getServerServices().getServerCredentialsList().get(from.getName());
|
||||||
Set<InetAddress> ipSet =
|
Set<InetAddress> ipSet =
|
||||||
ImmutableSet.of(stringIpToInetAddress.apply(from.getIp().getIp()));
|
ImmutableSet.of(stringIpToInetAddress.apply(from.getIp().getIp()));
|
||||||
|
@ -407,9 +427,9 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule {
|
||||||
Set<ServerImage> allImages = sync.getImageServices().getImageList();
|
Set<ServerImage> allImages = sync.getImageServices().getImageList();
|
||||||
for (ServerImage from : allImages) {
|
for (ServerImage from : allImages) {
|
||||||
OsFamily os = null;
|
OsFamily os = null;
|
||||||
Architecture arch = (from.getDescription().indexOf("64") == -1 &&
|
Architecture arch = (from.getOs().getName().indexOf("64") == -1 &&
|
||||||
from.getOs().getName().indexOf("64") == -1) ? Architecture.X86_32
|
from.getDescription().indexOf("64") == -1) ?
|
||||||
: Architecture.X86_64;
|
Architecture.X86_32 : Architecture.X86_64;
|
||||||
String osDescription;
|
String osDescription;
|
||||||
String version = "";
|
String version = "";
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ public class ParseServerNameToCredentialsMapFromJsonResponse extends ParseJson<M
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Password o) {
|
public int compareTo(Password o) {
|
||||||
return userName.compareTo(o.getUserName());
|
return server.getName().compareTo(o.getServer().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,18 @@ import java.util.regex.Pattern;
|
||||||
*/
|
*/
|
||||||
public class GoGridUtils {
|
public class GoGridUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches nth group or returns null.
|
||||||
|
*
|
||||||
|
* @param stringToParse string that the pattern will be applied to
|
||||||
|
* @param pattern regular expression {@link java.util.regex.Pattern pattern}
|
||||||
|
* @param nthGroup number of the group to extract / return
|
||||||
|
* @return matched group or null
|
||||||
|
*/
|
||||||
public static String parseStringByPatternAndGetNthMatchGroup(String stringToParse, Pattern pattern, int nthGroup) {
|
public static String parseStringByPatternAndGetNthMatchGroup(String stringToParse, Pattern pattern, int nthGroup) {
|
||||||
Matcher osVersionMatcher = pattern.matcher(stringToParse);
|
Matcher osVersionMatcher = pattern.matcher(stringToParse);
|
||||||
if (osVersionMatcher.find()) {
|
if (osVersionMatcher.find()) {
|
||||||
return osVersionMatcher.group(nthGroup).toLowerCase();
|
return osVersionMatcher.group(nthGroup);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.gogrid;
|
||||||
import static org.jclouds.compute.domain.OsFamily.CENTOS;
|
import static org.jclouds.compute.domain.OsFamily.CENTOS;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
import static org.testng.Assert.assertTrue;
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jclouds.compute.BaseComputeServiceLiveTest;
|
import org.jclouds.compute.BaseComputeServiceLiveTest;
|
||||||
|
@ -51,8 +50,22 @@ public class GoGridComputeServiceLiveTest extends BaseComputeServiceLiveTest {
|
||||||
service = "gogrid";
|
service = "gogrid";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String buildScript() {
|
||||||
|
return
|
||||||
|
new StringBuilder()//
|
||||||
|
.append("echo nameserver 208.67.222.222 >> /etc/resolv.conf\n")//
|
||||||
|
.append("echo \"[jdkrepo]\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
|
||||||
|
.append("echo \"name=jdkrepository\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
|
||||||
|
.append("echo \"baseurl=http://ec2-us-east-mirror.rightscale.com/epel/5/i386/\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
|
||||||
|
.append("echo \"enabled=1\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
|
||||||
|
.append("yum -y install java-1.6.0-openjdk\n")
|
||||||
|
.append("echo \"export PATH=\\\"/usr/lib/jvm/jre-1.6.0-openjdk/bin/:\\$PATH\\\"\" >> /root/.bashrc\n")
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
protected Template buildTemplate(TemplateBuilder templateBuilder) {
|
protected Template buildTemplate(TemplateBuilder templateBuilder) {
|
||||||
return templateBuilder.osFamily(CENTOS).osDescriptionMatches(".*5.3.*").smallest().build();
|
return templateBuilder.osFamily(CENTOS).imageId("GSI-f8979644-e646-4711-ad58-d98a5fa3612c").smallest().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed 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.gogrid.functions;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Injector;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
import org.jclouds.Constants;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.gogrid.config.GoGridContextModule;
|
||||||
|
import org.jclouds.gogrid.domain.IpState;
|
||||||
|
import org.jclouds.gogrid.domain.ServerImageState;
|
||||||
|
import org.jclouds.gogrid.domain.ServerImageType;
|
||||||
|
import org.jclouds.gogrid.functions.internal.CustomDeserializers;
|
||||||
|
import org.jclouds.http.functions.config.ParserModule;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Oleksiy Yarmula
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "gogrid.ParseServerNameToCredentialsMapFromJsonResponseTest")
|
||||||
|
public class ParseServerNameToCredentialsMapFromJsonResponseTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyInputStreamDetails() throws UnknownHostException {
|
||||||
|
InputStream is = getClass().getResourceAsStream("/test_credentials_list.json");
|
||||||
|
|
||||||
|
ParseServerNameToCredentialsMapFromJsonResponse parser = new ParseServerNameToCredentialsMapFromJsonResponse(i
|
||||||
|
.getInstance(Gson.class));
|
||||||
|
Map<String, Credentials> response = parser.apply(is);
|
||||||
|
assertEquals(response.size(), 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Injector i = Guice.createInjector(new ParserModule() {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(DateAdapter.class).to(GoGridContextModule.DateSecondsAdapter.class);
|
||||||
|
super.configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
@com.google.inject.name.Named(Constants.PROPERTY_GSON_ADAPTERS)
|
||||||
|
public Map<Class, Object> provideCustomAdapterBindings() {
|
||||||
|
Map<Class, Object> bindings = Maps.newHashMap();
|
||||||
|
bindings.put(IpState.class, new CustomDeserializers.IpStateAdapter());
|
||||||
|
bindings.put(ServerImageType.class, new CustomDeserializers.ServerImageTypeAdapter());
|
||||||
|
bindings.put(ServerImageState.class, new CustomDeserializers.ServerImageStateAdapter());
|
||||||
|
bindings.put(ServerImageState.class, new CustomDeserializers.ServerImageStateAdapter());
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,600 @@
|
||||||
|
{
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"password": "dig44sos",
|
||||||
|
"object": "password",
|
||||||
|
"username": "root",
|
||||||
|
"server": {
|
||||||
|
"object": "server",
|
||||||
|
"isSandbox": false,
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"object": "customer",
|
||||||
|
"name": "Gear6",
|
||||||
|
"id": 26443
|
||||||
|
},
|
||||||
|
"updatedTime": 1265675466171,
|
||||||
|
"isActive": true,
|
||||||
|
"id": 2500,
|
||||||
|
"createdTime": 1265412834154,
|
||||||
|
"isPublic": true,
|
||||||
|
"billingtokens": [
|
||||||
|
{
|
||||||
|
"price": 0,
|
||||||
|
"name": "CentOS 5.3 64bit",
|
||||||
|
"id": 47
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"price": 60,
|
||||||
|
"name": "Gear 6 Paid Version",
|
||||||
|
"id": 76
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"object": "serverimage",
|
||||||
|
"friendlyName": "gear6-memcache-server-2.3.6.2-x86_64",
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"price": 60,
|
||||||
|
"description": "Gear6 Memcache Server 2.3.6.2 (64 bit)",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Image is available for adds",
|
||||||
|
"name": "Available",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"location": "26443/GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a.img",
|
||||||
|
"name": "GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server is in active state.",
|
||||||
|
"name": "On",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"ram": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server with 512MB RAM",
|
||||||
|
"name": "512MB",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"name": "gogrid-19",
|
||||||
|
"ip": {
|
||||||
|
"object": "ip",
|
||||||
|
"public": true,
|
||||||
|
"subnet": "204.51.240.176/255.255.255.240",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "IP is reserved or in use",
|
||||||
|
"name": "Assigned",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"ip": "204.51.240.189",
|
||||||
|
"id": 1313090
|
||||||
|
},
|
||||||
|
"id": 77332
|
||||||
|
},
|
||||||
|
"id": 82647,
|
||||||
|
"applicationtype": "os"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"password": "job96qat",
|
||||||
|
"object": "password",
|
||||||
|
"username": "root",
|
||||||
|
"server": {
|
||||||
|
"object": "server",
|
||||||
|
"isSandbox": false,
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"object": "customer",
|
||||||
|
"name": "Gear6",
|
||||||
|
"id": 26443
|
||||||
|
},
|
||||||
|
"updatedTime": 1265675466171,
|
||||||
|
"isActive": true,
|
||||||
|
"id": 2500,
|
||||||
|
"createdTime": 1265412834154,
|
||||||
|
"isPublic": true,
|
||||||
|
"billingtokens": [
|
||||||
|
{
|
||||||
|
"price": 0,
|
||||||
|
"name": "CentOS 5.3 64bit",
|
||||||
|
"id": 47
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"price": 60,
|
||||||
|
"name": "Gear 6 Paid Version",
|
||||||
|
"id": 76
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"object": "serverimage",
|
||||||
|
"friendlyName": "gear6-memcache-server-2.3.6.2-x86_64",
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"price": 60,
|
||||||
|
"description": "Gear6 Memcache Server 2.3.6.2 (64 bit)",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Image is available for adds",
|
||||||
|
"name": "Available",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"location": "26443/GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a.img",
|
||||||
|
"name": "GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server is in active state.",
|
||||||
|
"name": "On",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"ram": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server with 512MB RAM",
|
||||||
|
"name": "512MB",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"name": "gogrid-5288",
|
||||||
|
"ip": {
|
||||||
|
"object": "ip",
|
||||||
|
"public": true,
|
||||||
|
"subnet": "204.51.240.176/255.255.255.240",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "IP is reserved or in use",
|
||||||
|
"name": "Assigned",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"ip": "204.51.240.186",
|
||||||
|
"id": 1313087
|
||||||
|
},
|
||||||
|
"id": 77335
|
||||||
|
},
|
||||||
|
"id": 82653,
|
||||||
|
"applicationtype": "os"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"password": "fif70cij",
|
||||||
|
"object": "password",
|
||||||
|
"username": "root",
|
||||||
|
"server": {
|
||||||
|
"object": "server",
|
||||||
|
"isSandbox": false,
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"object": "customer",
|
||||||
|
"name": "Gear6",
|
||||||
|
"id": 26443
|
||||||
|
},
|
||||||
|
"updatedTime": 1265675466171,
|
||||||
|
"isActive": true,
|
||||||
|
"id": 2500,
|
||||||
|
"createdTime": 1265412834154,
|
||||||
|
"isPublic": true,
|
||||||
|
"billingtokens": [
|
||||||
|
{
|
||||||
|
"price": 0,
|
||||||
|
"name": "CentOS 5.3 64bit",
|
||||||
|
"id": 47
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"price": 60,
|
||||||
|
"name": "Gear 6 Paid Version",
|
||||||
|
"id": 76
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"object": "serverimage",
|
||||||
|
"friendlyName": "gear6-memcache-server-2.3.6.2-x86_64",
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"price": 60,
|
||||||
|
"description": "Gear6 Memcache Server 2.3.6.2 (64 bit)",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Image is available for adds",
|
||||||
|
"name": "Available",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"location": "26443/GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a.img",
|
||||||
|
"name": "GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server is in active state.",
|
||||||
|
"name": "On",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"ram": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server with 512MB RAM",
|
||||||
|
"name": "512MB",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"name": "gogrid-7210",
|
||||||
|
"ip": {
|
||||||
|
"object": "ip",
|
||||||
|
"public": true,
|
||||||
|
"subnet": "204.51.240.176/255.255.255.240",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "IP is reserved or in use",
|
||||||
|
"name": "Assigned",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"ip": "204.51.240.188",
|
||||||
|
"id": 1313089
|
||||||
|
},
|
||||||
|
"id": 77333
|
||||||
|
},
|
||||||
|
"id": 82651,
|
||||||
|
"applicationtype": "os"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"password": "vam61doz",
|
||||||
|
"object": "password",
|
||||||
|
"username": "root",
|
||||||
|
"server": {
|
||||||
|
"object": "server",
|
||||||
|
"isSandbox": false,
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"object": "customer",
|
||||||
|
"name": "Gear6",
|
||||||
|
"id": 26443
|
||||||
|
},
|
||||||
|
"updatedTime": 1265675466171,
|
||||||
|
"isActive": true,
|
||||||
|
"id": 2500,
|
||||||
|
"createdTime": 1265412834154,
|
||||||
|
"isPublic": true,
|
||||||
|
"billingtokens": [
|
||||||
|
{
|
||||||
|
"price": 0,
|
||||||
|
"name": "CentOS 5.3 64bit",
|
||||||
|
"id": 47
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"price": 60,
|
||||||
|
"name": "Gear 6 Paid Version",
|
||||||
|
"id": 76
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"object": "serverimage",
|
||||||
|
"friendlyName": "gear6-memcache-server-2.3.6.2-x86_64",
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"price": 60,
|
||||||
|
"description": "Gear6 Memcache Server 2.3.6.2 (64 bit)",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Image is available for adds",
|
||||||
|
"name": "Available",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"location": "26443/GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a.img",
|
||||||
|
"name": "GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server is in active state.",
|
||||||
|
"name": "On",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"ram": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server with 512MB RAM",
|
||||||
|
"name": "512MB",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"name": "gogrid-7461",
|
||||||
|
"ip": {
|
||||||
|
"object": "ip",
|
||||||
|
"public": true,
|
||||||
|
"subnet": "204.51.240.176/255.255.255.240",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "IP is reserved or in use",
|
||||||
|
"name": "Assigned",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"ip": "204.51.240.187",
|
||||||
|
"id": 1313088
|
||||||
|
},
|
||||||
|
"id": 77334
|
||||||
|
},
|
||||||
|
"id": 82652,
|
||||||
|
"applicationtype": "os"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"password": "cun86xef",
|
||||||
|
"object": "password",
|
||||||
|
"username": "root",
|
||||||
|
"server": {
|
||||||
|
"object": "server",
|
||||||
|
"isSandbox": false,
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"object": "customer",
|
||||||
|
"name": "Gear6",
|
||||||
|
"id": 26443
|
||||||
|
},
|
||||||
|
"updatedTime": 1265675466171,
|
||||||
|
"isActive": true,
|
||||||
|
"id": 2500,
|
||||||
|
"createdTime": 1265412834154,
|
||||||
|
"isPublic": true,
|
||||||
|
"billingtokens": [
|
||||||
|
{
|
||||||
|
"price": 0,
|
||||||
|
"name": "CentOS 5.3 64bit",
|
||||||
|
"id": 47
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"price": 60,
|
||||||
|
"name": "Gear 6 Paid Version",
|
||||||
|
"id": 76
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"object": "serverimage",
|
||||||
|
"friendlyName": "gear6-memcache-server-2.3.6.2-x86_64",
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"price": 60,
|
||||||
|
"description": "Gear6 Memcache Server 2.3.6.2 (64 bit)",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Image is available for adds",
|
||||||
|
"name": "Available",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"location": "26443/GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a.img",
|
||||||
|
"name": "GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server is in active state.",
|
||||||
|
"name": "On",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"ram": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server with 512MB RAM",
|
||||||
|
"name": "512MB",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"name": "gogridalex-200",
|
||||||
|
"ip": {
|
||||||
|
"object": "ip",
|
||||||
|
"public": true,
|
||||||
|
"subnet": "204.51.240.176/255.255.255.240",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "IP is reserved or in use",
|
||||||
|
"name": "Assigned",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"ip": "204.51.240.179",
|
||||||
|
"id": 1313080
|
||||||
|
},
|
||||||
|
"id": 77410
|
||||||
|
},
|
||||||
|
"id": 82730,
|
||||||
|
"applicationtype": "os"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"password": "nun63wav",
|
||||||
|
"object": "password",
|
||||||
|
"username": "root",
|
||||||
|
"server": {
|
||||||
|
"object": "server",
|
||||||
|
"isSandbox": false,
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Web or Application Server",
|
||||||
|
"name": "Web Server",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"object": "customer",
|
||||||
|
"name": "Gear6",
|
||||||
|
"id": 26443
|
||||||
|
},
|
||||||
|
"updatedTime": 1265675466171,
|
||||||
|
"isActive": true,
|
||||||
|
"id": 2500,
|
||||||
|
"createdTime": 1265412834154,
|
||||||
|
"isPublic": true,
|
||||||
|
"billingtokens": [
|
||||||
|
{
|
||||||
|
"price": 0,
|
||||||
|
"name": "CentOS 5.3 64bit",
|
||||||
|
"id": 47
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"price": 60,
|
||||||
|
"name": "Gear 6 Paid Version",
|
||||||
|
"id": 76
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"object": "serverimage",
|
||||||
|
"friendlyName": "gear6-memcache-server-2.3.6.2-x86_64",
|
||||||
|
"os": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "CentOS 5.3 (64-bit)",
|
||||||
|
"name": "CentOS 5.3 (64-bit)",
|
||||||
|
"id": 17
|
||||||
|
},
|
||||||
|
"price": 60,
|
||||||
|
"description": "Gear6 Memcache Server 2.3.6.2 (64 bit)",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Image is available for adds",
|
||||||
|
"name": "Available",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"location": "26443/GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a.img",
|
||||||
|
"name": "GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server is in active state.",
|
||||||
|
"name": "On",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"ram": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "Server with 512MB RAM",
|
||||||
|
"name": "512MB",
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"name": "gogridalex-201",
|
||||||
|
"ip": {
|
||||||
|
"object": "ip",
|
||||||
|
"public": true,
|
||||||
|
"subnet": "204.51.240.176/255.255.255.240",
|
||||||
|
"state": {
|
||||||
|
"object": "option",
|
||||||
|
"description": "IP is reserved or in use",
|
||||||
|
"name": "Assigned",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
"ip": "204.51.240.185",
|
||||||
|
"id": 1313086
|
||||||
|
},
|
||||||
|
"id": 77411
|
||||||
|
},
|
||||||
|
"id": 82731,
|
||||||
|
"applicationtype": "os"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": {
|
||||||
|
"total": 6,
|
||||||
|
"start": 0,
|
||||||
|
"numpages": 0,
|
||||||
|
"returned": 6
|
||||||
|
},
|
||||||
|
"status": "success",
|
||||||
|
"method": "/support/password/list"
|
||||||
|
}
|
Loading…
Reference in New Issue