Fix guice cache binding issue for live tests

This commit is contained in:
Andrei Savu 2012-06-08 15:43:05 +03:00 committed by Adrian Cole
parent 72493161ab
commit 16afe38477
6 changed files with 122 additions and 85 deletions

View File

@ -52,6 +52,8 @@ import org.jclouds.cloudstack.domain.User;
import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.domain.Zone; import org.jclouds.cloudstack.domain.Zone;
import org.jclouds.cloudstack.features.GuestOSClient; import org.jclouds.cloudstack.features.GuestOSClient;
import org.jclouds.cloudstack.functions.GetFirewallRulesByVirtualMachine;
import org.jclouds.cloudstack.functions.GetIPForwardingRulesByVirtualMachine;
import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork; import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork;
import org.jclouds.cloudstack.functions.ZoneIdToZone; import org.jclouds.cloudstack.functions.ZoneIdToZone;
import org.jclouds.cloudstack.options.ListFirewallRulesOptions; import org.jclouds.cloudstack.options.ListFirewallRulesOptions;
@ -188,25 +190,6 @@ public class CloudStackComputeServiceContextModule extends
return CacheBuilder.newBuilder().build(getIPForwardingRules); return CacheBuilder.newBuilder().build(getIPForwardingRules);
} }
@Singleton
public static class GetIPForwardingRulesByVirtualMachine extends CacheLoader<String, Set<IPForwardingRule>> {
private final CloudStackClient client;
@Inject
public GetIPForwardingRulesByVirtualMachine(CloudStackClient client) {
this.client = checkNotNull(client, "client");
}
/**
* @throws ResourceNotFoundException
* when there is no ip forwarding rule available for the VM
*/
@Override
public Set<IPForwardingRule> load(String input) {
Set<IPForwardingRule> rules = client.getNATClient().getIPForwardingRulesForVirtualMachine(input);
return rules != null ? rules : ImmutableSet.<IPForwardingRule>of();
}
}
@Provides @Provides
@Singleton @Singleton
@ -215,27 +198,6 @@ public class CloudStackComputeServiceContextModule extends
return CacheBuilder.newBuilder().build(getFirewallRules); return CacheBuilder.newBuilder().build(getFirewallRules);
} }
@Singleton
public static class GetFirewallRulesByVirtualMachine extends CacheLoader<String, Set<FirewallRule>> {
private final CloudStackClient client;
@Inject
public GetFirewallRulesByVirtualMachine(CloudStackClient client) {
this.client = checkNotNull(client, "client");
}
/**
* @throws ResourceNotFoundException
* when there is no ip forwarding rule available for the VM
*/
@Override
public Set<FirewallRule> load(String input) {
String publicIPId = client.getVirtualMachineClient().getVirtualMachine(input).getPublicIPId();
Set<FirewallRule> rules = client.getFirewallClient().listFirewallRules(ListFirewallRulesOptions.Builder.ipAddressId(publicIPId));
return rules != null ? rules : ImmutableSet.<FirewallRule>of();
}
}
@Provides @Provides
@Singleton @Singleton
public Map<NetworkType, ? extends OptionsConverter> optionsConverters(){ public Map<NetworkType, ? extends OptionsConverter> optionsConverters(){

View File

@ -77,11 +77,10 @@ import com.google.common.primitives.Ints;
/** /**
* defines the connection between the {@link CloudStackClient} implementation * defines the connection between the {@link CloudStackClient} implementation
* and the jclouds {@link ComputeService} * and the jclouds {@link ComputeService}
*
*/ */
@Singleton @Singleton
public class CloudStackComputeServiceAdapter implements public class CloudStackComputeServiceAdapter implements
ComputeServiceAdapter<VirtualMachine, ServiceOffering, Template, Zone> { ComputeServiceAdapter<VirtualMachine, ServiceOffering, Template, Zone> {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
@ -101,19 +100,20 @@ public class CloudStackComputeServiceAdapter implements
@Inject @Inject
public CloudStackComputeServiceAdapter(CloudStackClient client, Predicate<String> jobComplete, public CloudStackComputeServiceAdapter(CloudStackClient client, Predicate<String> jobComplete,
@Memoized Supplier<Map<String, Network>> networkSupplier, @Memoized Supplier<Map<String, Network>> networkSupplier,
BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult, BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult,
StaticNATVirtualMachineInNetwork.Factory staticNATVMInNetwork, StaticNATVirtualMachineInNetwork.Factory staticNATVMInNetwork,
CreatePortForwardingRulesForIP setupPortForwardingRulesForIP, CreatePortForwardingRulesForIP setupPortForwardingRulesForIP,
CreateFirewallRulesForIP setupFirewallRulesForIP, CreateFirewallRulesForIP setupFirewallRulesForIP,
LoadingCache<String, Set<IPForwardingRule>> vmToRules, LoadingCache<String, Set<IPForwardingRule>> vmToRules,
Map<String, Credentials> credentialStore, Map<NetworkType, ? extends OptionsConverter> optionsConverters, Map<String, Credentials> credentialStore,
Supplier<LoadingCache<String, Zone>> zoneIdToZone) { Map<NetworkType, ? extends OptionsConverter> optionsConverters,
Supplier<LoadingCache<String, Zone>> zoneIdToZone) {
this.client = checkNotNull(client, "client"); this.client = checkNotNull(client, "client");
this.jobComplete = checkNotNull(jobComplete, "jobComplete"); this.jobComplete = checkNotNull(jobComplete, "jobComplete");
this.networkSupplier = checkNotNull(networkSupplier, "networkSupplier"); this.networkSupplier = checkNotNull(networkSupplier, "networkSupplier");
this.blockUntilJobCompletesAndReturnResult = checkNotNull(blockUntilJobCompletesAndReturnResult, this.blockUntilJobCompletesAndReturnResult = checkNotNull(blockUntilJobCompletesAndReturnResult,
"blockUntilJobCompletesAndReturnResult"); "blockUntilJobCompletesAndReturnResult");
this.staticNATVMInNetwork = checkNotNull(staticNATVMInNetwork, "staticNATVMInNetwork"); this.staticNATVMInNetwork = checkNotNull(staticNATVMInNetwork, "staticNATVMInNetwork");
this.setupPortForwardingRulesForIP = checkNotNull(setupPortForwardingRulesForIP, "setupPortForwardingRulesForIP"); this.setupPortForwardingRulesForIP = checkNotNull(setupPortForwardingRulesForIP, "setupPortForwardingRulesForIP");
this.setupFirewallRulesForIP = checkNotNull(setupFirewallRulesForIP, "setupFirewallRulesForIP"); this.setupFirewallRulesForIP = checkNotNull(setupFirewallRulesForIP, "setupFirewallRulesForIP");
@ -125,12 +125,12 @@ public class CloudStackComputeServiceAdapter implements
@Override @Override
public NodeAndInitialCredentials<VirtualMachine> createNodeWithGroupEncodedIntoName(String group, String name, public NodeAndInitialCredentials<VirtualMachine> createNodeWithGroupEncodedIntoName(String group, String name,
org.jclouds.compute.domain.Template template) { org.jclouds.compute.domain.Template template) {
checkNotNull(template, "template was null"); checkNotNull(template, "template was null");
checkNotNull(template.getOptions(), "template options was null"); checkNotNull(template.getOptions(), "template options was null");
checkArgument(template.getOptions().getClass().isAssignableFrom(CloudStackTemplateOptions.class), checkArgument(template.getOptions().getClass().isAssignableFrom(CloudStackTemplateOptions.class),
"options class %s should have been assignable from CloudStackTemplateOptions", template.getOptions() "options class %s should have been assignable from CloudStackTemplateOptions", template.getOptions()
.getClass()); .getClass());
Map<String, Network> networks = networkSupplier.get(); Map<String, Network> networks = networkSupplier.get();
final String zoneId = template.getLocation().getId(); final String zoneId = template.getLocation().getId();
@ -143,7 +143,7 @@ public class CloudStackComputeServiceAdapter implements
CloudStackTemplateOptions templateOptions = template.getOptions().as(CloudStackTemplateOptions.class); CloudStackTemplateOptions templateOptions = template.getOptions().as(CloudStackTemplateOptions.class);
checkState(optionsConverters.containsKey(zone.getNetworkType()), "no options converter configured for network type %s",zone.getNetworkType()); checkState(optionsConverters.containsKey(zone.getNetworkType()), "no options converter configured for network type %s", zone.getNetworkType());
DeployVirtualMachineOptions options = displayName(name).name(name); DeployVirtualMachineOptions options = displayName(name).name(name);
OptionsConverter optionsConverter = optionsConverters.get(zone.getNetworkType()); OptionsConverter optionsConverter = optionsConverters.get(zone.getNetworkType());
options = optionsConverter.apply(templateOptions, networks, zoneId, options); options = optionsConverter.apply(templateOptions, networks, zoneId, options);
@ -160,9 +160,9 @@ public class CloudStackComputeServiceAdapter implements
options.keyPair(templateOptions.getKeyPair()); options.keyPair(templateOptions.getKeyPair());
if (templateOptions.getRunScript() != null) { if (templateOptions.getRunScript() != null) {
checkArgument( checkArgument(
credentialStore.containsKey("keypair#" + templateOptions.getKeyPair()), credentialStore.containsKey("keypair#" + templateOptions.getKeyPair()),
"no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)", "no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)",
templateOptions.getKeyPair()); templateOptions.getKeyPair());
} }
} }
@ -170,10 +170,10 @@ public class CloudStackComputeServiceAdapter implements
String serviceOfferingId = template.getHardware().getId(); String serviceOfferingId = template.getHardware().getId();
logger.info("serviceOfferingId %s, templateId %s, zoneId %s, options %s%n", serviceOfferingId, templateId, logger.info("serviceOfferingId %s, templateId %s, zoneId %s, options %s%n", serviceOfferingId, templateId,
zoneId, options); zoneId, options);
AsyncCreateResponse job = client.getVirtualMachineClient().deployVirtualMachineInZone(zoneId, serviceOfferingId, AsyncCreateResponse job = client.getVirtualMachineClient().deployVirtualMachineInZone(zoneId, serviceOfferingId,
templateId, options); templateId, options);
VirtualMachine vm = blockUntilJobCompletesAndReturnResult.<VirtualMachine> apply(job); VirtualMachine vm = blockUntilJobCompletesAndReturnResult.<VirtualMachine>apply(job);
logger.debug("--- virtualmachine: %s", vm); logger.debug("--- virtualmachine: %s", vm);
LoginCredentials credentials = null; LoginCredentials credentials = null;
if (vm.isPasswordEnabled()) { if (vm.isPasswordEnabled()) {
@ -183,7 +183,7 @@ public class CloudStackComputeServiceAdapter implements
credentials = LoginCredentials.fromCredentials(credentialStore.get("keypair#" + templateOptions.getKeyPair())); credentials = LoginCredentials.fromCredentials(credentialStore.get("keypair#" + templateOptions.getKeyPair()));
} }
if (templateOptions.shouldSetupStaticNat()) { if (templateOptions.shouldSetupStaticNat()) {
Capabilities capabilities = client.getConfigurationClient().listCapabilities(); Capabilities capabilities = client.getConfigurationClient().listCapabilities();
// TODO: possibly not all network ids, do we want to do this // TODO: possibly not all network ids, do we want to do this
for (String networkId : options.getNetworkIds()) { for (String networkId : options.getNetworkIds()) {
logger.debug(">> creating static NAT for virtualMachine(%s) in network(%s)", vm.getId(), networkId); logger.debug(">> creating static NAT for virtualMachine(%s) in network(%s)", vm.getId(), networkId);
@ -192,13 +192,13 @@ public class CloudStackComputeServiceAdapter implements
vm = client.getVirtualMachineClient().getVirtualMachine(vm.getId()); vm = client.getVirtualMachineClient().getVirtualMachine(vm.getId());
List<Integer> ports = Ints.asList(templateOptions.getInboundPorts()); List<Integer> ports = Ints.asList(templateOptions.getInboundPorts());
if (capabilities.getCloudStackVersion().startsWith("2")) { if (capabilities.getCloudStackVersion().startsWith("2")) {
logger.debug(">> setting up IP forwarding for IPAddress(%s) rules(%s)", ip.getId(), ports); logger.debug(">> setting up IP forwarding for IPAddress(%s) rules(%s)", ip.getId(), ports);
Set<IPForwardingRule> rules = setupPortForwardingRulesForIP.apply(ip, ports); Set<IPForwardingRule> rules = setupPortForwardingRulesForIP.apply(ip, ports);
logger.trace("<< setup %d IP forwarding rules on IPAddress(%s)", rules.size(), ip.getId()); logger.trace("<< setup %d IP forwarding rules on IPAddress(%s)", rules.size(), ip.getId());
} else { } else {
logger.debug(">> setting up firewall rules for IPAddress(%s) rules(%s)", ip.getId(), ports); logger.debug(">> setting up firewall rules for IPAddress(%s) rules(%s)", ip.getId(), ports);
Set<FirewallRule> rules = setupFirewallRulesForIP.apply(ip, ports); Set<FirewallRule> rules = setupFirewallRulesForIP.apply(ip, ports);
logger.trace("<< setup %d firewall rules on IPAddress(%s)", rules.size(), ip.getId()); logger.trace("<< setup %d firewall rules on IPAddress(%s)", rules.size(), ip.getId());
} }
} }
} }
@ -310,7 +310,7 @@ public class CloudStackComputeServiceAdapter implements
Set<String> ipAddresses = Sets.newLinkedHashSet(); Set<String> ipAddresses = Sets.newLinkedHashSet();
Set<IPForwardingRule> forwardingRules = client.getNATClient().getIPForwardingRulesForVirtualMachine( Set<IPForwardingRule> forwardingRules = client.getNATClient().getIPForwardingRulesForVirtualMachine(
virtualMachineId); virtualMachineId);
for (IPForwardingRule rule : forwardingRules) { for (IPForwardingRule rule : forwardingRules) {
if (!"Deleting".equals(rule.getState())) { if (!"Deleting".equals(rule.getState())) {
ipAddresses.add(rule.getIPAddressId()); ipAddresses.add(rule.getIPAddressId());
@ -331,16 +331,16 @@ public class CloudStackComputeServiceAdapter implements
String publicIpId = client.getVirtualMachineClient().getVirtualMachine(virtualMachineId).getPublicIPId(); String publicIpId = client.getVirtualMachineClient().getVirtualMachine(virtualMachineId).getPublicIPId();
if (publicIpId != null) { if (publicIpId != null) {
Set<FirewallRule> firewallRules = client.getFirewallClient() Set<FirewallRule> firewallRules = client.getFirewallClient()
.listFirewallRules(ListFirewallRulesOptions.Builder.ipAddressId(client.getVirtualMachineClient().getVirtualMachine(virtualMachineId).getPublicIPId())); .listFirewallRules(ListFirewallRulesOptions.Builder.ipAddressId(client.getVirtualMachineClient().getVirtualMachine(virtualMachineId).getPublicIPId()));
for (FirewallRule rule : firewallRules) { for (FirewallRule rule : firewallRules) {
if (!FirewallRule.State.fromValue("DELETING").equals(rule.getState())) { if (!FirewallRule.State.fromValue("DELETING").equals(rule.getState())) {
ipAddresses.add(rule.getIpAddressId()); ipAddresses.add(rule.getIpAddressId());
client.getFirewallClient().deleteFirewallRule(rule.getId()); client.getFirewallClient().deleteFirewallRule(rule.getId());
logger.debug(">> deleting FirewallRule(%s)", rule.getId()); logger.debug(">> deleting FirewallRule(%s)", rule.getId());
} }
} }
} }
return ipAddresses; return ipAddresses;
} }

View File

@ -0,0 +1,33 @@
package org.jclouds.cloudstack.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.domain.FirewallRule;
import org.jclouds.cloudstack.options.ListFirewallRulesOptions;
@Singleton
public class GetFirewallRulesByVirtualMachine extends CacheLoader<String, Set<FirewallRule>> {
private final CloudStackClient client;
@Inject
public GetFirewallRulesByVirtualMachine(CloudStackClient client) {
this.client = checkNotNull(client, "client");
}
/**
* @throws org.jclouds.rest.ResourceNotFoundException
* when there is no ip forwarding rule available for the VM
*/
@Override
public Set<FirewallRule> load(String input) {
String publicIPId = client.getVirtualMachineClient().getVirtualMachine(input).getPublicIPId();
Set<FirewallRule> rules = client.getFirewallClient()
.listFirewallRules(ListFirewallRulesOptions.Builder.ipAddressId(publicIPId));
return rules != null ? rules : ImmutableSet.<FirewallRule>of();
}
}

View File

@ -0,0 +1,30 @@
package org.jclouds.cloudstack.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.domain.IPForwardingRule;
@Singleton
public class GetIPForwardingRulesByVirtualMachine extends CacheLoader<String, Set<IPForwardingRule>> {
private final CloudStackClient client;
@Inject
public GetIPForwardingRulesByVirtualMachine(CloudStackClient client) {
this.client = checkNotNull(client, "client");
}
/**
* @throws org.jclouds.rest.ResourceNotFoundException
* when there is no ip forwarding rule available for the VM
*/
@Override
public Set<IPForwardingRule> load(String input) {
Set<IPForwardingRule> rules = client.getNATClient().getIPForwardingRulesForVirtualMachine(input);
return rules != null ? rules : ImmutableSet.<IPForwardingRule>of();
}
}

View File

@ -21,6 +21,9 @@ package org.jclouds.cloudstack.compute;
import static com.google.common.collect.Iterables.getFirst; import static com.google.common.collect.Iterables.getFirst;
import static com.google.inject.name.Names.bindProperties; import static com.google.inject.name.Names.bindProperties;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import org.jclouds.cloudstack.domain.FirewallRule;
import org.jclouds.cloudstack.functions.GetFirewallRulesByVirtualMachine;
import org.jclouds.cloudstack.functions.GetIPForwardingRulesByVirtualMachine;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertFalse;
@ -33,7 +36,6 @@ import javax.inject.Singleton;
import org.jclouds.cloudstack.CloudStackClient; import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.compute.config.CloudStackComputeServiceContextModule; import org.jclouds.cloudstack.compute.config.CloudStackComputeServiceContextModule;
import org.jclouds.cloudstack.compute.config.CloudStackComputeServiceContextModule.GetIPForwardingRulesByVirtualMachine;
import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions; import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
import org.jclouds.cloudstack.compute.strategy.CloudStackComputeServiceAdapter; import org.jclouds.cloudstack.compute.strategy.CloudStackComputeServiceAdapter;
import org.jclouds.cloudstack.compute.strategy.OptionsConverter; import org.jclouds.cloudstack.compute.strategy.OptionsConverter;
@ -113,6 +115,10 @@ public class CloudStackComputeServiceAdapterLiveTest extends BaseCloudStackClien
bind(new TypeLiteral<Map<NetworkType, ? extends OptionsConverter>>() {}). bind(new TypeLiteral<Map<NetworkType, ? extends OptionsConverter>>() {}).
toInstance(new CloudStackComputeServiceContextModule().optionsConverters()); toInstance(new CloudStackComputeServiceContextModule().optionsConverters());
bind(String.class).annotatedWith(Names.named(PROPERTY_SESSION_INTERVAL)).toInstance("60"); bind(String.class).annotatedWith(Names.named(PROPERTY_SESSION_INTERVAL)).toInstance("60");
bind(new TypeLiteral<CacheLoader<String, Set<IPForwardingRule>>>() {
}).to(GetIPForwardingRulesByVirtualMachine.class);
bind(new TypeLiteral<CacheLoader<String, Set<FirewallRule>>>() {
}).to(GetFirewallRulesByVirtualMachine.class);
bind(new TypeLiteral<CacheLoader<String, Zone>>() {}). bind(new TypeLiteral<CacheLoader<String, Zone>>() {}).
to(ZoneIdToZone.class); to(ZoneIdToZone.class);
bind(new TypeLiteral<Supplier<LoadingCache<String, Zone>>>() {}). bind(new TypeLiteral<Supplier<LoadingCache<String, Zone>>>() {}).
@ -127,12 +133,19 @@ public class CloudStackComputeServiceAdapterLiveTest extends BaseCloudStackClien
return new RetryablePredicate<String>(jobComplete, 1200, 1, 5, TimeUnit.SECONDS); return new RetryablePredicate<String>(jobComplete, 1200, 1, 5, TimeUnit.SECONDS);
} }
@SuppressWarnings("unused")
@Provides @Provides
@Singleton @Singleton
protected LoadingCache<String, Set<IPForwardingRule>> getIPForwardingRuleByVirtualMachine( protected LoadingCache<String, Set<IPForwardingRule>> getIPForwardingRulesByVirtualMachine(
GetIPForwardingRulesByVirtualMachine getIPForwardingRule) { GetIPForwardingRulesByVirtualMachine getIPForwardingRules) {
return CacheBuilder.newBuilder().build(getIPForwardingRule); return CacheBuilder.newBuilder().build(getIPForwardingRules);
}
@Provides
@Singleton
protected LoadingCache<String, Set<FirewallRule>> getFirewallRulesByVirtualMachine(
GetFirewallRulesByVirtualMachine getFirewallRules) {
return CacheBuilder.newBuilder().build(getFirewallRules);
} }
}; };
adapter = Guice.createInjector(module, new SLF4JLoggingModule()).getInstance( adapter = Guice.createInjector(module, new SLF4JLoggingModule()).getInstance(
@ -176,9 +189,9 @@ public class CloudStackComputeServiceAdapterLiveTest extends BaseCloudStackClien
client.getNATClient().getIPForwardingRulesForVirtualMachine(vm.getNode().getId()), null); client.getNATClient().getIPForwardingRulesForVirtualMachine(vm.getNode().getId()), null);
String address = rule != null ? rule.getIPAddress() : vm.getNode().getIPAddress(); String address = rule != null ? rule.getIPAddress() : vm.getNode().getIPAddress();
loginCredentials = prioritizeCredentialsFromTemplate.apply(template, vm.getCredentials()); loginCredentials = prioritizeCredentialsFromTemplate.apply(template, vm.getCredentials());
assert InetAddresses.isInetAddress(address) : vm; assert InetAddresses.isInetAddress(address) : vm;
HostAndPort socket = HostAndPort.fromParts(address, 22); HostAndPort socket = HostAndPort.fromParts(address, 22);
checkSSH(socket); checkSSH(socket);

View File

@ -28,7 +28,6 @@ import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jclouds.cloudstack.compute.config.CloudStackComputeServiceContextModule.GetIPForwardingRulesByVirtualMachine;
import org.jclouds.cloudstack.domain.IPForwardingRule; import org.jclouds.cloudstack.domain.IPForwardingRule;
import org.jclouds.cloudstack.domain.Network; import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.PublicIPAddress;