diff --git a/.gitignore b/.gitignore index af4d3baf996..784ca1b1ba3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ dist/ cloud-*.tar.bz2 *.log *.pyc +*.cfg build.number api.log.*.gz cloud.log.*.* @@ -23,4 +24,4 @@ unittest deps/cloud.userlibraries .DS_Store .idea -*.iml \ No newline at end of file +*.iml diff --git a/INSTALL.txt b/INSTALL.txt index 081d1ace2e8..564dd5727d4 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -11,6 +11,16 @@ yum install ant ant-devel openjdk openjdk-devel mysql mysql-server tomcat Dependencies: yum install jakarta-commons-collections jakarta-commons-dbcp.noarch apache-commons-logging.noarch jakarta-commons-pool jakarta-commons-httpclient.noarch ws-commons-util.noarch glibc-devel gcc python MySQL-python openssh-clients +Tomcat: +Download tomcat6.0.33 from http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.33/bin/ instead of using distribution's default tomcat. Set CATALINA_HOME and CATALINA_BASE to path where you extract tomcat in environment variable, it would be better off setting them in .bashrc as it will take effect every time you log in. + +Note: Tomcat6.0.35 has some known issue with CloudStack, please avoid it + +SSHKEY: +Run: +sh-keygen -t rsa -q +to create sshkey for your account if you don't have one + Step 2: Configuration Start the MySQL service : diff --git a/agent-simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java b/agent-simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java index 6e2be2f31d1..e59824f0cdb 100755 --- a/agent-simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java +++ b/agent-simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java @@ -29,7 +29,9 @@ import com.cloud.agent.api.MaintainAnswer; import com.cloud.agent.api.PingTestCommand; import com.cloud.agent.api.PrepareForMigrationAnswer; import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.StartupCommand; import com.cloud.dc.dao.HostPodDao; +import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.resource.AgentResourceBase; import com.cloud.resource.AgentRoutingResource; @@ -261,21 +263,20 @@ public class MockAgentManagerImpl implements MockAgentManager { AgentStorageResource storageResource = new AgentStorageResource(); try { Map params = new HashMap(); + Map details = new HashMap(); params.put("guid", this.guid); + details.put("guid", this.guid); storageResource.configure("secondaryStorage", params); storageResource.start(); + //on the simulator the ssvm is as good as a direct agent + _resourceMgr.addHost(mockHost.getDataCenterId(), storageResource, Host.Type.SecondaryStorageVM, details); + _resources.put(this.guid, storageResource); } catch (ConfigurationException e) { s_logger.debug("Failed to load secondary storage resource: " + e.toString()); return; } - Map details = new HashMap(); - - _resourceMgr.addHost(this.dcId, storageResource, Type.SecondaryStorageVM, details); - _resources.put(this.guid, storageResource); - } - + } } - } @Override diff --git a/agent-simulator/src/com/cloud/resource/AgentStorageResource.java b/agent-simulator/src/com/cloud/resource/AgentStorageResource.java index 48793257d04..9bc0f48afdc 100644 --- a/agent-simulator/src/com/cloud/resource/AgentStorageResource.java +++ b/agent-simulator/src/com/cloud/resource/AgentStorageResource.java @@ -18,6 +18,7 @@ import com.cloud.agent.api.ReadyAnswer; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupSecondaryStorageCommand; +import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.storage.ssCommand; import com.cloud.agent.manager.SimulatorManager; import com.cloud.agent.manager.SimulatorManager.AgentType; @@ -67,7 +68,7 @@ public class AgentStorageResource extends AgentResourceBase implements Secondary @Override public StartupCommand[] initialize() { - StartupSecondaryStorageCommand cmd = new StartupSecondaryStorageCommand(); + StartupSecondaryStorageCommand cmd = new StartupSecondaryStorageCommand(); cmd.setPrivateIpAddress(agentHost.getPrivateIpAddress()); cmd.setPrivateNetmask(agentHost.getPrivateNetMask()); diff --git a/agent-simulator/src/com/cloud/resource/SimulatorDiscoverer.java b/agent-simulator/src/com/cloud/resource/SimulatorDiscoverer.java index 3b9b789e4f4..420853def10 100755 --- a/agent-simulator/src/com/cloud/resource/SimulatorDiscoverer.java +++ b/agent-simulator/src/com/cloud/resource/SimulatorDiscoverer.java @@ -307,7 +307,6 @@ public class SimulatorDiscoverer extends DiscovererBase implements Discoverer, L @Override public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { - // TODO Auto-generated method stub return null; } @@ -331,7 +330,6 @@ public class SimulatorDiscoverer extends DiscovererBase implements Discoverer, L @Override public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { - // TODO Auto-generated method stub return null; } diff --git a/agent-simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java b/agent-simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java index d3b74f29057..6fd0c6e226f 100644 --- a/agent-simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java +++ b/agent-simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java @@ -6,17 +6,34 @@ import java.util.Map; import javax.ejb.Local; import javax.naming.ConfigurationException; +import com.cloud.agent.AgentManager; +import com.cloud.agent.Listener; +import com.cloud.agent.api.AgentControlAnswer; +import com.cloud.agent.api.AgentControlCommand; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupSecondaryStorageCommand; import com.cloud.agent.manager.MockStorageManager; +import com.cloud.exception.ConnectionException; import com.cloud.host.HostVO; +import com.cloud.host.Status; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.secondary.SecondaryStorageDiscoverer; import com.cloud.utils.component.Inject; +import com.cloud.utils.exception.CloudRuntimeException; @Local(value=Discoverer.class) -public class SimulatorSecondaryDiscoverer extends SecondaryStorageDiscoverer { - @Inject - MockStorageManager _mockStorageMgr = null; +public class SimulatorSecondaryDiscoverer extends SecondaryStorageDiscoverer implements ResourceStateAdapter, Listener { + @Inject MockStorageManager _mockStorageMgr = null; + @Inject AgentManager _agentMgr; + @Inject ResourceManager _resourceMgr; + @Inject SnapshotDao _snapshotDao; @Override public boolean configure(String name, Map params) throws ConfigurationException { + _agentMgr.registerForHostEvents(this, true, false, false); + _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); return super.configure(name, params); } @@ -27,4 +44,92 @@ public class SimulatorSecondaryDiscoverer extends SecondaryStorageDiscoverer { _mockStorageMgr.preinstallTemplates(host.getStorageUrl(), host.getDataCenterId()); } } + + @Override + public HostVO createHostVOForConnectedAgent(HostVO host, + StartupCommand[] cmd) { + return null; + } + + @Override + public HostVO createHostVOForDirectConnectAgent(HostVO host, + StartupCommand[] startup, ServerResource resource, + Map details, List hostTags) { + //for detecting SSVM dispatch + StartupCommand firstCmd = startup[0]; + if (!(firstCmd instanceof StartupSecondaryStorageCommand)) { + return null; + } + + host.setType(com.cloud.host.Host.Type.SecondaryStorageVM); + return host; + } + + @Override + public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, + boolean isForceDeleteStorage) throws UnableDeleteHostException { + long hostId = host.getId(); + List snapshots = _snapshotDao.listByHostId(hostId); + if (snapshots != null && !snapshots.isEmpty()) { + throw new CloudRuntimeException("Cannot delete this secondary storage because there are still snapshots on it "); + } + _vmTemplateHostDao.deleteByHost(hostId); + host.setGuid(null); + _hostDao.update(hostId, host); + _hostDao.remove(hostId); + return new DeleteHostAnswer(true); + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + _resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName()); + return true; + } + + @Override + public int getTimeout() { + return 0; + } + + @Override + public boolean isRecurring() { + return false; + } + + @Override + public boolean processAnswers(long agentId, long seq, Answer[] answers) { + return false; + } + + @Override + public boolean processCommands(long agentId, long seq, Command[] commands) { + return false; + } + + @Override + public void processConnect(HostVO host, StartupCommand cmd, + boolean forRebalance) throws ConnectionException { + + } + + @Override + public AgentControlAnswer processControlCommand(long agentId, + AgentControlCommand cmd) { + return null; + } + + @Override + public boolean processDisconnect(long agentId, Status state) { + return false; + } + + @Override + public boolean processTimeout(long agentId, long seq) { + return false; + } } diff --git a/agent/distro/ubuntu/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/ubuntu/SYSCONFDIR/init.d/cloud-agent.in index 0c09f1e3b94..099df35c43a 100755 --- a/agent/distro/ubuntu/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/ubuntu/SYSCONFDIR/init.d/cloud-agent.in @@ -37,10 +37,10 @@ wait_for_network() { if ip addr show cloudbr0 |grep -w inet > /dev/null 2>&1; then break else + sleep 1 + let i=$i+1 continue fi - sleep 1 - let i=$i+1 done } diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java index 28241e259a7..e5b5facb0f0 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java @@ -1993,7 +1993,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv getUsage.add("-d", vif); } - getUsage.add(" -i ", privateIpAddress); + getUsage.add("-i", privateIpAddress); final OutputInterpreter.OneLineParser usageParser = new OutputInterpreter.OneLineParser(); String result = getUsage.execute(usageParser); if (result != null) { @@ -3434,8 +3434,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } if (oldStats != null) { - stats.setNetworkReadKBs((rx - oldStats._rx)/1000); - stats.setNetworkWriteKBs((tx - oldStats._tx)/1000); + long deltarx = rx - oldStats._rx; + if (deltarx > 0) + stats.setNetworkReadKBs(deltarx/1000); + long deltatx = tx - oldStats._tx; + if (deltatx > 0) + stats.setNetworkWriteKBs(deltatx/1000); } vmStats newStat = new vmStats(); diff --git a/api/src/com/cloud/acl/SecurityChecker.java b/api/src/com/cloud/acl/SecurityChecker.java index e0438610a3e..3d5c7c9d3a3 100644 --- a/api/src/com/cloud/acl/SecurityChecker.java +++ b/api/src/com/cloud/acl/SecurityChecker.java @@ -21,7 +21,6 @@ */ package com.cloud.acl; -import com.cloud.acl.SecurityChecker.AccessType; import com.cloud.dc.DataCenter; import com.cloud.domain.Domain; import com.cloud.exception.PermissionDeniedException; diff --git a/api/src/com/cloud/api/BaseCmd.java b/api/src/com/cloud/api/BaseCmd.java index 25c2b1cebd4..14f3b59ce5d 100755 --- a/api/src/com/cloud/api/BaseCmd.java +++ b/api/src/com/cloud/api/BaseCmd.java @@ -35,6 +35,7 @@ import com.cloud.domain.Domain; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.NetworkService; @@ -459,7 +460,7 @@ public abstract class BaseCmd { return this.fullUrlParams; } - public Long getAccountId(String accountName, Long domainId, Long projectId) { + public Long finalyzeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly) { if (accountName != null) { if (domainId == null) { throw new InvalidParameterValueException("Account must be specified with domainId parameter"); @@ -472,27 +473,28 @@ public abstract class BaseCmd { Account account = _accountService.getActiveAccountByName(accountName, domainId); if (account != null && account.getType() != Account.ACCOUNT_TYPE_PROJECT) { - return account.getId(); + if (!enabledOnly || account.getState() == Account.State.enabled) { + return account.getId(); + } else { + throw new PermissionDeniedException("Can't add resources to the account id=" + account.getId() + " in state=" + account.getState() + " as it's no longer active"); + } } else { throw new InvalidParameterValueException("Unable to find account by name " + accountName + " in domain id=" + domainId); } } if (projectId != null) { - Project project = _projectService.getProject(projectId); if (project != null) { - if (project.getState() == Project.State.Active) { + if (!enabledOnly || project.getState() == Project.State.Active) { return project.getProjectAccountId(); } else { - throw new InvalidParameterValueException("Can't add resources to the project id=" + projectId + " in state=" + project.getState() + " as it's no longer active"); + throw new PermissionDeniedException("Can't add resources to the project id=" + projectId + " in state=" + project.getState() + " as it's no longer active"); } - } else { throw new InvalidParameterValueException("Unable to find project by id " + projectId); } } - return null; } } diff --git a/api/src/com/cloud/api/commands/AddVpnUserCmd.java b/api/src/com/cloud/api/commands/AddVpnUserCmd.java index c605b328af1..6336b98bf89 100644 --- a/api/src/com/cloud/api/commands/AddVpnUserCmd.java +++ b/api/src/com/cloud/api/commands/AddVpnUserCmd.java @@ -96,7 +96,7 @@ public class AddVpnUserCmd extends BaseAsyncCreateCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/AssignVMCmd.java b/api/src/com/cloud/api/commands/AssignVMCmd.java index a89e95580b6..51b06cd3e2e 100644 --- a/api/src/com/cloud/api/commands/AssignVMCmd.java +++ b/api/src/com/cloud/api/commands/AssignVMCmd.java @@ -18,6 +18,9 @@ package com.cloud.api.commands; +import java.util.ArrayList; +import java.util.List; + import org.apache.log4j.Logger; import com.cloud.api.ApiConstants; @@ -32,6 +35,7 @@ import com.cloud.api.response.UserVmResponse; import com.cloud.api.response.ZoneResponse; import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -54,7 +58,12 @@ public class AssignVMCmd extends BaseCmd { @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="an optional domainId for the vpn user. If the account parameter is used, domainId must also be used.") private Long domainId; + //Network information + @IdentityMapper(entityTableName="networks") + @Parameter(name=ApiConstants.NETWORK_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="list of network ids that will be part of VM network after move") + private List networkIds; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -70,6 +79,10 @@ public class AssignVMCmd extends BaseCmd { public Long getDomainId() { return domainId; } + + public List getNetworkIds() { + return networkIds; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java index 234c17be3e2..6f454388fd2 100644 --- a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java +++ b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java @@ -129,7 +129,7 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/AuthorizeSecurityGroupEgressCmd.java b/api/src/com/cloud/api/commands/AuthorizeSecurityGroupEgressCmd.java index be522ccff34..c840bb3fe17 100644 --- a/api/src/com/cloud/api/commands/AuthorizeSecurityGroupEgressCmd.java +++ b/api/src/com/cloud/api/commands/AuthorizeSecurityGroupEgressCmd.java @@ -164,7 +164,7 @@ public class AuthorizeSecurityGroupEgressCmd extends BaseAsyncCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/AuthorizeSecurityGroupIngressCmd.java b/api/src/com/cloud/api/commands/AuthorizeSecurityGroupIngressCmd.java index c95cb5b7e1d..32f20ca91b0 100644 --- a/api/src/com/cloud/api/commands/AuthorizeSecurityGroupIngressCmd.java +++ b/api/src/com/cloud/api/commands/AuthorizeSecurityGroupIngressCmd.java @@ -166,7 +166,7 @@ public class AuthorizeSecurityGroupIngressCmd extends BaseAsyncCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/CreateNetworkCmd.java b/api/src/com/cloud/api/commands/CreateNetworkCmd.java index c7ff560c50c..87e5a2d3aad 100644 --- a/api/src/com/cloud/api/commands/CreateNetworkCmd.java +++ b/api/src/com/cloud/api/commands/CreateNetworkCmd.java @@ -199,7 +199,7 @@ public class CreateNetworkCmd extends BaseCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/CreateSSHKeyPairCmd.java b/api/src/com/cloud/api/commands/CreateSSHKeyPairCmd.java index b51c510e46d..5645aa8dfa2 100644 --- a/api/src/com/cloud/api/commands/CreateSSHKeyPairCmd.java +++ b/api/src/com/cloud/api/commands/CreateSSHKeyPairCmd.java @@ -80,7 +80,7 @@ public class CreateSSHKeyPairCmd extends BaseCmd { ///////////////////////////////////////////////////// @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/CreateSnapshotCmd.java b/api/src/com/cloud/api/commands/CreateSnapshotCmd.java index d10ae4899be..4186072d003 100755 --- a/api/src/com/cloud/api/commands/CreateSnapshotCmd.java +++ b/api/src/com/cloud/api/commands/CreateSnapshotCmd.java @@ -30,7 +30,10 @@ import com.cloud.api.ServerApiException; import com.cloud.api.response.SnapshotResponse; import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; +import com.cloud.projects.Project; import com.cloud.storage.Snapshot; import com.cloud.storage.Volume; import com.cloud.user.Account; @@ -103,13 +106,24 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd { @Override public long getEntityOwnerId() { + Volume volume = _entityMgr.findById(Volume.class, getVolumeId()); - if (volume != null) { - return volume.getAccountId(); + if (volume == null) { + throw new InvalidParameterValueException("Unable to find volume by id=" + volumeId); } - - // bad id given, parent this command to SYSTEM so ERROR events are tracked - return Account.ACCOUNT_ID_SYSTEM; + + Account account = _accountService.getAccount(volume.getAccountId()); + //Can create templates for enabled projects/accounts only + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + Project project = _projectService.findByProjectAccountId(volume.getAccountId()); + if (project.getState() != Project.State.Active) { + throw new PermissionDeniedException("Can't add resources to the project id=" + project.getId() + " in state=" + project.getState() + " as it's no longer active"); + } + } else if (account.getState() == Account.State.disabled) { + throw new PermissionDeniedException("The owner of template is disabled: " + account); + } + + return volume.getAccountId(); } @Override @@ -140,7 +154,7 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd { @Override public void execute() { UserContext.current().setEventDetails("Volume Id: "+getVolumeId()); - Snapshot snapshot = _snapshotService.createSnapshot(getVolumeId(), getPolicyId(), getEntityId()); + Snapshot snapshot = _snapshotService.createSnapshot(getVolumeId(), getPolicyId(), getEntityId(), _accountService.getAccount(getEntityOwnerId())); if (snapshot != null) { SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/api/commands/CreateSnapshotPolicyCmd.java b/api/src/com/cloud/api/commands/CreateSnapshotPolicyCmd.java index 23bfa1f0ca8..6052ab115df 100644 --- a/api/src/com/cloud/api/commands/CreateSnapshotPolicyCmd.java +++ b/api/src/com/cloud/api/commands/CreateSnapshotPolicyCmd.java @@ -27,6 +27,9 @@ import com.cloud.api.Implementation; import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; import com.cloud.api.response.SnapshotPolicyResponse; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.projects.Project; import com.cloud.storage.Volume; import com.cloud.storage.snapshot.SnapshotPolicy; import com.cloud.user.Account; @@ -100,16 +103,27 @@ public class CreateSnapshotPolicyCmd extends BaseCmd { @Override public long getEntityOwnerId() { Volume volume = _entityMgr.findById(Volume.class, getVolumeId()); - if (volume != null) { - return volume.getAccountId(); + if (volume == null) { + throw new InvalidParameterValueException("Unable to find volume by id=" + volumeId); } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + + Account account = _accountService.getAccount(volume.getAccountId()); + //Can create templates for enabled projects/accounts only + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + Project project = _projectService.findByProjectAccountId(volume.getAccountId()); + if (project.getState() != Project.State.Active) { + throw new PermissionDeniedException("Can't add resources to the project id=" + project.getId() + " in state=" + project.getState() + " as it's no longer active"); + } + } else if (account.getState() == Account.State.disabled) { + throw new PermissionDeniedException("The owner of template is disabled: " + account); + } + + return volume.getAccountId(); } @Override public void execute(){ - SnapshotPolicy result = _snapshotService.createPolicy(this); + SnapshotPolicy result = _snapshotService.createPolicy(this, _accountService.getAccount(getEntityOwnerId())); if (result != null) { SnapshotPolicyResponse response = _responseGenerator.createSnapshotPolicyResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/api/commands/CreateTemplateCmd.java b/api/src/com/cloud/api/commands/CreateTemplateCmd.java index 397f868346a..287d757f2b9 100755 --- a/api/src/com/cloud/api/commands/CreateTemplateCmd.java +++ b/api/src/com/cloud/api/commands/CreateTemplateCmd.java @@ -35,7 +35,10 @@ import com.cloud.api.response.StoragePoolResponse; import com.cloud.api.response.TemplateResponse; import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; +import com.cloud.projects.Project; import com.cloud.storage.Snapshot; import com.cloud.storage.Volume; import com.cloud.template.VirtualMachineTemplate; @@ -185,20 +188,35 @@ import com.cloud.user.UserContext; public long getEntityOwnerId() { Long volumeId = getVolumeId(); Long snapshotId = getSnapshotId(); + Long accountId = null; if (volumeId != null) { Volume volume = _entityMgr.findById(Volume.class, volumeId); if (volume != null) { - return volume.getAccountId(); + accountId = volume.getAccountId(); + } else { + throw new InvalidParameterValueException("Unable to find volume by id=" + volumeId); } } else { Snapshot snapshot = _entityMgr.findById(Snapshot.class, snapshotId); if (snapshot != null) { - return snapshot.getAccountId(); + accountId = snapshot.getAccountId(); + } else { + throw new InvalidParameterValueException("Unable to find snapshot by id=" + snapshotId); } } - - // bad id given, parent this command to SYSTEM so ERROR events are tracked - return Account.ACCOUNT_ID_SYSTEM; + + Account account = _accountService.getAccount(accountId); + //Can create templates for enabled projects/accounts only + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + Project project = _projectService.findByProjectAccountId(accountId); + if (project.getState() != Project.State.Active) { + throw new PermissionDeniedException("Can't add resources to the project id=" + project.getId() + " in state=" + project.getState() + " as it's no longer active"); + } + } else if (account.getState() == Account.State.disabled) { + throw new PermissionDeniedException("The owner of template is disabled: " + account); + } + + return accountId; } @Override @@ -223,13 +241,12 @@ import com.cloud.user.UserContext; @Override public void create() throws ResourceAllocationException { if (isBareMetal()) { - _bareMetalVmService.createPrivateTemplateRecord(this); + _bareMetalVmService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); /*Baremetal creates template record after taking image proceeded, use vmId as entity id here*/ this.setEntityId(vmId); } else { VirtualMachineTemplate template = null; - template = _userVmService.createPrivateTemplateRecord(this); - + template = _userVmService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); if (template != null) { this.setEntityId(template.getId()); } else { diff --git a/api/src/com/cloud/api/commands/CreateVMGroupCmd.java b/api/src/com/cloud/api/commands/CreateVMGroupCmd.java index 1593a98939b..a760612f7cc 100644 --- a/api/src/com/cloud/api/commands/CreateVMGroupCmd.java +++ b/api/src/com/cloud/api/commands/CreateVMGroupCmd.java @@ -84,7 +84,7 @@ public class CreateVMGroupCmd extends BaseCmd{ @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/CreateVolumeCmd.java b/api/src/com/cloud/api/commands/CreateVolumeCmd.java index 75713fdfe24..83924d0adf0 100644 --- a/api/src/com/cloud/api/commands/CreateVolumeCmd.java +++ b/api/src/com/cloud/api/commands/CreateVolumeCmd.java @@ -131,7 +131,7 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/DeleteSecurityGroupCmd.java b/api/src/com/cloud/api/commands/DeleteSecurityGroupCmd.java index 70cc1322438..7c6788a29e9 100644 --- a/api/src/com/cloud/api/commands/DeleteSecurityGroupCmd.java +++ b/api/src/com/cloud/api/commands/DeleteSecurityGroupCmd.java @@ -89,7 +89,7 @@ public class DeleteSecurityGroupCmd extends BaseCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/DeployVMCmd.java b/api/src/com/cloud/api/commands/DeployVMCmd.java index 71b59995180..56301acf8dc 100644 --- a/api/src/com/cloud/api/commands/DeployVMCmd.java +++ b/api/src/com/cloud/api/commands/DeployVMCmd.java @@ -281,7 +281,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/ListResourceLimitsCmd.java b/api/src/com/cloud/api/commands/ListResourceLimitsCmd.java index 06dc81506c0..45e6d11dfdb 100644 --- a/api/src/com/cloud/api/commands/ListResourceLimitsCmd.java +++ b/api/src/com/cloud/api/commands/ListResourceLimitsCmd.java @@ -94,7 +94,7 @@ public class ListResourceLimitsCmd extends BaseListCmd { @Override public void execute(){ - List result = _resourceLimitService.searchForLimits(id, getAccountId(accountName, domainId, projectId), domainId, resourceType, this.getStartIndex(), this.getPageSizeVal()); + List result = _resourceLimitService.searchForLimits(id, finalyzeAccountId(accountName, domainId, projectId, false), domainId, resourceType, this.getStartIndex(), this.getPageSizeVal()); ListResponse response = new ListResponse(); List limitResponses = new ArrayList(); for (ResourceLimit limit : result) { diff --git a/api/src/com/cloud/api/commands/RegisterIsoCmd.java b/api/src/com/cloud/api/commands/RegisterIsoCmd.java index 16b72a39950..47365e558c1 100755 --- a/api/src/com/cloud/api/commands/RegisterIsoCmd.java +++ b/api/src/com/cloud/api/commands/RegisterIsoCmd.java @@ -152,7 +152,7 @@ public class RegisterIsoCmd extends BaseCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/RegisterSSHKeyPairCmd.java b/api/src/com/cloud/api/commands/RegisterSSHKeyPairCmd.java index 8240d3af3eb..87c81f895f0 100644 --- a/api/src/com/cloud/api/commands/RegisterSSHKeyPairCmd.java +++ b/api/src/com/cloud/api/commands/RegisterSSHKeyPairCmd.java @@ -87,7 +87,7 @@ public class RegisterSSHKeyPairCmd extends BaseCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/RegisterTemplateCmd.java b/api/src/com/cloud/api/commands/RegisterTemplateCmd.java index 6b098149d17..dc4a2be7045 100755 --- a/api/src/com/cloud/api/commands/RegisterTemplateCmd.java +++ b/api/src/com/cloud/api/commands/RegisterTemplateCmd.java @@ -213,7 +213,7 @@ public class RegisterTemplateCmd extends BaseCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/RemoveVpnUserCmd.java b/api/src/com/cloud/api/commands/RemoveVpnUserCmd.java index cca05ed947e..d6370fc3115 100644 --- a/api/src/com/cloud/api/commands/RemoveVpnUserCmd.java +++ b/api/src/com/cloud/api/commands/RemoveVpnUserCmd.java @@ -88,7 +88,7 @@ public class RemoveVpnUserCmd extends BaseAsyncCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } diff --git a/api/src/com/cloud/api/commands/UpdateResourceCountCmd.java b/api/src/com/cloud/api/commands/UpdateResourceCountCmd.java index a5797382dec..05a52b5b9db 100644 --- a/api/src/com/cloud/api/commands/UpdateResourceCountCmd.java +++ b/api/src/com/cloud/api/commands/UpdateResourceCountCmd.java @@ -112,7 +112,7 @@ public class UpdateResourceCountCmd extends BaseCmd { @Override public void execute(){ - List result = _resourceLimitService.recalculateResourceCount(getAccountId(accountName, domainId, projectId), getDomainId(), getResourceType()); + List result = _resourceLimitService.recalculateResourceCount(finalyzeAccountId(accountName, domainId, projectId, true), getDomainId(), getResourceType()); if ((result != null) && (result.size()>0)){ ListResponse response = new ListResponse(); diff --git a/api/src/com/cloud/api/commands/UpdateResourceLimitCmd.java b/api/src/com/cloud/api/commands/UpdateResourceLimitCmd.java index e150f587f87..984cd31b746 100644 --- a/api/src/com/cloud/api/commands/UpdateResourceLimitCmd.java +++ b/api/src/com/cloud/api/commands/UpdateResourceLimitCmd.java @@ -89,7 +89,7 @@ public class UpdateResourceLimitCmd extends BaseCmd { @Override public long getEntityOwnerId() { - Long accountId = getAccountId(accountName, domainId, projectId); + Long accountId = finalyzeAccountId(accountName, domainId, projectId, true); if (accountId == null) { return UserContext.current().getCaller().getId(); } @@ -99,7 +99,7 @@ public class UpdateResourceLimitCmd extends BaseCmd { @Override public void execute(){ - ResourceLimit result = _resourceLimitService.updateResourceLimit(getAccountId(accountName, domainId, projectId), getDomainId(), resourceType, max); + ResourceLimit result = _resourceLimitService.updateResourceLimit(finalyzeAccountId(accountName, domainId, projectId, true), getDomainId(), resourceType, max); if (result != null || (result == null && max != null && max.longValue() == -1L)){ ResourceLimitResponse response = _responseGenerator.createResourceLimitResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/configuration/Resource.java b/api/src/com/cloud/configuration/Resource.java index 4c9cda41058..f9a05f09143 100644 --- a/api/src/com/cloud/configuration/Resource.java +++ b/api/src/com/cloud/configuration/Resource.java @@ -18,6 +18,8 @@ package com.cloud.configuration; public interface Resource { + + public static final short RESOURCE_UNLIMITED = -1; public enum ResourceType{ user_vm ("user_vm", 0, ResourceOwnerType.Account, ResourceOwnerType.Domain), diff --git a/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java b/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java index 32b9b4776e9..7d31f3cd7fe 100644 --- a/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java +++ b/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java @@ -4,6 +4,7 @@ import java.util.List; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; +import com.cloud.network.PublicIpAddress; import com.cloud.network.lb.LoadBalancingRule; public interface LoadBalancingServiceProvider extends NetworkElement { @@ -15,4 +16,13 @@ public interface LoadBalancingServiceProvider extends NetworkElement { * @throws ResourceUnavailableException */ boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException; + + /** + * Apply ip addresses to this network service provider + * @param network + * @param ipAddress + * @return + * @throws ResourceUnavailableException + */ + boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException; } diff --git a/api/src/com/cloud/network/element/PortForwardingServiceProvider.java b/api/src/com/cloud/network/element/PortForwardingServiceProvider.java index bdd6bc01da4..2bcdc8c7fa0 100644 --- a/api/src/com/cloud/network/element/PortForwardingServiceProvider.java +++ b/api/src/com/cloud/network/element/PortForwardingServiceProvider.java @@ -4,6 +4,7 @@ import java.util.List; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; +import com.cloud.network.PublicIpAddress; import com.cloud.network.rules.PortForwardingRule; public interface PortForwardingServiceProvider extends NetworkElement { @@ -15,4 +16,13 @@ public interface PortForwardingServiceProvider extends NetworkElement { * @throws ResourceUnavailableException */ boolean applyPFRules(Network network, List rules) throws ResourceUnavailableException; + + /** + * Apply ip addresses to this network service provider + * @param network + * @param ipAddress + * @return + * @throws ResourceUnavailableException + */ + boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException; } diff --git a/api/src/com/cloud/network/element/SourceNatServiceProvider.java b/api/src/com/cloud/network/element/SourceNatServiceProvider.java index d21e0b660a1..f42c445997c 100644 --- a/api/src/com/cloud/network/element/SourceNatServiceProvider.java +++ b/api/src/com/cloud/network/element/SourceNatServiceProvider.java @@ -1,4 +1,19 @@ package com.cloud.network.element; +import java.util.List; + +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.PublicIpAddress; + public interface SourceNatServiceProvider extends NetworkElement { + + /** + * Apply ip addresses to this network + * @param network + * @param ipAddress + * @return + * @throws ResourceUnavailableException + */ + boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException; } diff --git a/api/src/com/cloud/network/element/StaticNatServiceProvider.java b/api/src/com/cloud/network/element/StaticNatServiceProvider.java index c73ce2b77c5..c5c0608fe76 100644 --- a/api/src/com/cloud/network/element/StaticNatServiceProvider.java +++ b/api/src/com/cloud/network/element/StaticNatServiceProvider.java @@ -4,6 +4,7 @@ import java.util.List; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; +import com.cloud.network.PublicIpAddress; import com.cloud.network.rules.StaticNat; public interface StaticNatServiceProvider extends NetworkElement { @@ -15,4 +16,13 @@ public interface StaticNatServiceProvider extends NetworkElement { * @throws ResourceUnavailableException */ boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException; + + /** + * Apply ip addresses to this network service provider + * @param network + * @param ipAddress + * @return + * @throws ResourceUnavailableException + */ + boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException; } diff --git a/api/src/com/cloud/storage/snapshot/SnapshotService.java b/api/src/com/cloud/storage/snapshot/SnapshotService.java index 371396c5498..dbe84151034 100644 --- a/api/src/com/cloud/storage/snapshot/SnapshotService.java +++ b/api/src/com/cloud/storage/snapshot/SnapshotService.java @@ -27,6 +27,7 @@ import com.cloud.api.commands.ListSnapshotsCmd; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.storage.Snapshot; +import com.cloud.user.Account; public interface SnapshotService { @@ -53,9 +54,10 @@ public interface SnapshotService { * * @param cmd * the command that + * @param policyOwner TODO * @return the newly created snapshot policy if success, null otherwise */ - SnapshotPolicy createPolicy(CreateSnapshotPolicyCmd cmd); + SnapshotPolicy createPolicy(CreateSnapshotPolicyCmd cmd, Account policyOwner); /** * Get the recurring snapshots scheduled for this volume currently along with the time at which they are scheduled @@ -82,10 +84,11 @@ public interface SnapshotService { /** * Create a snapshot of a volume - * + * @param snapshotOwner TODO * @param cmd * the API command wrapping the parameters for creating the snapshot (mainly volumeId) + * * @return the Snapshot that was created */ - Snapshot createSnapshot(Long volumeId, Long policyId, Long snapshotId); + Snapshot createSnapshot(Long volumeId, Long policyId, Long snapshotId, Account snapshotOwner); } diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index 1cf2d3a012e..f8f2c7aafe7 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -123,10 +123,11 @@ public interface UserVmService { * @param cmd * the command object that defines the name, display text, snapshot/volume, bits, public/private, etc. for the * private template + * @param templateOwner TODO * @return the vm template object if successful, null otherwise * @throws ResourceAllocationException */ - VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd) throws ResourceAllocationException; + VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException; /** * Creates a private template from a snapshot of a VM diff --git a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java index d10e25da40b..65bc8d69fbc 100755 --- a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java +++ b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java @@ -462,6 +462,17 @@ public class VirtualRoutingResource implements Manager { command.add("-v", cmd.getVmIpAddress()); command.add("-m", cmd.getVmMac()); command.add("-n", cmd.getVmName()); + + if (cmd.getDefaultRouter() != null) { + command.add(" -d " + cmd.getDefaultRouter()); + } + if (cmd.getStaticRoutes() != null) { + command.add(" -s " + cmd.getStaticRoutes()); + } + + if (cmd.getDefaultDns() != null) { + command.add(" -N " + cmd.getDefaultDns()); + } final String result = command.execute(); return new Answer(cmd, result==null, result); diff --git a/core/src/com/cloud/configuration/ConfigurationVO.java b/core/src/com/cloud/configuration/ConfigurationVO.java index 95f32fd04db..3ddcbe1e307 100644 --- a/core/src/com/cloud/configuration/ConfigurationVO.java +++ b/core/src/com/cloud/configuration/ConfigurationVO.java @@ -22,6 +22,8 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; + +import com.cloud.utils.crypt.DBEncryptionUtil; @Entity @Table(name="configuration") @@ -36,7 +38,7 @@ public class ConfigurationVO implements Configuration{ @Column(name="name") private String name; - @Column(name="value", length=4095, encryptable=true) + @Column(name="value", length=4095) private String value; @Column(name="description", length=1024) @@ -88,8 +90,8 @@ public class ConfigurationVO implements Configuration{ this.name = name; } - public String getValue() { - return value; + public String getValue() { + return ("Hidden".equals(getCategory()) ? DBEncryptionUtil.decrypt(value) : value); } public void setValue(String value) { diff --git a/core/src/com/cloud/host/DetailVO.java b/core/src/com/cloud/host/DetailVO.java index d87081f25cb..021590a3c90 100644 --- a/core/src/com/cloud/host/DetailVO.java +++ b/core/src/com/cloud/host/DetailVO.java @@ -38,7 +38,7 @@ public class DetailVO { @Column(name="name") private String name; - @Column(name="value", encryptable=true) + @Column(name="value") private String value; protected DetailVO() { diff --git a/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 3d2fcfaf40a..857fc565630 100755 --- a/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -933,11 +933,24 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_logger.info("Executing resource DhcpEntryCommand: " + _gson.toJson(cmd)); } + // ssh -p 3922 -o StrictHostKeyChecking=no -i $cert root@$domr "/root/edithosts.sh $mac $ip $vm $dfltrt $ns $staticrt" >/dev/null String args = " " + cmd.getVmMac(); args += " " + cmd.getVmIpAddress(); - args += " " + cmd.getVmName(); - - if (s_logger.isDebugEnabled()) { + args += " " + cmd.getVmName(); + + if (cmd.getDefaultRouter() != null) { + args += " " + cmd.getDefaultRouter(); + } + + if (cmd.getDefaultDns() != null) { + args += " " + cmd.getDefaultDns(); + } + + if (cmd.getStaticRoutes() != null) { + args += " " + cmd.getStaticRoutes(); + } + + if (s_logger.isDebugEnabled()) { s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /root/edithosts.sh " + args); } diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 7df4998df27..15825ab8ff9 100755 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -253,7 +253,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe protected long _dcId; protected String _pod; protected String _cluster; - protected static final XenServerPoolVms s_vms = new XenServerPoolVms(); + private static final XenServerPoolVms s_vms = new XenServerPoolVms(); protected String _privateNetworkName; protected String _linkLocalPrivateNetworkName; protected String _publicNetworkName; @@ -1081,7 +1081,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } } - s_logger.debug("The VM " + vmName + " is in Starting state."); + s_logger.debug("1. The VM " + vmName + " is in Starting state."); s_vms.put(_cluster, _name, vmName, State.Starting); Host host = Host.getByUuid(conn, _host.uuid); @@ -1164,7 +1164,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } finally { synchronized (s_vms) { if (state != State.Stopped) { - s_logger.debug("The VM " + vmName + " is in " + state + " state."); + s_logger.debug("2. The VM " + vmName + " is in " + state + " state."); s_vms.put(_cluster, _name, vmName, state); } else { s_logger.debug("The VM is in stopped state, detected problem during startup : " + vmName); @@ -2168,7 +2168,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe Integer vncPort = null; if (state == State.Running) { synchronized (s_vms) { - s_logger.debug("The VM " + vmName + " is in " + State.Running + " state"); + s_logger.debug("3. The VM " + vmName + " is in " + State.Running + " state"); s_vms.put(_cluster, _name, vmName, State.Running); } } @@ -2191,7 +2191,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe for (NicTO nic : nics) { getNetwork(conn, nic); } - s_logger.debug("The VM " + vm.getName() + " is in " + State.Migrating + " state"); + s_logger.debug("4. The VM " + vm.getName() + " is in " + State.Migrating + " state"); s_vms.put(_cluster, _name, vm.getName(), State.Migrating); return new PrepareForMigrationAnswer(cmd); @@ -2428,7 +2428,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe state = s_vms.getState(_cluster, vmName); - s_logger.debug("The VM " + vmName + " is in " + State.Stopping + " state"); + s_logger.debug("5. The VM " + vmName + " is in " + State.Stopping + " state"); s_vms.put(_cluster, _name, vmName, State.Stopping); try { Set vms = VM.getByNameLabel(conn, vmName); @@ -2495,7 +2495,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.warn(msg, e); return new MigrateAnswer(cmd, false, msg, null); } finally { - s_logger.debug("The VM " + vmName + " is in " + state + " state"); + s_logger.debug("6. The VM " + vmName + " is in " + state + " state"); s_vms.put(_cluster, _name, vmName, state); } @@ -2618,7 +2618,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe @Override public RebootAnswer execute(RebootCommand cmd) { Connection conn = getConnection(); - s_logger.debug("The VM " + cmd.getVmName() + " is in " + State.Starting + " state"); + s_logger.debug("7. The VM " + cmd.getVmName() + " is in " + State.Starting + " state"); s_vms.put(_cluster, _name, cmd.getVmName(), State.Starting); try { Set vms = null; @@ -2642,7 +2642,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } return new RebootAnswer(cmd, "reboot succeeded", null, null); } finally { - s_logger.debug("The VM " + cmd.getVmName() + " is in " + State.Running + " state"); + s_logger.debug("8. The VM " + cmd.getVmName() + " is in " + State.Running + " state"); s_vms.put(_cluster, _name, cmd.getVmName(), State.Running); } } @@ -3136,7 +3136,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe State state = s_vms.getState(_cluster, vmName); - s_logger.debug("The VM " + vmName + " is in " + State.Stopping + " state"); + s_logger.debug("9. The VM " + vmName + " is in " + State.Stopping + " state"); s_vms.put(_cluster, _name, vmName, State.Stopping); try { @@ -3198,7 +3198,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String msg = "VM destroy failed in Stop " + vmName + " Command due to " + e.getMessage(); s_logger.warn(msg, e); } finally { - s_logger.debug("The VM " + vmName + " is in " + state + " state"); + s_logger.debug("10. The VM " + vmName + " is in " + state + " state"); s_vms.put(_cluster, _name, vmName, state); } } @@ -5442,25 +5442,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe if (!createSecondaryStorageFolder(conn, remoteVolumesMountPath, volumeFolder)) { throw new InternalErrorException("Failed to create the volume folder."); } - VDI vdi = VDI.getByUuid(conn, volumeUUID); - String pUuid = getVhdParent(conn, srUuid, vdi.getUuid(conn), IsISCSI(primaryStoragePool.getType(conn))); - if( pUuid != null ) { - SR secondaryStorage = null; - try { - // Create a SR for the volume UUID folder - secondaryStorage = createNfsSRbyURI(conn, new URI(secondaryStorageURL + "/volumes/" + volumeFolder), false); - // Look up the volume on the source primary storage pool - VDI srcVolume = getVDIbyUuid(conn, volumeUUID); - // Copy the volume to secondary storage - VDI destVolume = cloudVDIcopy(conn, srcVolume, secondaryStorage, wait); - String destVolumeUUID = destVolume.getUuid(conn); - return new CopyVolumeAnswer(cmd, true, null, null, destVolumeUUID); - } finally { - removeSR(conn, secondaryStorage); - } - } else { - String uuid = copy_vhd_to_secondarystorage(conn, mountpoint, volumeUUID, srUuid, wait); - return new CopyVolumeAnswer(cmd, true, null, null, uuid); + SR secondaryStorage = null; + try { + // Create a SR for the volume UUID folder + secondaryStorage = createNfsSRbyURI(conn, new URI(secondaryStorageURL + "/volumes/" + volumeFolder), false); + // Look up the volume on the source primary storage pool + VDI srcVolume = getVDIbyUuid(conn, volumeUUID); + // Copy the volume to secondary storage + VDI destVolume = cloudVDIcopy(conn, srcVolume, secondaryStorage, wait); + String destVolumeUUID = destVolume.getUuid(conn); + return new CopyVolumeAnswer(cmd, true, null, null, destVolumeUUID); + } finally { + removeSR(conn, secondaryStorage); } } else { try { @@ -6644,7 +6637,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.warn("Detecting a change in host for " + vm); changes.put(vm, new Pair(host_uuid, newState)); - s_logger.debug("The VM " + vm + " is in " + newState + " state"); + s_logger.debug("11. The VM " + vm + " is in " + newState + " state"); s_vms.put(_cluster, host_uuid, vm, newState); continue; } @@ -6668,7 +6661,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe changes.put(vm, new Pair(host_uuid, newState)); } else if (oldState.second() == State.Starting) { if (newState == State.Running) { - s_logger.debug("The VM " + vm + " is in " + State.Running + " state"); + s_logger.debug("12. The VM " + vm + " is in " + State.Running + " state"); s_vms.put(_cluster, host_uuid, vm, newState); } else if (newState == State.Stopped) { s_logger.warn("Ignoring vm " + vm + " because of a lag in starting the vm."); @@ -6680,13 +6673,13 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } else if (oldState.second() == State.Stopping) { if (newState == State.Stopped) { - s_logger.debug("The VM " + vm + " is in " + State.Stopped + " state"); + s_logger.debug("13. The VM " + vm + " is in " + State.Stopped + " state"); s_vms.put(_cluster, host_uuid, vm, newState); } else if (newState == State.Running) { s_logger.warn("Ignoring vm " + vm + " because of a lag in stopping the vm. "); } } else if (oldState.second() != newState) { - s_logger.debug("The VM " + vm + " is in " + newState + " state was " + oldState.second()); + s_logger.debug("14. The VM " + vm + " is in " + newState + " state was " + oldState.second()); s_vms.put(_cluster, host_uuid, vm, newState); if (newState == State.Stopped) { /* diff --git a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java index 678ad623fc2..b77edd9e948 100755 --- a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java +++ b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java @@ -153,6 +153,8 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return execute((ListTemplateCommand)cmd); } else if (cmd instanceof downloadSnapshotFromSwiftCommand){ return execute((downloadSnapshotFromSwiftCommand)cmd); + } else if (cmd instanceof DeleteSnapshotBackupCommand){ + return execute((DeleteSnapshotBackupCommand)cmd); } else if (cmd instanceof DeleteSnapshotsDirCommand){ return execute((DeleteSnapshotsDirCommand)cmd); } else if (cmd instanceof downloadTemplateFromSwiftToSecondaryStorageCommand) { @@ -391,6 +393,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S } } } + return new Answer(cmd, true, "success"); } catch (Exception e) { String msg = cmd + " Command failed due to " + e.toString(); diff --git a/core/src/com/cloud/vm/UserVmVO.java b/core/src/com/cloud/vm/UserVmVO.java index 8bb2c1fd4fd..3cd1bbf4cae 100755 --- a/core/src/com/cloud/vm/UserVmVO.java +++ b/core/src/com/cloud/vm/UserVmVO.java @@ -126,4 +126,8 @@ public class UserVmVO extends VMInstanceVO implements UserVm { public void setAccountId(long accountId){ this.accountId = accountId; } + + public void setDomainId(long domainId){ + this.domainId = domainId; + } } diff --git a/scripts/vm/hypervisor/xenserver/vmops b/scripts/vm/hypervisor/xenserver/vmops index 24610ea17d2..54fbb64ed56 100755 --- a/scripts/vm/hypervisor/xenserver/vmops +++ b/scripts/vm/hypervisor/xenserver/vmops @@ -385,6 +385,7 @@ def can_bridge_firewall(session, args): util.pread2(['iptables', '-D', 'FORWARD', '-j', 'RH-Firewall-1-INPUT']) except: util.SMlog('Chain BRIDGE-FIREWALL already exists') + default_ebtables_rules() privnic = get_private_nic(session, args) result = 'true' try: @@ -405,6 +406,30 @@ def can_bridge_firewall(session, args): return result +@echo +def default_ebtables_rules(): + try: + util.pread2(['ebtables', '-N', 'DEFAULT_EBTABLES']) + util.pread2(['ebtables', '-A', 'FORWARD', '-j' 'DEFAULT_EBTABLES']) + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'IPv4', '--ip-dst', '255.255.255.255', '--ip-proto', 'udp', '--ip-dport', '67', '-j', 'ACCEPT']) + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'ARP', '--arp-op', 'Request', '-j', 'ACCEPT']) + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'ARP', '--arp-op', 'Reply', '-j', 'ACCEPT']) + # deny mac broadcast and multicast + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'IPv4', '-d', 'Broadcast', '-j', 'DROP']) + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'IPv4', '-d', 'Multicast', '-j', 'DROP']) + # deny ip broadcast and multicast + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'IPv4', '--ip-dst', '255.255.255.255', '-j', 'DROP']) + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'IPv4', '--ip-dst', '224.0.0.0/4', '-j', 'DROP']) + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'IPv4', '-j', 'RETURN']) + # deny ipv6 + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'IPv6', '-j', 'DROP']) + # deny vlan + util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', '802_1Q', '-j', 'DROP']) + # deny all other 802. frames + util.pread2(['ebtables', '-A', 'FORWARD', '-j', 'DROP']) + except: + util.SMlog('Chain DEFAULT_EBTABLES already exists') + @echo def allow_egress_traffic(session): devs = [] @@ -526,74 +551,119 @@ def destroy_network_rules_for_vm(session, args): @echo def destroy_ebtables_rules(vm_chain): - delcmd = "ebtables-save | grep ROUTING | grep " + vm_chain + " | sed 's/-A/-D/'" + delcmd = "ebtables-save | grep " + vm_chain + " | sed 's/-A/-D/'" delcmds = util.pread2(['/bin/bash', '-c', delcmd]).split('\n') delcmds.pop() for cmd in delcmds: try: dc = cmd.split(' ') dc.insert(0, 'ebtables') - dc.insert(1, '-t') - dc.insert(2, 'nat') util.pread2(dc) except: util.SMlog("Ignoring failure to delete ebtables rules for vm " + vm_chain) - chains = [vm_chain+"-in", vm_chain+"-out"] - for chain in chains: - try: - util.pread2(['ebtables', '-t', 'nat', '-F', chain]) - util.pread2(['ebtables', '-t', 'nat', '-X', chain]) - except: + try: + util.pread2(['ebtables', '-F', vm_chain]) + util.pread2(['ebtables', '-X', vm_chain]) + except: util.SMlog("Ignoring failure to delete ebtables chain for vm " + vm_chain) - +@echo +def destroy_arptables_rules(vm_chain): + delcmd = "arptables -vL FORWARD | grep " + vm_chain + " | sed 's/-i any//' | sed 's/-o any//' | awk '{print $1,$2,$3,$4}' " + delcmds = util.pread2(['/bin/bash', '-c', delcmd]).split('\n') + delcmds.pop() + for cmd in delcmds: + try: + dc = cmd.split(' ') + dc.insert(0, 'arptables') + dc.insert(1, '-D') + dc.insert(2, 'FORWARD') + util.pread2(dc) + except: + util.SMlog("Ignoring failure to delete arptables rules for vm " + vm_chain) + + try: + util.pread2(['arptables', '-F', vm_chain]) + util.pread2(['arptables', '-X', vm_chain]) + except: + util.SMlog("Ignoring failure to delete arptables chain for vm " + vm_chain) @echo -def default_ebtables_rules(vm_chain, vif, vm_ip, vm_mac): +def default_ebtables_antispoof_rules(vm_chain, vifs, vm_ip, vm_mac): + if vm_mac == 'ff:ff:ff:ff:ff:ff': + util.SMlog("Ignoring since mac address is not valid") + return 'true' - vmchain_in = vm_chain + "-in" - vmchain_out = vm_chain + "-out" - - for chain in [vmchain_in, vmchain_out]: + try: + util.pread2(['ebtables', '-N', vm_chain]) + except: try: - util.pread2(['ebtables', '-t', 'nat', '-N', chain]) + util.pread2(['ebtables', '-F', vm_chain]) except: - try: - util.pread2(['ebtables', '-t', 'nat', '-F', chain]) - except: - util.SMlog("Failed to create ebtables nat rule, skipping") - return 'true' + util.SMlog("Failed to create ebtables antispoof chain, skipping") + return 'true' try: - # -s ! 52:54:0:56:44:32 -j DROP - util.pread2(['ebtables', '-t', 'nat', '-A', 'PREROUTING', '-i', vif, '-j', vmchain_in]) - util.pread2(['ebtables', '-t', 'nat', '-A', 'POSTROUTING', '-o', vif, '-j', vmchain_out]) + for vif in vifs: + util.pread2(['ebtables', '-I', 'FORWARD', '2', '-i', vif, '-j', vm_chain]) + util.pread2(['ebtables', '-I', 'FORWARD', '2', '-o', vif, '-j', vm_chain]) except: - util.SMlog("Failed to program default rules") + util.SMlog("Failed to program default ebtables FORWARD rules for %s" % vm_chain) + return 'false' + + try: + for vif in vifs: + # only allow source mac that belongs to the vm + util.pread2(['ebtables', '-A', vm_chain, '-i', vif, '-s', '!', vm_mac, '-j', 'DROP']) + # do not allow fake dhcp responses + util.pread2(['ebtables', '-A', vm_chain, '-i', vif, '-p', 'IPv4', '--ip-proto', 'udp', '--ip-dport', '68', '-j', 'DROP']) + # do not allow snooping of dhcp requests + util.pread2(['ebtables', '-A', vm_chain, '-o', vif, '-p', 'IPv4', '--ip-proto', 'udp', '--ip-dport', '67', '-j', 'DROP']) + except: + util.SMlog("Failed to program default ebtables antispoof rules for %s" % vm_chain) + return 'false' + + return 'true' + +@echo +def default_arp_antispoof(vm_chain, vifs, vm_ip, vm_mac): + if vm_mac == 'ff:ff:ff:ff:ff:ff': + util.SMlog("Ignoring since mac address is not valid") + return 'true' + + try: + util.pread2(['arptables', '-N', vm_chain]) + except: + try: + util.pread2(['arptables', '-F', vm_chain]) + except: + util.SMlog("Failed to create arptables rule, skipping") + return 'true' + + try: + for vif in vifs: + util.pread2(['arptables', '-A', 'FORWARD', '-i', vif, '-j', vm_chain]) + util.pread2(['arptables', '-A', 'FORWARD', '-o', vif, '-j', vm_chain]) + except: + util.SMlog("Failed to program default arptables rules in FORWARD chain vm=" + vm_chain) return 'false' try: - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-i', vif, '-s', '!', vm_mac, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '-s', '!', vm_mac, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-mac-src', '!', vm_mac, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-ip-src', '!', vm_ip, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-op', 'Request', '-j', 'ACCEPT']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-op', 'Reply', '-j', 'ACCEPT']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '-j', 'DROP']) + for vif in vifs: + #accept arp replies into the bridge as long as the source mac and ips match the vm + util.pread2(['arptables', '-A', vm_chain, '-i', vif, '--opcode', 'Reply', '--source-mac', vm_mac, '--source-ip', vm_ip, '-j', 'ACCEPT']) + #accept any arp requests from this vm. In the future this can be restricted to deny attacks on hosts + util.pread2(['arptables', '-A', vm_chain, '-i', vif, '--opcode', 'Request', '-j', 'ACCEPT']) + #accept any arp requests to this vm as long as the request is for this vm's ip + util.pread2(['arptables', '-A', vm_chain, '-o', vif, '--opcode', 'Request', '--destination-ip', vm_ip, '-j', 'ACCEPT']) + #accept any arp replies to this vm as long as the mac and ip matches + util.pread2(['arptables', '-A', vm_chain, '-o', vif, '--opcode', 'Reply', '--destination-mac', vm_mac, '--destination-ip', vm_ip, '-j', 'ACCEPT']) + util.pread2(['arptables', '-A', vm_chain, '-j', 'DROP']) + except: - util.SMlog("Failed to program default ebtables IN rules") + util.SMlog("Failed to program default arptables rules") return 'false' - - try: - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-op', 'Reply', '--arp-mac-dst', '!', vm_mac, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-ip-dst', '!', vm_ip, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-op', 'Request', '-j', 'ACCEPT']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-op', 'Reply', '-j', 'ACCEPT']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '-j', 'DROP']) - except: - util.SMlog("Failed to program default ebtables OUT rules") - return 'false' - + return 'true' @echo @@ -722,15 +792,16 @@ def default_network_rules(session, args): util.SMlog("Failed to program default rules for vm " + vm_name) return 'false' - for v in vifs: - default_ebtables_rules(vmchain, v, vm_ip, vm_mac) + default_arp_antispoof(vmchain, vifs, vm_ip, vm_mac) + default_ebtables_antispoof_rules(vmchain, vifs, vm_ip, vm_mac) - if write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, '_initial_', '-1') == False: + if write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, '_initial_', '-1', vm_mac) == False: util.SMlog("Failed to log default network rules, ignoring") util.SMlog("Programmed default rules for vm " + vm_name) return 'true' +@echo def check_domid_changed(session, vmName): curr_domid = '-1' try: @@ -750,18 +821,22 @@ def check_domid_changed(session, vmName): lines = (line.rstrip() for line in open(logfilename)) - [_vmName,_vmID,_vmIP,old_domid,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1'] + [_vmName,_vmID,_vmIP,old_domid,_signature,_seqno, _vmMac] = ['_', '-1', '_', '-1', '_', '-1', 'ff:ff:ff:ff:ff:ff'] for line in lines: - [_vmName,_vmID,_vmIP,old_domid,_signature,_seqno] = line.split(',') + try: + [_vmName,_vmID,_vmIP,old_domid,_signature,_seqno,_vmMac] = line.split(',') + except ValueError,v: + [_vmName,_vmID,_vmIP,old_domid,_signature,_seqno] = line.split(',') break return [curr_domid, old_domid] +@echo def delete_rules_for_vm_in_bridge_firewall_chain(vmName): vm_name = vmName vmchain = chain_name_def(vm_name) - delcmd = "iptables -S BRIDGE-FIREWALL | grep " + vmchain + " | sed 's/-A/-D/'" + delcmd = "iptables-save | grep '\-A BRIDGE-FIREWALL' | grep " + vmchain + " | sed 's/-A/-D/'" delcmds = util.pread2(['/bin/bash', '-c', delcmd]).split('\n') delcmds.pop() for cmd in delcmds: @@ -769,11 +844,12 @@ def delete_rules_for_vm_in_bridge_firewall_chain(vmName): dc = cmd.split(' ') dc.insert(0, 'iptables') dc.pop() - util.pread2(dc) + util.pread2(filter(None, dc)) except: util.SMlog("Ignoring failure to delete rules for vm " + vmName) +@echo def network_rules_for_rebooted_vm(session, vmName): vm_name = vmName [curr_domid, old_domid] = check_domid_changed(session, vm_name) @@ -811,12 +887,15 @@ def network_rules_for_rebooted_vm(session, vmName): #change antispoof rule in vmchain try: - delcmd = "iptables -S " + vmchain_default + " | grep physdev-in | sed 's/-A/-D/'" - inscmd = "iptables -S " + vmchain_default + " | grep physdev-in | grep vif | sed -r 's/vif[0-9]+.0/" + vif + "/' | sed 's/-A/-I/'" - inscmd2 = "iptables -S " + vmchain_default + " | grep physdev-in | grep tap | sed -r 's/tap[0-9]+.0/" + tap + "/' | sed 's/-A/-I/'" + delcmd = "iptables-save | grep '\-A " + vmchain_default + "' | grep physdev-in | sed 's/-A/-D/'" + delcmd2 = "iptables-save | grep '\-A " + vmchain_default + "' | grep physdev-out | sed 's/-A/-D/'" + inscmd = "iptables-save | grep '\-A " + vmchain_default + "' | grep physdev-in | grep vif | sed -r 's/vif[0-9]+.0/" + vif + "/' | sed 's/-A/-I/'" + inscmd2 = "iptables-save| grep '\-A " + vmchain_default + "' | grep physdev-in | grep tap | sed -r 's/tap[0-9]+.0/" + tap + "/' | sed 's/-A/-I/'" + inscmd3 = "iptables-save | grep '\-A " + vmchain_default + "' | grep physdev-out | grep vif | sed -r 's/vif[0-9]+.0/" + vif + "/' | sed 's/-A/-I/'" + inscmd4 = "iptables-save| grep '\-A " + vmchain_default + "' | grep physdev-out | grep tap | sed -r 's/tap[0-9]+.0/" + tap + "/' | sed 's/-A/-I/'" ipts = [] - for cmd in [delcmd, inscmd, inscmd2]: + for cmd in [delcmd, delcmd2, inscmd, inscmd2, inscmd3, inscmd4]: cmds = util.pread2(['/bin/bash', '-c', cmd]).split('\n') cmds.pop() for c in cmds: @@ -827,12 +906,17 @@ def network_rules_for_rebooted_vm(session, vmName): for ipt in ipts: try: - util.pread2(ipt) + util.pread2(filter(None,ipt)) except: util.SMlog("Failed to rewrite antispoofing rules for vm " + vm_name) except: util.SMlog("No rules found for vm " + vm_name) + destroy_ebtables_rules(vmchain) + destroy_arptables_rules(vmchain) + [vm_ip, vm_mac] = get_vm_mac_ip_from_log(vmchain) + default_arp_antispoof(vmchain, vifs, vm_ip, vm_mac) + default_ebtables_antispoof_rules(vmchain, vifs, vm_ip, vm_mac) rewrite_rule_log_for_vm(vm_name, curr_domid) return True @@ -842,12 +926,15 @@ def rewrite_rule_log_for_vm(vm_name, new_domid): return lines = (line.rstrip() for line in open(logfilename)) - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1'] + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno,_vmMac] = ['_', '-1', '_', '-1', '_', '-1','ff:ff:ff:ff:ff:ff'] for line in lines: - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') - break + try: + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno,_vmMac] = line.split(',') + break + except ValueError,v: + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') - write_rule_log_for_vm(_vmName, _vmID, '0.0.0.0', new_domid, _signature, '-1') + write_rule_log_for_vm(_vmName, _vmID, _vmIP, new_domid, _signature, '-1', _vmMac) def get_rule_log_for_vm(session, vmName): vm_name = vmName; @@ -857,13 +944,33 @@ def get_rule_log_for_vm(session, vmName): lines = (line.rstrip() for line in open(logfilename)) - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1'] + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno,_vmMac] = ['_', '-1', '_', '-1', '_', '-1', 'ff:ff:ff:ff:ff:ff'] for line in lines: - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') - break + try: + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno,_vmMac] = line.split(',') + break + except ValueError,v: + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') return ','.join([_vmName, _vmID, _vmIP, _domID, _signature, _seqno]) +@echo +def get_vm_mac_ip_from_log(vm_name): + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno,_vmMac] = ['_', '-1', '0.0.0.0', '-1', '_', '-1','ff:ff:ff:ff:ff:ff'] + logfilename = "/var/run/cloud/" + vm_name +".log" + if not os.path.exists(logfilename): + return ['_', '_'] + + lines = (line.rstrip() for line in open(logfilename)) + for line in lines: + try: + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno,_vmMac] = line.split(',') + break + except ValueError,v: + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') + + return [ _vmIP, _vmMac] + @echo def get_rule_logs_for_vms(session, args): host_uuid = args.pop('host_uuid') @@ -956,10 +1063,13 @@ def check_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno): lines = (line.rstrip() for line in open(logfilename)) - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1'] + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno,_vmMac] = ['_', '-1', '_', '-1', '_', '-1', 'ff:ff:ff:ff:ff:ff'] try: for line in lines: - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') + try: + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno, _vmMac] = line.split(',') + except ValueError,v: + [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') break except: util.SMlog("Failed to parse log file for vm " + vmName) @@ -1002,12 +1112,12 @@ def check_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno): @echo -def write_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno): +def write_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno, vmMac='ff:ff:ff:ff:ff:ff'): vm_name = vmName logfilename = "/var/run/cloud/" + vm_name +".log" util.SMlog("Writing log to " + logfilename) logf = open(logfilename, 'w') - output = ','.join([vmName, vmID, vmIP, domID, signature, seqno]) + output = ','.join([vmName, vmID, vmIP, domID, signature, seqno, vmMac]) result = True try: logf.write(output) @@ -1044,6 +1154,7 @@ def network_rules(session, args): vm_name = args.get('vmName') vm_ip = args.get('vmIP') vm_id = args.get('vmID') + vm_mac = args.get('vmMAC') signature = args.pop('signature') seqno = args.pop('seqno') deflated = 'false' @@ -1083,7 +1194,7 @@ def network_rules(session, args): reason = 'seqno_same_sig_same' if rewriteLog: reason = 'seqno_increased_sig_same' - write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, signature, seqno) + write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, signature, seqno, vm_mac) util.SMlog("Programming network rules for vm %s seqno=%s signature=%s guestIp=%s,"\ " do nothing, reason=%s" % (vm_name, seqno, signature, vm_ip, reason)) return 'true' @@ -1181,7 +1292,7 @@ def network_rules(session, args): util.pread2(['iptables', '-A', vmchain, '-j', 'DROP']) - if write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, signature, seqno) == False: + if write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, signature, seqno, vm_mac) == False: return 'false' return 'true' @@ -1246,4 +1357,3 @@ if __name__ == "__main__": "setLinkLocalIP":setLinkLocalIP, "lt2p_vpn":lt2p_vpn, "cleanup_rules":cleanup_rules, "checkRouter":checkRouter, "bumpUpPriority":bumpUpPriority, "getDomRVersion":getDomRVersion }) - diff --git a/scripts/vm/hypervisor/xenserver/vmops.orig b/scripts/vm/hypervisor/xenserver/vmops.orig deleted file mode 100755 index f35de53389d..00000000000 --- a/scripts/vm/hypervisor/xenserver/vmops.orig +++ /dev/null @@ -1,1208 +0,0 @@ -#!/usr/bin/python -# Version 2.2.8.2011-08-18T08:15:52Z -# -# A plugin for executing script needed by vmops cloud - -import os, sys, time -import XenAPIPlugin -sys.path.extend(["/opt/xensource/sm/", "/usr/local/sbin/", "/sbin/"]) -import base64 -import hostvmstats -import socket -import stat -import tempfile -import util -<<<<<<< HEAD -import subprocess -======= -import zlib ->>>>>>> acfbe18... bug 11336: compression to allow number of cidrs to scale beyond 8k -from util import CommandException - -def echo(fn): - def wrapped(*v, **k): - name = fn.__name__ - util.SMlog("#### VMOPS enter %s ####" % name ) - res = fn(*v, **k) - util.SMlog("#### VMOPS exit %s ####" % name ) - return res - return wrapped - -@echo -def gethostvmstats(session, args): - collect_host_stats = args['collectHostStats'] - consolidation_function = args['consolidationFunction'] - interval = args['interval'] - start_time = args['startTime'] - result = hostvmstats.get_stats(session, collect_host_stats, consolidation_function, interval, start_time) - return result - -@echo -def setup_iscsi(session, args): - uuid=args['uuid'] - try: - cmd = ["bash", "/opt/xensource/bin/setup_iscsi.sh", uuid] - txt = util.pread2(cmd) - except: - txt = '' - return txt - -@echo -def getvncport(session, args): - domid = args['domID'] - hvm = args['hvm'] - if hvm == 'true': - path1 = "/local/domain/" + domid + "/qemu-pid" - path2 = "/local/domain/" + domid + "/console/vnc-port" - else: - path1 = "/local/domain/" + domid + "/serial/0/vncterm-pid" - path2 = "/local/domain/" + domid + "/serial/0/vnc-port" - try: - cmd = ["xenstore-read", path1] - pid = util.pread2(cmd) - pid = pid.strip() - cmd = ["ps", pid] - util.pread2(cmd) - cmd = ["xenstore-read", path2] - vncport = util.pread2(cmd) - vncport = vncport.strip() - return vncport - except: - return '' - -@echo -def getgateway(session, args): - mgmt_ip = args['mgmtIP'] - try: - cmd = ["bash", "/opt/xensource/bin/network_info.sh", "-g", mgmt_ip] - txt = util.pread2(cmd) - except: - txt = '' - - return txt - -@echo -def preparemigration(session, args): - uuid = args['uuid'] - try: - cmd = ["/opt/xensource/bin/make_migratable.sh", uuid] - util.pread2(cmd) - txt = 'success' - except: - util.SMlog("Catch prepare migration exception" ) - txt = '' - - return txt - -@echo -def setIptables(session, args): - try: - cmd = ["/bin/bash", "/opt/xensource/bin/setupxenserver.sh"] - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog(" setIptables execution failed " ) - txt = '' - - return txt - -@echo -def pingdomr(session, args): - host = args['host'] - port = args['port'] - socket.setdefaulttimeout(3) - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.connect((host,int(port))) - txt = 'success' - except: - txt = '' - - s.close() - - return txt - -@echo -def pingxenserver(session, args): - txt = 'success' - return txt - -@echo -def ipassoc(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/ipassoc.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog(" ip associate failed " ) - txt = '' - - return txt - -@echo -def vm_data(session, args): - router_ip = args.pop('routerIP') - vm_ip = args.pop('vmIP') - - util.SMlog(" adding vmdata for VM with IP: " + vm_ip + " to router with IP: " + router_ip) - - for pair in args: - pairList = pair.split(',') - vmDataFolder = pairList[0] - vmDataFile = pairList[1] - vmDataValue = args[pair] - cmd = ["/bin/bash", "/opt/xensource/bin/vm_data.sh", "-r", router_ip, "-v", vm_ip, "-F", vmDataFolder, "-f", vmDataFile] - - fd = None - tmp_path = None - - try: - fd,tmp_path = tempfile.mkstemp() - tmpfile = open(tmp_path, 'w') - - if vmDataFolder == "userdata" and vmDataValue != "none": - vmDataValue = base64.urlsafe_b64decode(vmDataValue) - - if vmDataValue != "none": - tmpfile.write(vmDataValue) - - tmpfile.close() - cmd.append("-d") - cmd.append(tmp_path) - except: - util.SMlog(" vmdata failed to write tempfile " ) - os.close(fd) - os.remove(tmp_path) - return '' - - try: - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog(" vmdata failed with folder: " + vmDataFolder + " and file: " + vmDataFile) - txt = '' - - if (fd != None): - os.close(fd) - os.remove(tmp_path) - - return txt - -def pingtest(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/pingtest.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog(" pingtest failed " ) - txt = '' - - return txt - -@echo -def savePassword(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/save_password_to_domr.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog(" save password to domr failed " ) - txt = '' - - return txt - -@echo -def saveDhcpEntry(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/dhcp_entry.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog(" save dhcp entry failed " ) - txt = '' - - return txt - -@echo -def lt2p_vpn(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/l2tp_vpn.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog("l2tp vpn failed " ) - txt = '' - - return txt - -@echo -def setLinkLocalIP(session, args): - brName = args['brName'] - try: - cmd = ["ip", "route", "del", "169.254.0.0/16"] - txt = util.pread2(cmd) - except: - txt = '' - try: - cmd = ["ifconfig", brName, "169.254.0.1", "netmask", "255.255.0.0"] - txt = util.pread2(cmd) - except: - txt = '' - try: - cmd = ["ip", "route", "add", "169.254.0.0/16", "dev", brName, "src", "169.254.0.1"] - txt = util.pread2(cmd) - except: - txt = '' - txt = 'success' - return txt - -@echo -def setFirewallRule(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/call_firewall.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog(" set firewall rule failed " ) - txt = '' - - return txt - -@echo -def setLoadBalancerRule(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/call_loadbalancer.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog(" set loadbalancer rule failed " ) - txt = '' - - return txt - -@echo -def createFile(session, args): - file_path = args['filepath'] - file_contents = args['filecontents'] - - try: - f = open(file_path, "w") - f.write(file_contents) - f.close() - txt = 'success' - except: - util.SMlog(" failed to create HA proxy cfg file ") - txt = '' - - return txt - -@echo -def deleteFile(session, args): - file_path = args["filepath"] - - try: - if os.path.isfile(file_path): - os.remove(file_path) - txt = 'success' - except: - util.SMlog(" failed to remove HA proxy cfg file ") - txt = '' - - return txt - - -@echo -def networkUsage(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/networkUsage.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - except: - util.SMlog(" network usage error " ) - txt = '' - - return txt - -def get_private_nic(session, args): - vms = session.xenapi.VM.get_all() - host_uuid = args.get('host_uuid') - host = session.xenapi.host.get_by_uuid(host_uuid) - piflist = session.xenapi.host.get_PIFs(host) - mgmtnic = 'eth0' - for pif in piflist: - pifrec = session.xenapi.PIF.get_record(pif) - network = pifrec.get('network') - nwrec = session.xenapi.network.get_record(network) - if nwrec.get('name_label') == 'cloud-guest': - return pifrec.get('device') - if pifrec.get('management'): - mgmtnic = pifrec.get('device') - - return mgmtnic - -def chain_name(vm_name): - if vm_name.startswith('i-') or vm_name.startswith('r-'): - if vm_name.endswith('untagged'): - return '-'.join(vm_name.split('-')[:-1]) - return vm_name - -def chain_name_def(vm_name): - if vm_name.startswith('i-'): - if vm_name.endswith('untagged'): - return '-'.join(vm_name.split('-')[:-2]) + "-def" - return '-'.join(vm_name.split('-')[:-1]) + "-def" - return vm_name - -@echo -def can_bridge_firewall(session, args): - host_uuid = args.get('host_uuid') - try: - util.pread2(['iptables', '-N', 'BRIDGE-FIREWALL']) - util.pread2(['iptables', '-I', 'BRIDGE-FIREWALL', '-m', 'state', '--state', 'RELATED,ESTABLISHED', '-j', 'ACCEPT']) - util.pread2(['iptables', '-D', 'FORWARD', '-j', 'RH-Firewall-1-INPUT']) - except: - util.SMlog('Chain BRIDGE-FIREWALL already exists') - privnic = get_private_nic(session, args) - result = 'true' - try: - util.pread2(['/bin/bash', '-c', 'iptables -n -L FORWARD | grep BRIDGE-FIREWALL']) - except: - try: - util.pread2(['iptables', '-I', 'FORWARD', '-m', 'physdev', '--physdev-is-bridged', '-j', 'BRIDGE-FIREWALL']) - util.pread2(['iptables', '-A', 'FORWARD', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', privnic, '-j', 'ACCEPT']) - util.pread2(['iptables', '-A', 'FORWARD', '-j', 'DROP']) - except: - result = 'false' - allow_egress_traffic(session) - if not os.path.exists('/var/run/cloud'): - os.makedirs('/var/run/cloud') - - cleanup_rules_for_dead_vms(session) - cleanup_rules(session, args) - - return result - -@echo -def allow_egress_traffic(session): - devs = [] - for pif in session.xenapi.PIF.get_all(): - pif_rec = session.xenapi.PIF.get_record(pif) - vlan = pif_rec.get('VLAN') - dev = pif_rec.get('device') - if vlan == '-1': - devs.append(dev) - else: - devs.append(dev + "." + vlan) - for d in devs: - try: - util.pread2(['/bin/bash', '-c', "iptables -n -L FORWARD | grep '%s '" % d]) - except: - try: - util.pread2(['iptables', '-I', 'FORWARD', '2', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', d, '-j', 'ACCEPT']) - except: - util.SMlog("Failed to add FORWARD rule through to %s" % d) - return 'false' - return 'true' - - -def ipset(ipsetname, proto, start, end, ips): - try: - util.pread2(['ipset', '-N', ipsetname, 'iptreemap']) - except: - util.SMlog("ipset chain already exists" + ipsetname) - - result = True - ipsettmp = ''.join(''.join(ipsetname.split('-')).split('_')) + str(int(time.time()) % 1000) - - try: - util.pread2(['ipset', '-N', ipsettmp, 'iptreemap']) - except: - util.SMlog("Failed to create temp ipset, reusing old name= " + ipsettmp) - try: - util.pread2(['ipset', '-F', ipsettmp]) - except: - util.SMlog("Failed to clear old temp ipset name=" + ipsettmp) - return False - - try: - for ip in ips: - try: - util.pread2(['ipset', '-A', ipsettmp, ip]) - except CommandException, cex: - if cex.reason.rfind('already in set') == -1: - raise - except: - util.SMlog("Failed to program ipset " + ipsetname) - util.pread2(['ipset', '-F', ipsettmp]) - util.pread2(['ipset', '-X', ipsettmp]) - return False - - try: - util.pread2(['ipset', '-W', ipsettmp, ipsetname]) - except: - util.SMlog("Failed to swap ipset " + ipsetname) - result = False - - try: - util.pread2(['ipset', '-F', ipsettmp]) - util.pread2(['ipset', '-X', ipsettmp]) - except: - # if the temporary name clashes next time we'll just reuse it - util.SMlog("Failed to delete temp ipset " + ipsettmp) - - return result - -@echo -def destroy_network_rules_for_vm(session, args): - vm_name = args.pop('vmName') - vmchain = chain_name(vm_name) - vmchain_default = chain_name_def(vm_name) - - delete_rules_for_vm_in_bridge_firewall_chain(vm_name) - if vm_name.startswith('i-') or vm_name.startswith('r-') or vm_name.startswith('l-'): - try: - util.pread2(['iptables', '-F', vmchain_default]) - util.pread2(['iptables', '-X', vmchain_default]) - except: - util.SMlog("Ignoring failure to delete chain " + vmchain_default) - - destroy_ebtables_rules(vmchain) - - try: - util.pread2(['iptables', '-F', vmchain]) - util.pread2(['iptables', '-X', vmchain]) - except: - util.SMlog("Ignoring failure to delete chain " + vmchain) - - - - remove_rule_log_for_vm(vm_name) - - if 1 in [ vm_name.startswith(c) for c in ['r-', 's-', 'v-', 'l-'] ]: - return 'true' - - try: - setscmd = "ipset --save | grep " + vmchain + " | grep '^-N' | awk '{print $2}'" - setsforvm = util.pread2(['/bin/bash', '-c', setscmd]).split('\n') - for set in setsforvm: - if set != '': - util.pread2(['ipset', '-F', set]) - util.pread2(['ipset', '-X', set]) - except: - util.SMlog("Failed to destroy ipsets for %" % vm_name) - - - return 'true' - -@echo -def destroy_ebtables_rules(vm_chain): - - delcmd = "ebtables-save | grep ROUTING | grep " + vm_chain + " | sed 's/-A/-D/'" - delcmds = util.pread2(['/bin/bash', '-c', delcmd]).split('\n') - delcmds.pop() - for cmd in delcmds: - try: - dc = cmd.split(' ') - dc.insert(0, 'ebtables') - dc.insert(1, '-t') - dc.insert(2, 'nat') - util.pread2(dc) - except: - util.SMlog("Ignoring failure to delete ebtables rules for vm " + vm_chain) - chains = [vm_chain+"-in", vm_chain+"-out"] - for chain in chains: - try: - util.pread2(['ebtables', '-t', 'nat', '-F', chain]) - util.pread2(['ebtables', '-t', 'nat', '-X', chain]) - except: - util.SMlog("Ignoring failure to delete ebtables chain for vm " + vm_chain) - - - -@echo -def default_ebtables_rules(vm_chain, vif, vm_ip, vm_mac): - - vmchain_in = vm_chain + "-in" - vmchain_out = vm_chain + "-out" - - for chain in [vmchain_in, vmchain_out]: - try: - util.pread2(['ebtables', '-t', 'nat', '-N', chain]) - except: - try: - util.pread2(['ebtables', '-t', 'nat', '-F', chain]) - except: - util.SMlog("Failed to create ebtables nat rule, skipping") - return 'true' - - try: - # -s ! 52:54:0:56:44:32 -j DROP - util.pread2(['ebtables', '-t', 'nat', '-A', 'PREROUTING', '-i', vif, '-j', vmchain_in]) - util.pread2(['ebtables', '-t', 'nat', '-A', 'POSTROUTING', '-o', vif, '-j', vmchain_out]) - except: - util.SMlog("Failed to program default rules") - return 'false' - - try: - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-i', vif, '-s', '!', vm_mac, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '-s', '!', vm_mac, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-mac-src', '!', vm_mac, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-ip-src', '!', vm_ip, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-op', 'Request', '-j', 'ACCEPT']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-op', 'Reply', '-j', 'ACCEPT']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '-j', 'DROP']) - except: - util.SMlog("Failed to program default ebtables IN rules") - return 'false' - - try: - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-op', 'Reply', '--arp-mac-dst', '!', vm_mac, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-ip-dst', '!', vm_ip, '-j', 'DROP']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-op', 'Request', '-j', 'ACCEPT']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-op', 'Reply', '-j', 'ACCEPT']) - util.pread2(['ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '-j', 'DROP']) - except: - util.SMlog("Failed to program default ebtables OUT rules") - return 'false' - - return 'true' - -@echo -def default_network_rules_systemvm(session, args): - vm_name = args.pop('vmName') - try: - vm = session.xenapi.VM.get_by_name_label(vm_name) - if len(vm) != 1: - return 'false' - vm_rec = session.xenapi.VM.get_record(vm[0]) - vm_vifs = vm_rec.get('VIFs') - vifnums = [session.xenapi.VIF.get_record(vif).get('device') for vif in vm_vifs] - domid = vm_rec.get('domid') - except: - util.SMlog("### Failed to get domid or vif list for vm ##" + vm_name) - return 'false' - - if domid == '-1': - util.SMlog("### Failed to get domid for vm (-1): " + vm_name) - return 'false' - - vifs = ["vif" + domid + "." + v for v in vifnums] - #vm_name = '-'.join(vm_name.split('-')[:-1]) - vmchain = chain_name(vm_name) - - - delete_rules_for_vm_in_bridge_firewall_chain(vm_name) - - try: - util.pread2(['iptables', '-N', vmchain]) - except: - util.pread2(['iptables', '-F', vmchain]) - - allow_egress_traffic(session) - - for vif in vifs: - try: - util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', vif, '-j', vmchain]) - util.pread2(['iptables', '-I', 'BRIDGE-FIREWALL', '2', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', vif, '-j', vmchain]) - util.pread2(['iptables', '-I', vmchain, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', vif, '-j', 'RETURN']) - except: - util.SMlog("Failed to program default rules") - return 'false' - - - util.pread2(['iptables', '-A', vmchain, '-j', 'ACCEPT']) - - if write_rule_log_for_vm(vm_name, '-1', '_ignore_', domid, '_initial_', '-1') == False: - util.SMlog("Failed to log default network rules for systemvm, ignoring") - return 'true' - - -@echo -def default_network_rules(session, args): - vm_name = args.pop('vmName') - vm_ip = args.pop('vmIP') - vm_id = args.pop('vmID') - vm_mac = args.pop('vmMAC') - - try: - vm = session.xenapi.VM.get_by_name_label(vm_name) - if len(vm) != 1: - util.SMlog("### Failed to get record for vm " + vm_name) - return 'false' - vm_rec = session.xenapi.VM.get_record(vm[0]) - domid = vm_rec.get('domid') - except: - util.SMlog("### Failed to get domid for vm " + vm_name) - return 'false' - if domid == '-1': - util.SMlog("### Failed to get domid for vm (-1): " + vm_name) - return 'false' - - vif = "vif" + domid + ".0" - tap = "tap" + domid + ".0" - vifs = [vif] - try: - util.pread2(['ifconfig', tap]) - vifs.append(tap) - except: - pass - - delete_rules_for_vm_in_bridge_firewall_chain(vm_name) - - - vmchain = chain_name(vm_name) - vmchain_default = chain_name_def(vm_name) - - destroy_ebtables_rules(vmchain) - - - try: - util.pread2(['iptables', '-N', vmchain]) - except: - util.pread2(['iptables', '-F', vmchain]) - - try: - util.pread2(['iptables', '-N', vmchain_default]) - except: - util.pread2(['iptables', '-F', vmchain_default]) - - try: - for v in vifs: - util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-j', vmchain_default]) - util.pread2(['iptables', '-I', 'BRIDGE-FIREWALL', '2', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-j', vmchain_default]) - util.pread2(['iptables', '-A', vmchain_default, '-m', 'state', '--state', 'RELATED,ESTABLISHED', '-j', 'ACCEPT']) - #allow dhcp - for v in vifs: - util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-p', 'udp', '--dport', '67', '--sport', '68', '-j', 'ACCEPT']) - util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-p', 'udp', '--dport', '68', '--sport', '67', '-j', 'ACCEPT']) - - #don't let vm spoof its ip address - for v in vifs: - util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '--source', vm_ip, '-j', 'RETURN']) - util.pread2(['iptables', '-A', vmchain_default, '-j', vmchain]) - except: - util.SMlog("Failed to program default rules for vm " + vm_name) - return 'false' - - for v in vifs: - default_ebtables_rules(vmchain, v, vm_ip, vm_mac) - - if write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, '_initial_', '-1') == False: - util.SMlog("Failed to log default network rules, ignoring") - - util.SMlog("Programmed default rules for vm " + vm_name) - return 'true' - -def check_domid_changed(session, vmName): - curr_domid = '-1' - try: - vm = session.xenapi.VM.get_by_name_label(vmName) - if len(vm) != 1: - util.SMlog("### Could not get record for vm ## " + vmName) - else: - vm_rec = session.xenapi.VM.get_record(vm[0]) - curr_domid = vm_rec.get('domid') - except: - util.SMlog("### Failed to get domid for vm ## " + vmName) - - - logfilename = "/var/run/cloud/" + vmName +".log" - if not os.path.exists(logfilename): - return ['-1', curr_domid] - - lines = (line.rstrip() for line in open(logfilename)) - - [_vmName,_vmID,_vmIP,old_domid,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1'] - for line in lines: - [_vmName,_vmID,_vmIP,old_domid,_signature,_seqno] = line.split(',') - break - - return [curr_domid, old_domid] - -def delete_rules_for_vm_in_bridge_firewall_chain(vmName): - vm_name = vmName - vmchain = chain_name_def(vm_name) - - delcmd = "iptables -S BRIDGE-FIREWALL | grep " + vmchain + " | sed 's/-A/-D/'" - delcmds = util.pread2(['/bin/bash', '-c', delcmd]).split('\n') - delcmds.pop() - for cmd in delcmds: - try: - dc = cmd.split(' ') - dc.insert(0, 'iptables') - dc.pop() - util.pread2(dc) - except: - util.SMlog("Ignoring failure to delete rules for vm " + vmName) - - -def network_rules_for_rebooted_vm(session, vmName): - vm_name = vmName - [curr_domid, old_domid] = check_domid_changed(session, vm_name) - - if curr_domid == old_domid: - return True - - if old_domid == '-1': - return True - - if curr_domid == '-1': - return True - - util.SMlog("Found a rebooted VM -- reprogramming rules for " + vm_name) - - delete_rules_for_vm_in_bridge_firewall_chain(vm_name) - if 1 in [ vm_name.startswith(c) for c in ['r-', 's-', 'v-', 'l-'] ]: - default_network_rules_systemvm(session, {"vmName":vm_name}) - return True - - vif = "vif" + curr_domid + ".0" - tap = "tap" + curr_domid + ".0" - vifs = [vif] - try: - util.pread2(['ifconfig', tap]) - vifs.append(tap) - except: - pass - vmchain = chain_name(vm_name) - vmchain_default = chain_name_def(vm_name) - - for v in vifs: - util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-j', vmchain_default]) - util.pread2(['iptables', '-I', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-j', vmchain_default]) - - #change antispoof rule in vmchain - try: - delcmd = "iptables -S " + vmchain_default + " | grep physdev-in | sed 's/-A/-D/'" - inscmd = "iptables -S " + vmchain_default + " | grep physdev-in | grep vif | sed -r 's/vif[0-9]+.0/" + vif + "/' | sed 's/-A/-I/'" - inscmd2 = "iptables -S " + vmchain_default + " | grep physdev-in | grep tap | sed -r 's/tap[0-9]+.0/" + tap + "/' | sed 's/-A/-I/'" - - ipts = [] - for cmd in [delcmd, inscmd, inscmd2]: - cmds = util.pread2(['/bin/bash', '-c', cmd]).split('\n') - cmds.pop() - for c in cmds: - ipt = c.split(' ') - ipt.insert(0, 'iptables') - ipt.pop() - ipts.append(ipt) - - for ipt in ipts: - try: - util.pread2(ipt) - except: - util.SMlog("Failed to rewrite antispoofing rules for vm " + vm_name) - except: - util.SMlog("No rules found for vm " + vm_name) - - rewrite_rule_log_for_vm(vm_name, curr_domid) - return True - -def rewrite_rule_log_for_vm(vm_name, new_domid): - logfilename = "/var/run/cloud/" + vm_name +".log" - if not os.path.exists(logfilename): - return - lines = (line.rstrip() for line in open(logfilename)) - - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1'] - for line in lines: - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') - break - - write_rule_log_for_vm(_vmName, _vmID, '0.0.0.0', new_domid, _signature, '-1') - -def get_rule_log_for_vm(session, vmName): - vm_name = vmName; - logfilename = "/var/run/cloud/" + vm_name +".log" - if not os.path.exists(logfilename): - return '' - - lines = (line.rstrip() for line in open(logfilename)) - - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1'] - for line in lines: - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') - break - - return ','.join([_vmName, _vmID, _vmIP, _domID, _signature, _seqno]) - -@echo -def get_rule_logs_for_vms(session, args): - host_uuid = args.pop('host_uuid') - try: - thishost = session.xenapi.host.get_by_uuid(host_uuid) - hostrec = session.xenapi.host.get_record(thishost) - vms = hostrec.get('resident_VMs') - except: - util.SMlog("Failed to get host from uuid " + host_uuid) - return ' ' - - result = [] - try: - for name in [session.xenapi.VM.get_name_label(x) for x in vms]: - if 1 not in [ name.startswith(c) for c in ['r-', 's-', 'v-', 'i-', 'l-'] ]: - continue - network_rules_for_rebooted_vm(session, name) - if name.startswith('i-'): - log = get_rule_log_for_vm(session, name) - result.append(log) - except: - util.SMlog("Failed to get rule logs, better luck next time!") - - return ";".join(result) - -@echo -def cleanup_rules_for_dead_vms(session): - try: - vms = session.xenapi.VM.get_all() - cleaned = 0 - for vm_name in [session.xenapi.VM.get_name_label(x) for x in vms]: - if 1 in [ vm_name.startswith(c) for c in ['r-', 'i-', 's-', 'v-', 'l-'] ]: - vm = session.xenapi.VM.get_by_name_label(vm_name) - if len(vm) != 1: - continue - vm_rec = session.xenapi.VM.get_record(vm[0]) - state = vm_rec.get('power_state') - if state != 'Running' and state != 'Paused': - util.SMlog("vm " + vm_name + " is not running, cleaning up") - destroy_network_rules_for_vm(session, {'vmName':vm_name}) - cleaned = cleaned+1 - - util.SMlog("Cleaned up rules for " + str(cleaned) + " vms") - except: - util.SMlog("Failed to cleanup rules for dead vms!") - - -@echo -def cleanup_rules(session, args): - instance = args.get('instance') - if not instance: - instance = 'VM' - - try: - chainscmd = "iptables-save | grep '^:' | awk '{print $1}' | cut -d':' -f2 | sed 's/-def/-%s/'|sort|uniq" % instance - chains = util.pread2(['/bin/bash', '-c', chainscmd]).split('\n') - cleaned = 0 - cleanup = [] - for chain in chains: - if 1 in [ chain.startswith(c) for c in ['r-', 'i-', 's-', 'v-', 'l-'] ]: - vm = session.xenapi.VM.get_by_name_label(chain) - if len(vm) != 1: - vm = session.xenapi.VM.get_by_name_label(chain + "-untagged") - if len(vm) != 1: - util.SMlog("chain " + chain + " does not correspond to a vm, cleaning up") - cleanup.append(chain) - continue - vm_rec = session.xenapi.VM.get_record(vm[0]) - state = vm_rec.get('power_state') - if state != 'Running' and state != 'Paused': - util.SMlog("vm " + vm_name + " is not running, cleaning up") - cleanup.append(vm_name) - - for vm_name in cleanup: - destroy_network_rules_for_vm(session, {'vmName':vm_name}) - - util.SMlog("Cleaned up rules for " + str(len(cleanup)) + " chains") - return str(len(cleanup)) - except: - util.SMlog("Failed to cleanup rules !") - return '-1'; - -@echo -def check_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno): - vm_name = vmName; - logfilename = "/var/run/cloud/" + vm_name +".log" - if not os.path.exists(logfilename): - util.SMlog("Failed to find logfile %s" %logfilename) - return [True, True, True] - - lines = (line.rstrip() for line in open(logfilename)) - - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1'] - try: - for line in lines: - [_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',') - break - except: - util.SMlog("Failed to parse log file for vm " + vmName) - remove_rule_log_for_vm(vmName) - return [True, True, True] - - reprogramDefault = False - if (domID != _domID) or (vmID != _vmID) or (vmIP != _vmIP): - util.SMlog("Change in default info set of vm %s" % vmName) - return [True, True, True] - else: - util.SMlog("No change in default info set of vm %s" % vmName) - - reprogramChain = False - rewriteLog = True - if (int(seqno) > int(_seqno)): - if (_signature != signature): - reprogramChain = True - util.SMlog("Seqno increased from %s to %s: reprogamming "\ - "ingress rules for vm %s" % (_seqno, seqno, vmName)) - else: - util.SMlog("Seqno increased from %s to %s: but no change "\ - "in signature for vm: skip programming ingress "\ - "rules %s" % (_seqno, seqno, vmName)) - elif (int(seqno) < int(_seqno)): - util.SMlog("Seqno decreased from %s to %s: ignoring these "\ - "ingress rules for vm %s" % (_seqno, seqno, vmName)) - rewriteLog = False - elif (signature != _signature): - util.SMlog("Seqno %s stayed the same but signature changed from "\ - "%s to %s for vm %s" % (seqno, _signature, signature, vmName)) - rewriteLog = True - reprogramChain = True - else: - util.SMlog("Seqno and signature stayed the same: %s : ignoring these "\ - "ingress rules for vm %s" % (seqno, vmName)) - rewriteLog = False - - return [reprogramDefault, reprogramChain, rewriteLog] - - -@echo -def write_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno): - vm_name = vmName - logfilename = "/var/run/cloud/" + vm_name +".log" - util.SMlog("Writing log to " + logfilename) - logf = open(logfilename, 'w') - output = ','.join([vmName, vmID, vmIP, domID, signature, seqno]) - result = True - try: - logf.write(output) - logf.write('\n') - except: - util.SMlog("Failed to write to rule log file " + logfilename) - result = False - - logf.close() - - return result - -@echo -def remove_rule_log_for_vm(vmName): - vm_name = vmName - logfilename = "/var/run/cloud/" + vm_name +".log" - - result = True - try: - os.remove(logfilename) - except: - util.SMlog("Failed to delete rule log file " + logfilename) - result = False - - return result - -@echo -def inflate_rules (zipped): - return zlib.decompress(base64.b64decode(zipped)) - -@echo -def network_rules(session, args): - try: - vm_name = args.get('vmName') - vm_ip = args.get('vmIP') - vm_id = args.get('vmID') - signature = args.pop('signature') - seqno = args.pop('seqno') - deflated = 'false' - if 'deflated' in args: - deflated = args.pop('deflated') - - try: - vm = session.xenapi.VM.get_by_name_label(vm_name) - if len(vm) != 1: - util.SMlog("### Could not get record for vm ## " + vm_name) - return 'false' - vm_rec = session.xenapi.VM.get_record(vm[0]) - domid = vm_rec.get('domid') - except: - util.SMlog("### Failed to get domid for vm ## " + vm_name) - return 'false' - if domid == '-1': - util.SMlog("### Failed to get domid for vm (-1): " + vm_name) - return 'false' - - vif = "vif" + domid + ".0" - tap = "tap" + domid + ".0" - vifs = [vif] - try: - util.pread2(['ifconfig', tap]) - vifs.append(tap) - except: - pass - - vmchain = chain_name(vm_name) - reason = 'seqno_change_or_sig_change' - [reprogramDefault, reprogramChain, rewriteLog] = \ - check_rule_log_for_vm (vm_name, vm_id, vm_ip, domid, signature, seqno) - - if not reprogramDefault and not reprogramChain: - util.SMlog("No changes detected between current state and received state") - reason = 'seqno_same_sig_same' - if rewriteLog: - reason = 'seqno_increased_sig_same' - write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, signature, seqno) - util.SMlog("Programming network rules for vm %s seqno=%s signature=%s guestIp=%s,"\ - " do nothing, reason=%s" % (vm_name, seqno, signature, vm_ip, reason)) - return 'true' - - if not reprogramChain: - util.SMlog("###Not programming any ingress rules since no changes detected?") - return 'true' - - if reprogramDefault: - util.SMlog("Change detected in vmId or vmIp or domId, resetting default rules") - default_network_rules(session, args) - reason = 'domid_change' - - rules = args.pop('rules') - if deflated.lower() == 'true': - rules = inflate_rules (rules) - - lines = rules.split(' ') - - util.SMlog("Programming network rules for vm %s seqno=%s numrules=%s signature=%s guestIp=%s,"\ - " update iptables, reason=%s" % (vm_name, seqno, len(lines), signature, vm_ip, reason)) - util.pread2(['iptables', '-F', vmchain]) - - for line in lines: - tokens = line.split(':') - if len(tokens) != 4: - continue - protocol = tokens[0] - start = tokens[1] - end = tokens[2] - cidrs = tokens.pop(); - ips = cidrs.split(",") - ips.pop() - allow_any = False - if '0.0.0.0/0' in ips: - i = ips.index('0.0.0.0/0') - del ips[i] - allow_any = True - range = start + ":" + end - if ips: - ipsetname = vmchain + "_" + protocol + "_" + start + "_" + end - if start == "-1": - ipsetname = vmchain + "_" + protocol + "_any" - - if ipset(ipsetname, protocol, start, end, ips) == False: - util.SMlog(" failed to create ipset for rule " + str(tokens)) - - if protocol == 'all': - iptables = ['iptables', '-I', vmchain, '-m', 'state', '--state', 'NEW', '-m', 'set', '--match-set', ipsetname, 'src', '-j', 'ACCEPT'] - elif protocol != 'icmp': - iptables = ['iptables', '-I', vmchain, '-p', protocol, '-m', protocol, '--dport', range, '-m', 'state', '--state', 'NEW', '-m', 'set', '--match-set', ipsetname, 'src', '-j', 'ACCEPT'] - else: - range = start + "/" + end - if start == "-1": - range = "any" - iptables = ['iptables', '-I', vmchain, '-p', 'icmp', '--icmp-type', range, '-m', 'set', '--match-set', ipsetname, 'src', '-j', 'ACCEPT'] - util.pread2(iptables) - util.SMlog(iptables) - - if allow_any and protocol != 'all': - if protocol != 'icmp': - iptables = ['iptables', '-I', vmchain, '-p', protocol, '-m', protocol, '--dport', range, '-m', 'state', '--state', 'NEW', '-j', 'ACCEPT'] - else: - range = start + "/" + end - if start == "-1": - range = "any" - iptables = ['iptables', '-I', vmchain, '-p', 'icmp', '--icmp-type', range, '-j', 'ACCEPT'] - util.pread2(iptables) - util.SMlog(iptables) - - util.pread2(['iptables', '-A', vmchain, '-j', 'DROP']) - - if write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, signature, seqno) == False: - return 'false' - - return 'true' - except: - util.SMlog("Failed to network rule !") - -@echo -def checkRouter(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/getRouterStatus.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - except: - util.SMlog(" check router status fail! ") - txt = '' - - return txt - -@echo -def bumpUpPriority(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/bumpUpPriority.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - txt = 'success' - except: - util.SMlog("bump up priority fail! ") - txt = '' - - return txt - -@echo -def getDomRVersion(session, args): - sargs = args['args'] - cmd = sargs.split(' ') - cmd.insert(0, "/opt/xensource/bin/getDomRVersion.sh") - cmd.insert(0, "/bin/bash") - try: - txt = util.pread2(cmd) - except: - util.SMlog(" get domR version fail! ") - txt = '' - - return txt - -if __name__ == "__main__": - XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi, "gethostvmstats": gethostvmstats, - "getvncport": getvncport, "getgateway": getgateway, "preparemigration": preparemigration, - "setIptables": setIptables, "pingdomr": pingdomr, "pingxenserver": pingxenserver, - "ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword, - "saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule, - "setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile, - "networkUsage": networkUsage, "network_rules":network_rules, - "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, - "destroy_network_rules_for_vm":destroy_network_rules_for_vm, - "default_network_rules_systemvm":default_network_rules_systemvm, - "get_rule_logs_for_vms":get_rule_logs_for_vms, - "setLinkLocalIP":setLinkLocalIP, "lt2p_vpn":lt2p_vpn, - "cleanup_rules":cleanup_rules, "checkRouter":checkRouter, - "bumpUpPriority":bumpUpPriority, "getDomRVersion":getDomRVersion }) diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 7f8157f6d35..25e8703d11e 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -153,8 +153,6 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { @Inject protected HostDao _hostDao = null; @Inject - protected HostDetailsDao _detailsDao = null; - @Inject protected DataCenterDao _dcDao = null; @Inject protected DataCenterIpAddressDao _privateIPAddressDao = null; @@ -173,8 +171,6 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { @Inject protected StoragePoolHostDao _storagePoolHostDao = null; @Inject - protected HostDetailsDao _hostDetailsDao = null; - @Inject protected ClusterDao _clusterDao = null; @Inject protected ClusterDetailsDao _clusterDetailsDao = null; diff --git a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java b/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java index 6da3422afdf..fa2987a319d 100755 --- a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java +++ b/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java @@ -140,7 +140,7 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet } @Override - public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd) throws ResourceAllocationException { + public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { /*Baremetal creates record after host rebooting for imaging, in createPrivateTemplate*/ return null; } diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 0c000550adf..6d05044a202 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -59,7 +59,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @param name * @param value */ - void updateConfiguration(long userId, String name, String value); + void updateConfiguration(long userId, String name, String category, String value); /** * Creates a new service offering diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index b506bf7f9c4..57a253ebc84 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -194,8 +194,6 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura @Inject VlanDao _vlanDao; @Inject - HostDetailsDao _hostDetailsDao; - @Inject IPAddressDao _publicIpAddressDao; @Inject DataCenterIpAddressDao _privateIpAddressDao; @@ -299,7 +297,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura s_logger.warn("Management network CIDR is not configured originally. Set it default to " + localCidrs[0]); _alertMgr.sendAlert(AlertManager.ALERT_TYPE_MANAGMENT_NODE, 0, new Long(0), "Management network CIDR is not configured originally. Set it default to " + localCidrs[0], ""); - _configDao.update(Config.ManagementNetwork.key(), localCidrs[0]); + _configDao.update(Config.ManagementNetwork.key(), Config.ManagementNetwork.getCategory(), localCidrs[0]); } else { s_logger.warn("Management network CIDR is not properly configured and we are not able to find a default setting"); _alertMgr.sendAlert(AlertManager.ALERT_TYPE_MANAGMENT_NODE, 0, new Long(0), "Management network CIDR is not properly configured and we are not able to find a default setting", ""); @@ -316,7 +314,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura @Override @DB - public void updateConfiguration(long userId, String name, String value) { + public void updateConfiguration(long userId, String name, String category, String value) { if (value != null && (value.trim().isEmpty() || value.equals("null"))) { value = null; } @@ -332,7 +330,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura Transaction txn = Transaction.currentTxn(); txn.start(); - if (!_configDao.update(name, value)) { + if (!_configDao.update(name, category, value)) { s_logger.error("Failed to update configuration option, name: " + name + ", value:" + value); throw new CloudRuntimeException("Failed to update configuration value. Please contact Cloud Support."); } @@ -343,7 +341,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String sql = "update host_details set value=? where name=?"; try { pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setString(1, DBEncryptionUtil.encrypt(value)); + pstmt.setString(1, value); pstmt.setString(2, "guest.network.device"); pstmt.executeUpdate(); @@ -354,7 +352,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String sql = "update host_details set value=? where name=?"; try { pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setString(1, DBEncryptionUtil.encrypt(value)); + pstmt.setString(1, value); pstmt.setString(2, "private.network.device"); pstmt.executeUpdate(); @@ -365,7 +363,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String sql = "update host_details set value=? where name=?"; try { pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setString(1, DBEncryptionUtil.encrypt(value)); + pstmt.setString(1, value); pstmt.setString(2, "public.network.device"); pstmt.executeUpdate(); @@ -376,7 +374,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String sql = "update host_details set value=? where name=?"; try { pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setString(1, DBEncryptionUtil.encrypt(value)); + pstmt.setString(1, value); pstmt.setString(2, "storage.network.device1"); pstmt.executeUpdate(); @@ -387,7 +385,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String sql = "update host_details set value=? where name=?"; try { pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setString(1, DBEncryptionUtil.encrypt(value)); + pstmt.setString(1, value); pstmt.setString(2, "storage.network.device2"); pstmt.executeUpdate(); @@ -435,7 +433,8 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String value = cmd.getValue(); UserContext.current().setEventDetails(" Name: " + name + " New Value: " + ((value == null) ? "" : value)); // check if config value exists - if (_configDao.findByName(name) == null) { + ConfigurationVO config = _configDao.findByName(name); + if (config == null) { throw new InvalidParameterValueException("Config parameter with name " + name + " doesn't exist"); } @@ -443,7 +442,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura return _configDao.findByName(name); } - updateConfiguration(userId, name, value); + updateConfiguration(userId, name, config.getCategory(), value); if (_configDao.getValue(name).equalsIgnoreCase(value)) { return _configDao.findByName(name); } else { @@ -2773,6 +2772,9 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String value = cmd.getValue(); String description = cmd.getDescription(); try { + if("Hidden".equals(category)){ + value = DBEncryptionUtil.encrypt(value); + } ConfigurationVO entity = new ConfigurationVO(category, instance, component, name, value, description); _configDao.persist(entity); s_logger.info("Successfully added configuration value into db: category:" + category + " instance:" + instance + " component:" + component + " name:" + name + " value:" + value); diff --git a/server/src/com/cloud/configuration/dao/ConfigurationDao.java b/server/src/com/cloud/configuration/dao/ConfigurationDao.java index 8c51eb9b694..25340b5a1b5 100644 --- a/server/src/com/cloud/configuration/dao/ConfigurationDao.java +++ b/server/src/com/cloud/configuration/dao/ConfigurationDao.java @@ -59,7 +59,7 @@ public interface ConfigurationDao extends GenericDao { */ public String getValue(String name); - public String getValueAndInitIfNotExist(String name, String initValue); + public String getValueAndInitIfNotExist(String name, String category, String initValue); /** @@ -70,5 +70,5 @@ public interface ConfigurationDao extends GenericDao { ConfigurationVO findByName(String name); - ConfigurationVO persistConfigValue(ConfigurationVO config); + boolean update(String name, String category, String value); } diff --git a/server/src/com/cloud/configuration/dao/ConfigurationDaoImpl.java b/server/src/com/cloud/configuration/dao/ConfigurationDaoImpl.java index d72c48fca1d..88b615eddda 100644 --- a/server/src/com/cloud/configuration/dao/ConfigurationDaoImpl.java +++ b/server/src/com/cloud/configuration/dao/ConfigurationDaoImpl.java @@ -26,7 +26,6 @@ import java.util.Map; import javax.ejb.Local; import javax.naming.ConfigurationException; -import javax.persistence.EntityExistsException; import org.apache.log4j.Logger; @@ -77,15 +76,18 @@ public class ConfigurationDaoImpl extends GenericDaoBase sc = NameSearch.create(); - sc.setParameters("name", name); - List configurations = listIncludingRemovedBy(sc); - - if (configurations.size() == 0) { - return null; - } - - ConfigurationVO config = configurations.get(0); - String value = config.getValue(); - return value; + ConfigurationVO config = findByName(name); + return (config == null) ? null : config.getValue(); } @Override @DB - public String getValueAndInitIfNotExist(String name, String initValue) { + public String getValueAndInitIfNotExist(String name, String category, String initValue) { Transaction txn = Transaction.currentTxn(); PreparedStatement stmt = null; PreparedStatement stmtInsert = null; @@ -166,19 +176,26 @@ public class ConfigurationDaoImpl extends GenericDaoBase implement sc.setParameters("hostId", hostId); sc.setParameters("name", name); - return findOneIncludingRemovedBy(sc); + DetailVO detail = findOneIncludingRemovedBy(sc); + if("password".equals(name) && detail != null){ + detail.setValue(DBEncryptionUtil.decrypt(detail.getValue())); + } + return detail; } @Override @@ -62,7 +67,11 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement List results = search(sc, null); Map details = new HashMap(results.size()); for (DetailVO result : results) { - details.put(result.getName(), result.getValue()); + if("password".equals(result.getName())){ + details.put(result.getName(), DBEncryptionUtil.decrypt(result.getValue())); + } else { + details.put(result.getName(), result.getValue()); + } } return details; } @@ -87,7 +96,11 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement expunge(sc); for (Map.Entry detail : details.entrySet()) { - DetailVO vo = new DetailVO(hostId, detail.getKey(), detail.getValue()); + String value = detail.getValue(); + if("password".equals(detail.getKey())){ + value = DBEncryptionUtil.encrypt(value); + } + DetailVO vo = new DetailVO(hostId, detail.getKey(), value); persist(vo); } txn.commit(); diff --git a/server/src/com/cloud/hypervisor/guru/HypervGuru.java b/server/src/com/cloud/hypervisor/guru/HypervGuru.java index 204066895e1..267e81430b1 100644 --- a/server/src/com/cloud/hypervisor/guru/HypervGuru.java +++ b/server/src/com/cloud/hypervisor/guru/HypervGuru.java @@ -29,7 +29,6 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru { @Inject GuestOSDao _guestOsDao; @Inject HostDao _hostDao; - @Inject HostDetailsDao _hostDetailsDao; protected HypervGuru() { super(); diff --git a/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java index ff64fa8c29e..9015a452db5 100644 --- a/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java @@ -113,7 +113,6 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl @Inject HostDao _hostDao; @Inject NetworkServiceMapDao _ntwkSrvcProviderDao; @Inject DataCenterDao _dcDao; - @Inject HostDetailsDao _detailsDao; @Inject NetworkManager _networkMgr; @Inject InlineLoadBalancerNicMapDao _inlineLoadBalancerNicMapDao; @Inject NicDao _nicDao; @@ -316,7 +315,7 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl } public ExternalFirewallResponse createExternalFirewallResponse(Host externalFirewall) { - Map fwDetails = _detailsDao.findDetails(externalFirewall.getId()); + Map fwDetails = _hostDetailDao.findDetails(externalFirewall.getId()); ExternalFirewallResponse response = new ExternalFirewallResponse(); response.setId(externalFirewall.getId()); response.setIpAddress(externalFirewall.getPrivateIpAddress()); diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 5774cc977ac..c4ffe6d540a 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -134,8 +134,6 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase @Inject DataCenterDao _dcDao; @Inject - HostDetailsDao _detailsDao; - @Inject NetworkManager _networkMgr; @Inject InlineLoadBalancerNicMapDao _inlineLoadBalancerNicMapDao; @@ -329,7 +327,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } public ExternalLoadBalancerResponse createExternalLoadBalancerResponse(Host externalLoadBalancer) { - Map lbDetails = _detailsDao.findDetails(externalLoadBalancer.getId()); + Map lbDetails = _hostDetailDao.findDetails(externalLoadBalancer.getId()); ExternalLoadBalancerResponse response = new ExternalLoadBalancerResponse(); response.setId(externalLoadBalancer.getId()); response.setIpAddress(externalLoadBalancer.getPrivateIpAddress()); @@ -650,7 +648,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } private boolean externalLoadBalancerIsInline(HostVO externalLoadBalancer) { - DetailVO detail = _detailsDao.findDetail(externalLoadBalancer.getId(), "inline"); + DetailVO detail = _hostDetailDao.findDetail(externalLoadBalancer.getId(), "inline"); return (detail != null && detail.getValue().equals("true")); } diff --git a/server/src/com/cloud/network/ExternalNetworkDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalNetworkDeviceManagerImpl.java index 9a1d37ab517..ca561dacbb7 100644 --- a/server/src/com/cloud/network/ExternalNetworkDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalNetworkDeviceManagerImpl.java @@ -98,7 +98,6 @@ public class ExternalNetworkDeviceManagerImpl implements ExternalNetworkDeviceMa @Inject PortForwardingRulesDao _portForwardingRulesDao; @Inject LoadBalancerDao _loadBalancerDao; @Inject ConfigurationDao _configDao; - @Inject HostDetailsDao _detailsDao; @Inject NetworkOfferingDao _networkOfferingDao; @Inject NicDao _nicDao; @Inject VpnUserDao _vpnUsersDao; diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 92ea5c8fc39..04bb0cded93 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -601,8 +601,79 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return success; } + protected boolean applyProviderIpAssociations(Network network, Purpose purpose, boolean continueOnError, List rules) throws ResourceUnavailableException { + boolean success = true; + + List publicIps = new ArrayList(); + for (FirewallRule rule : rules) { + IPAddressVO lbIp = _ipAddressDao.findById(rule.getSourceIpAddressId()); + PublicIp publicIp = new PublicIp(lbIp, _vlanDao.findById(lbIp.getVlanId()), NetUtils.createSequenceBasedMacAddress(lbIp.getMacAddress())); + publicIps.add(publicIp); + } + + for (NetworkElement ne : _networkElements) { + try { + boolean handled; + switch (purpose) { + case LoadBalancing: + if (!(ne instanceof LoadBalancingServiceProvider)) { + continue; + } + LoadBalancingServiceProvider lbProvider = (LoadBalancingServiceProvider) ne; + s_logger.trace("Asking " + ne + " to apply ip associations for " + purpose.toString() + " purpose"); + handled = lbProvider.applyLoadBalancerIp(network, publicIps); + break; + + case PortForwarding: + if (!(ne instanceof PortForwardingServiceProvider)) { + continue; + } + PortForwardingServiceProvider pfProvider = (PortForwardingServiceProvider) ne; + s_logger.trace("Asking " + ne + " to apply ip associations for " + purpose.toString() + " purpose"); + handled = pfProvider.applyIps(network, publicIps); + break; + + case StaticNat: + case Firewall: + if (!(ne instanceof FirewallServiceProvider)) { + continue; + } + s_logger.trace("Asking " + ne + " to apply ip associations for " + purpose.toString() + " purpose"); + FirewallServiceProvider fwProvider = (FirewallServiceProvider) ne; + handled = fwProvider.applyIps(network, publicIps); + break; + + default: + s_logger.debug("Unable to handle IP association for purpose: " + purpose.toString()); + handled = false; + } + s_logger.debug("Network Rules for network " + network.getId() + " were " + (handled ? "" : " not") + " handled by " + ne.getName()); + } catch (ResourceUnavailableException e) { + success = false; + if (!continueOnError) { + throw e; + } else { + s_logger.debug("Resource is not available: " + ne.getName(), e); + } + } + } + return success; + } + protected boolean applyIpAssociations(Network network, boolean continueOnError, List publicIps) throws ResourceUnavailableException { boolean success = true; + List srcNatpublicIps = new ArrayList(); + + // apply IP only for source NAT public IP at this point. Depending on the network service for which + // public IP will be used do IP Association to respective network service provider before apply rules + if (publicIps != null && !publicIps.isEmpty()) { + for (PublicIp ip : publicIps) { + if (ip.isSourceNat()) { + srcNatpublicIps.add(ip); + } + } + } + for (NetworkElement element : _networkElements) { try { if (!(element instanceof FirewallServiceProvider)) { @@ -610,7 +681,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } FirewallServiceProvider e = (FirewallServiceProvider)element; s_logger.trace("Asking " + element + " to apply ip associations"); - e.applyIps(network, publicIps); + e.applyIps(network, srcNatpublicIps); } catch (ResourceUnavailableException e) { success = false; if (!continueOnError) { @@ -2583,6 +2654,10 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag boolean success = true; Network network = _networksDao.findById(rules.get(0).getNetworkId()); Purpose purpose = rules.get(0).getPurpose(); + + // associate the IP with corresponding network service provider + applyProviderIpAssociations(network, purpose, continueOnError, rules); + for (NetworkElement ne : _networkElements) { try { boolean handled; @@ -2745,14 +2820,19 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag s_logger.debug("Restarting network " + networkId + "..."); - //shutdown the network ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount); - s_logger.debug("Shutting down the network id=" + networkId + " as a part of network restart"); + + if (cleanup) { + //shutdown the network + s_logger.debug("Shutting down the network id=" + networkId + " as a part of network restart"); - if (!shutdownNetworkElementsAndResources(context, cleanup, network)) { - s_logger.debug("Failed to shutdown the network elements and resources as a part of network restart: " + network.getState()); - setRestartRequired(network, true); - return false; + if (!shutdownNetworkElementsAndResources(context, true, network)) { + s_logger.debug("Failed to shutdown the network elements and resources as a part of network restart: " + network.getState()); + setRestartRequired(network, true); + return false; + } + } else { + s_logger.debug("Skip the shutting down of network id=" + networkId); } //implement the network elements and rules again @@ -3611,14 +3691,30 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return true; } + List staticNatIps = new ArrayList(); + for (StaticNat rule : staticNats) { + IPAddressVO staticNatIP = _ipAddressDao.findById(rule.getSourceIpAddressId()); + PublicIp publicIp = new PublicIp(staticNatIP, _vlanDao.findById(staticNatIP.getVlanId()), NetUtils.createSequenceBasedMacAddress(staticNatIP.getMacAddress())); + staticNatIps.add(publicIp); + } + boolean success = true; + boolean handled = false; Network network = _networksDao.findById(staticNats.get(0).getNetworkId()); for (NetworkElement ne : _networkElements) { try { if (!(ne instanceof StaticNatServiceProvider)) { continue; } - boolean handled = ((StaticNatServiceProvider)ne).applyStaticNats(network, staticNats); + + // associate the IP's with StaticNatServiceProvider for the network + handled = ((StaticNatServiceProvider)ne).applyIps(network, staticNatIps); + if(!handled) { + s_logger.debug(ne.getName() +" did not assocate IP with source Nat service provider for the network " + network.getId() + "so skippg apply static nats"); + continue; + } + + handled = ((StaticNatServiceProvider)ne).applyStaticNats(network, staticNats); s_logger.debug("Static Nat for network " + network.getId() + " were " + (handled ? "" : " not") + " handled by " + ne.getName()); } catch (ResourceUnavailableException e) { if (!continueOnError) { diff --git a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java index cbb429a4465..3fc8f11bbb4 100644 --- a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java +++ b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java @@ -39,6 +39,7 @@ import com.cloud.network.Network.Service; import com.cloud.network.NetworkManager; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; import com.cloud.network.dao.NetworkDao; import com.cloud.network.lb.ElasticLoadBalancerManager; import com.cloud.network.lb.LoadBalancingRule; @@ -179,4 +180,10 @@ public class ElasticLoadBalancerElement extends AdapterBase implements LoadBalan public boolean verifyServicesCombination(List services) { return true; } + + @Override + public boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException { + // TODO Auto-generated method stub + return false; + } } diff --git a/server/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java b/server/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java index 6f58a9a3b4b..68567f88dbc 100644 --- a/server/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java +++ b/server/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java @@ -66,6 +66,7 @@ import com.cloud.network.NetworkManager; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PhysicalNetworkVO; +import com.cloud.network.PublicIpAddress; import com.cloud.network.dao.ExternalLoadBalancerDeviceDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkExternalLoadBalancerDao; @@ -440,4 +441,10 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan public boolean verifyServicesCombination(List services) { return true; } + + @Override + public boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException { + // return true, as IP will be associated as part of LB rule configuration + return true; + } } diff --git a/server/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java b/server/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java index c70f2280b85..17daa651b69 100644 --- a/server/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java +++ b/server/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java @@ -175,16 +175,6 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan return true; } - @Override - public boolean applyIps(Network network, List ipAddresses) throws ResourceUnavailableException { - if (!canHandle(network)) { - return false; - } - - return applyIps(network, ipAddresses); - } - - @Override public boolean applyFWRules(Network config, List rules) throws ResourceUnavailableException { if (!canHandle(config)) { @@ -505,4 +495,10 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan public boolean verifyServicesCombination(List services) { return true; } + + @Override + public boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException { + // TODO Auto-generated method stub + return false; + } } \ No newline at end of file diff --git a/server/src/com/cloud/network/element/NetscalerExternalLoadBalancerElement.java b/server/src/com/cloud/network/element/NetscalerExternalLoadBalancerElement.java index 06c638461d4..a87e9a98327 100644 --- a/server/src/com/cloud/network/element/NetscalerExternalLoadBalancerElement.java +++ b/server/src/com/cloud/network/element/NetscalerExternalLoadBalancerElement.java @@ -64,6 +64,7 @@ import com.cloud.network.NetworkVO; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PhysicalNetworkVO; +import com.cloud.network.PublicIpAddress; import com.cloud.network.dao.ExternalLoadBalancerDeviceDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkExternalLoadBalancerDao; @@ -465,4 +466,10 @@ public class NetscalerExternalLoadBalancerElement extends ExternalLoadBalancerDe public boolean verifyServicesCombination(List services) { return true; } + + @Override + public boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException { + // return true, as IP will be associated as part of LB rule configuration + return true; + } } \ No newline at end of file diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index 024a8097fc4..57a3ce0f2d4 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -270,6 +270,21 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl } } + @Override + public boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException { + if (canHandle(network, Service.Lb)) { + List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); + if (routers == null || routers.isEmpty()) { + s_logger.debug("Virtual router element doesn't need to associate load balancer ip addresses on the backend; virtual router doesn't exist in the network " + network.getId()); + return true; + } + + return _routerMgr.associateIP(network, ipAddress, routers); + } else { + return false; + } + } + @Override public Provider getProvider() { return Provider.VirtualRouter; @@ -644,4 +659,5 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl } return true; } + } diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index 46e4a7fc7ec..e0a9ee373d0 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -55,8 +55,8 @@ import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.rules.FirewallManager; import com.cloud.network.rules.FirewallRule; -import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.FirewallRuleType; +import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.PortForwardingRuleVO; @@ -375,8 +375,10 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma if (!_elbEnabled) { protocolCapabilities = _networkMgr.getNetworkServiceCapabilities(network.getId(), Service.Lb); } - } else { + } else if (purpose == Purpose.Firewall){ protocolCapabilities = _networkMgr.getNetworkServiceCapabilities(network.getId(), Service.Firewall); + } else if (purpose == Purpose.PortForwarding) { + protocolCapabilities = _networkMgr.getNetworkServiceCapabilities(network.getId(), Service.PortForwarding); } if (protocolCapabilities != null) { diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index f862798f435..225d8e43221 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -76,8 +76,6 @@ import com.cloud.agent.api.to.StaticNatRuleTO; import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; import com.cloud.api.commands.UpgradeRouterCmd; -import com.cloud.async.AsyncJobManager; -import com.cloud.capacity.dao.CapacityDao; import com.cloud.cluster.ManagementServerHostVO; import com.cloud.cluster.ManagementServerNode; import com.cloud.cluster.dao.ManagementServerHostDao; @@ -85,7 +83,6 @@ import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ZoneConfig; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.configuration.dao.ResourceLimitDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; @@ -100,7 +97,6 @@ import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; -import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.event.dao.EventDao; @@ -146,7 +142,6 @@ import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.LoadBalancerVMMapDao; import com.cloud.network.dao.NetworkDao; -import com.cloud.network.dao.NetworkRuleConfigDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.dao.VirtualRouterProviderDao; @@ -181,13 +176,11 @@ import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; -import com.cloud.user.AccountService; import com.cloud.user.User; import com.cloud.user.UserContext; import com.cloud.user.UserStatisticsVO; import com.cloud.user.UserStatsLogVO; import com.cloud.user.UserVO; -import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.user.dao.UserStatisticsDao; import com.cloud.user.dao.UserStatsLogDao; @@ -253,10 +246,6 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian @Inject UserDao _userDao = null; @Inject - AccountDao _accountDao = null; - @Inject - DomainDao _domainDao = null; - @Inject UserStatisticsDao _userStatsDao = null; @Inject VolumeDao _volsDao = null; @@ -271,10 +260,6 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian @Inject VMTemplateHostDao _vmTemplateHostDao = null; @Inject - ResourceLimitDao _limitDao = null; - @Inject - CapacityDao _capacityDao = null; - @Inject UserStatsLogDao _userStatsLogDao = null; @Inject AgentManager _agentMgr; @@ -285,20 +270,14 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian @Inject AccountManager _accountMgr; @Inject - AccountService _accountService; - @Inject ConfigurationManager _configMgr; @Inject - AsyncJobManager _asyncMgr; - @Inject ServiceOfferingDao _serviceOfferingDao = null; @Inject UserVmDao _userVmDao; @Inject FirewallRulesDao _firewallRulesDao; @Inject - NetworkRuleConfigDao _networkRuleConfigDao; - @Inject UserStatisticsDao _statsDao = null; @Inject NetworkOfferingDao _networkOfferingDao = null; @@ -675,7 +654,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian throw new ConfigurationException(msg); } - _systemAcct = _accountService.getSystemAccount(); + _systemAcct = _accountMgr.getSystemAccount(); String aggregationRange = configs.get("usage.stats.job.aggregation.range"); _usageAggregationRange = NumbersUtil.parseInt(aggregationRange, 1440); @@ -1254,7 +1233,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian NicProfile defaultNic = new NicProfile(); //if source nat service is supported by the network, get the source nat ip address if (publicNetwork) { - PublicIp sourceNatIp = _networkMgr.assignSourceNatIpAddress(owner, guestNetwork, _accountService.getSystemUser().getId()); + PublicIp sourceNatIp = _networkMgr.assignSourceNatIpAddress(owner, guestNetwork, _accountMgr.getSystemUser().getId()); defaultNic.setDefaultNic(true); defaultNic.setIp4Address(sourceNatIp.getAddress().addr()); defaultNic.setGateway(sourceNatIp.getGateway()); @@ -1336,6 +1315,9 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian //Router is the network element, we don't know the hypervisor type yet. //Try to allocate the domR twice using diff hypervisors, and when failed both times, throw the exception up List supportedHypervisors = _resourceMgr.getSupportedHypervisorTypes(dest.getDataCenter().getId()); + if (supportedHypervisors.isEmpty()) { + throw new InsufficientServerCapacityException("Unable to create virtual router, there are no clusters in the zone ", DataCenter.class, dest.getDataCenter().getId()); + } int retry = 0; for (HypervisorType hType : supportedHypervisors) { try { @@ -1346,9 +1328,15 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian s_logger.debug(hType + " won't support system vm, skip it"); continue; } + + boolean offerHA = routerOffering.getOfferHA(); + /* We don't provide HA to redundant router VMs, admin should own it all, and redundant router themselves are HA */ + if (isRedundant) { + offerHA = false; + } router = new DomainRouterVO(id, routerOffering.getId(), vrProvider.getId(), VirtualMachineName.getRouterName(id, _instance), template.getId(), template.getHypervisorType(), - template.getGuestOSId(), owner.getDomainId(), owner.getId(), guestNetwork.getId(), isRedundant, 0, false, RedundantState.UNKNOWN, routerOffering.getOfferHA(), false); + template.getGuestOSId(), owner.getDomainId(), owner.getId(), guestNetwork.getId(), isRedundant, 0, false, RedundantState.UNKNOWN, offerHA, false); router.setRole(Role.VIRTUAL_ROUTER); router = _itMgr.allocate(router, template, routerOffering, networks, plan, null, owner); break; @@ -1481,7 +1469,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian } if (!skip) { if (state != State.Running) { - router = startVirtualRouter(router, _accountService.getSystemUser(), _accountService.getSystemAccount(), params); + router = startVirtualRouter(router, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount(), params); } if (router != null) { runningRouters.add(router); @@ -2155,6 +2143,11 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian return null; } + NetworkOfferingVO offering = _networkOfferingDao.findById(_networkDao.findById(defaultNic.getNetworkId()).getNetworkOfferingId()); + if (offering.getRedundantRouter()) { + return findGatewayIp(userVmId); + } + //find domR's nic in the network NicVO domrDefaultNic = _nicDao.findByNetworkIdAndType(defaultNic.getNetworkId(), VirtualMachine.Type.DomainRouter); return domrDefaultNic.getIp4Address(); diff --git a/server/src/com/cloud/projects/ProjectManagerImpl.java b/server/src/com/cloud/projects/ProjectManagerImpl.java index e62a00be9ba..950f1f9a0b4 100755 --- a/server/src/com/cloud/projects/ProjectManagerImpl.java +++ b/server/src/com/cloud/projects/ProjectManagerImpl.java @@ -546,6 +546,11 @@ public class ProjectManagerImpl implements ProjectManager, Manager{ if (project == null) { throw new InvalidParameterValueException("Unable to find the project id=" + projectId); } + + //User can be added to Active project only + if (project.getState() != Project.State.Active) { + throw new InvalidParameterValueException("Can't add account to the project id=" + projectId + " in state=" + project.getState() + " as it's no longer active"); + } //check that account-to-add exists Account account = null; @@ -916,6 +921,7 @@ public class ProjectManagerImpl implements ProjectManager, Manager{ @Override @ActionEvent(eventType = EventTypes.EVENT_PROJECT_ACTIVATE, eventDescription = "activating project") + @DB public Project activateProject(long projectId) { Account caller = UserContext.current().getCaller(); @@ -941,9 +947,16 @@ public class ProjectManagerImpl implements ProjectManager, Manager{ throw new InvalidParameterValueException("Can't activate the project in " + currentState + " state"); } + Transaction txn = Transaction.currentTxn(); + txn.start(); + project.setState(Project.State.Active); _projectDao.update(projectId, project); + _accountMgr.enableAccount(project.getProjectAccountId()); + + txn.commit(); + return _projectDao.findById(projectId); } @@ -970,7 +983,8 @@ public class ProjectManagerImpl implements ProjectManager, Manager{ } - private boolean suspendProject(ProjectVO project) throws ConcurrentOperationException, ResourceUnavailableException{ + private boolean suspendProject(ProjectVO project) throws ConcurrentOperationException, ResourceUnavailableException { + s_logger.debug("Marking project " + project + " with state " + State.Suspended + " as a part of project suspend..."); project.setState(State.Suspended); boolean updateResult = _projectDao.update(project.getId(), project); @@ -979,7 +993,7 @@ public class ProjectManagerImpl implements ProjectManager, Manager{ long projectAccountId = project.getProjectAccountId(); if (!_accountMgr.disableAccount(projectAccountId)) { s_logger.warn("Failed to suspend all project's " + project + " resources; the resources will be suspended later by background thread"); - } + } } else { throw new CloudRuntimeException("Failed to mark the project " + project + " with state " + State.Suspended); } diff --git a/server/src/com/cloud/projects/dao/ProjectAccountDao.java b/server/src/com/cloud/projects/dao/ProjectAccountDao.java index 97606174c06..658ec8fbf9f 100644 --- a/server/src/com/cloud/projects/dao/ProjectAccountDao.java +++ b/server/src/com/cloud/projects/dao/ProjectAccountDao.java @@ -32,4 +32,6 @@ public interface ProjectAccountDao extends GenericDao{ boolean canModifyProjectAccount(long accountId, long projectAccountId); List listPermittedAccountIds(long accountId); + + List listAdministratedProjects(long adminAccountId); } diff --git a/server/src/com/cloud/projects/dao/ProjectAccountDaoImpl.java b/server/src/com/cloud/projects/dao/ProjectAccountDaoImpl.java index 8555aca9ab4..802f3fe9a61 100644 --- a/server/src/com/cloud/projects/dao/ProjectAccountDaoImpl.java +++ b/server/src/com/cloud/projects/dao/ProjectAccountDaoImpl.java @@ -17,23 +17,23 @@ */ package com.cloud.projects.dao; -import java.util.ArrayList; import java.util.List; import javax.ejb.Local; -import org.apache.log4j.Logger; - import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectAccountVO; import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; @Local(value={ProjectAccountDao.class}) public class ProjectAccountDaoImpl extends GenericDaoBase implements ProjectAccountDao { - private static final Logger s_logger = Logger.getLogger(ProjectAccountDaoImpl.class); protected final SearchBuilder AllFieldsSearch; + final GenericSearchBuilder AdminSearch; + final GenericSearchBuilder ProjectAccountSearch; protected ProjectAccountDaoImpl() { AllFieldsSearch = createSearchBuilder(); @@ -42,6 +42,17 @@ public class ProjectAccountDaoImpl extends GenericDaoBase listPermittedAccountIds(long accountId) { - List permittedAccounts = new ArrayList(); - SearchCriteria sc = AllFieldsSearch.create(); + SearchCriteria sc = ProjectAccountSearch.create(); sc.setParameters("accountId", accountId); - - List records = listBy(sc); - - for (ProjectAccountVO record : records) { - permittedAccounts.add(record.getProjectAccountId()); - } - - return permittedAccounts; + return customSearch(sc, null); + } + + @Override + public List listAdministratedProjects(long adminAccountId) { + SearchCriteria sc = AdminSearch.create(); + sc.setParameters("role", ProjectAccount.Role.Admin); + sc.setParameters("accountId", adminAccountId); + return customSearch(sc, null); } } diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 64b251455bd..37f983b7f74 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -195,8 +195,6 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma protected ClusterManager _clusterMgr; @Inject protected StoragePoolHostDao _storagePoolHostDao; - @Inject - protected HostDetailsDao _detailsDao; @Inject(adapter = PodAllocator.class) protected Adapters _podAllocators = null; @@ -1800,9 +1798,9 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma return false; } - DetailVO nv = _detailsDao.findDetail(hostId, ApiConstants.USERNAME); + DetailVO nv = _hostDetailsDao.findDetail(hostId, ApiConstants.USERNAME); String username = nv.getValue(); - nv = _detailsDao.findDetail(hostId, ApiConstants.PASSWORD); + nv = _hostDetailsDao.findDetail(hostId, ApiConstants.PASSWORD); String password = nv.getValue(); UpdateHostPasswordCommand cmd = new UpdateHostPasswordCommand(username, password); attache.updatePassword(cmd); diff --git a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index 6bc6a7f054e..557c23b32ce 100755 --- a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -200,7 +200,7 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{ @Override public long findCorrectResourceLimitForAccount(Account account, ResourceType type) { - long max = -1; //if resource limit is not found, then we treat it as unlimited + long max = Resource.RESOURCE_UNLIMITED; //if resource limit is not found, then we treat it as unlimited ResourceLimitVO limit = _resourceLimitDao.findByOwnerIdAndType(account.getId(), ResourceOwnerType.Account, type); // Check if limit is configured for account @@ -224,7 +224,7 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{ @Override public long findCorrectResourceLimitForDomain(Domain domain, ResourceType type) { - long max = -1; + long max = Resource.RESOURCE_UNLIMITED; // Check account ResourceLimitVO limit = _resourceLimitDao.findByOwnerIdAndType(domain.getId(), ResourceOwnerType.Domain, type); @@ -274,11 +274,11 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{ // Check account limits long accountLimit = findCorrectResourceLimitForAccount(account, type); long potentialCount = _resourceCountDao.getResourceCount(account.getId(), ResourceOwnerType.Account, type) + numResources; - if (accountLimit != -1 && potentialCount > accountLimit) { - String message = "Maximum number of resources of type \"" + type + "\" for account name=" + account.getAccountName() + if (accountLimit != Resource.RESOURCE_UNLIMITED && potentialCount > accountLimit) { + String message = "Maximum number of resources of type '" + type + "' for account name=" + account.getAccountName() + " in domain id=" + account.getDomainId() + " has been exceeded."; if (project != null) { - message = "Maximum number of resources of type \"" + type + "\" for project name=" + project.getName() + message = "Maximum number of resources of type '" + type + "' for project name=" + project.getName() + " in domain id=" + account.getDomainId() + " has been exceeded."; } throw new ResourceAllocationException(message, type); @@ -295,10 +295,10 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{ while (domainId != null) { DomainVO domain = _domainDao.findById(domainId); ResourceLimitVO domainLimit = _resourceLimitDao.findByOwnerIdAndType(domainId, ResourceOwnerType.Domain, type); - if (domainLimit != null) { + if (domainLimit != null && domainLimit.getMax().longValue() != Resource.RESOURCE_UNLIMITED) { long domainCount = _resourceCountDao.getResourceCount(domainId, ResourceOwnerType.Domain, type); if ((domainCount + numResources) > domainLimit.getMax().longValue()) { - throw new ResourceAllocationException("Maximum number of resources of type \"" + type + "\" for domain id=" + domainId + " has been exceeded.", type); + throw new ResourceAllocationException("Maximum number of resources of type '" + type + "' for domain id=" + domainId + " has been exceeded.", type); } } @@ -458,8 +458,8 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{ Account caller = UserContext.current().getCaller(); if (max == null) { - max = new Long(-1); - } else if (max < -1) { + max = new Long(Resource.RESOURCE_UNLIMITED); + } else if (max.longValue() < Resource.RESOURCE_UNLIMITED) { throw new InvalidParameterValueException("Please specify either '-1' for an infinite limit, or a limit that is at least '0'."); } diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 666f3c2081d..bc5356a681a 100644 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -174,16 +174,17 @@ public class ConfigurationServerImpl implements ConfigurationServer { String instance = "DEFAULT"; String component = c.getComponent(); String value = c.getDefaultValue(); + value = ("Hidden".equals(category)) ? DBEncryptionUtil.encrypt(value) : value; String description = c.getDescription(); ConfigurationVO configVO = new ConfigurationVO(category, instance, component, name, value, description); _configDao.persist(configVO); } } - _configDao.update("secondary.storage.vm", "true"); + _configDao.update(Config.UseSecondaryStorageVm.key(), Config.UseSecondaryStorageVm.getCategory(), "true"); s_logger.debug("ConfigurationServer made secondary storage vm required."); - _configDao.update("secstorage.encrypt.copy", "true"); + _configDao.update(Config.SecStorageEncryptCopy.key(), Config.SecStorageEncryptCopy.getCategory(), "true"); s_logger.debug("ConfigurationServer made secondary storage copy encrypted."); _configDao.update("secstorage.secure.copy.cert", "realhostip"); @@ -201,7 +202,7 @@ public class ConfigurationServerImpl implements ConfigurationServer { // Save the mount parent to the configuration table String mountParent = getMountParent(); if (mountParent != null) { - _configDao.update("mount.parent", mountParent); + _configDao.update(Config.MountParent.key(), Config.MountParent.getCategory(), mountParent); s_logger.debug("ConfigurationServer saved \"" + mountParent + "\" as mount.parent."); } else { s_logger.debug("ConfigurationServer could not detect mount.parent."); @@ -209,7 +210,7 @@ public class ConfigurationServerImpl implements ConfigurationServer { String hostIpAdr = NetUtils.getDefaultHostIp(); if (hostIpAdr != null) { - _configDao.update("host", hostIpAdr); + _configDao.update(Config.ManagementHostIPAdr.key(), Config.ManagementHostIPAdr.getCategory(), hostIpAdr); s_logger.debug("ConfigurationServer saved \"" + hostIpAdr + "\" as host."); } @@ -266,7 +267,7 @@ public class ConfigurationServerImpl implements ConfigurationServer { updateCloudIdentifier(); // Set init to true - _configDao.update("init", "true"); + _configDao.update("init", "Hidden", "true"); } @@ -402,7 +403,7 @@ public class ConfigurationServerImpl implements ConfigurationServer { String currentCloudIdentifier = _configDao.getValue("cloud.identifier"); if (currentCloudIdentifier == null || currentCloudIdentifier.isEmpty()) { String uuid = UUID.randomUUID().toString(); - _configDao.update("cloud.identifier", uuid); + _configDao.update(Config.CloudIdentifier.key(),Config.CloudIdentifier.getCategory(), uuid); } } @@ -485,14 +486,14 @@ public class ConfigurationServerImpl implements ConfigurationServer { s_logger.info("Generated SSL keystore."); } String base64Keystore = getBase64Keystore(keystorePath); - ConfigurationVO configVO = new ConfigurationVO("Hidden", "DEFAULT", "management-server", "ssl.keystore", base64Keystore, "SSL Keystore for the management servers"); + ConfigurationVO configVO = new ConfigurationVO("Hidden", "DEFAULT", "management-server", "ssl.keystore", DBEncryptionUtil.encrypt(base64Keystore), "SSL Keystore for the management servers"); _configDao.persist(configVO); s_logger.info("Stored SSL keystore to database."); } else if (keystoreFile.exists()) { // and dbExisted // Check if they are the same one, otherwise override with local keystore String base64Keystore = getBase64Keystore(keystorePath); if (base64Keystore.compareTo(dbString) != 0) { - _configDao.update("ssl.keystore", base64Keystore); + _configDao.update("ssl.keystore", "Hidden", base64Keystore); s_logger.info("Updated database keystore with local one."); } } else { // !keystoreFile.exists() and dbExisted @@ -702,7 +703,7 @@ public class ConfigurationServerImpl implements ConfigurationServer { SecretKey key = generator.generateKey(); encodedKey = Base64.encodeBase64URLSafeString(key.getEncoded()); - _configDao.update("security.singlesignon.key", encodedKey); + _configDao.update(Config.SSOKey.key(), Config.SSOKey.getCategory(), encodedKey); } catch (NoSuchAlgorithmException ex) { s_logger.error("error generating sso key", ex); } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 1aaa36df542..3ffab2f58d3 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -217,6 +217,7 @@ import com.cloud.utils.component.Adapters; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.component.Inject; import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GlobalLock; @@ -1294,8 +1295,9 @@ public class ManagementServerImpl implements ManagementServer { } else { domain = _domainDao.findById(DomainVO.ROOT_DOMAIN); } + List hypers = null; - if( ! isIso ) { + if(!isIso) { hypers = _resourceMgr.listAvailHypervisorInZone(null, null); } Set> templateZonePairSet = new HashSet>(); @@ -3483,7 +3485,7 @@ public class ManagementServerImpl implements ManagementServer { // although we may have race conditioning here, database transaction serialization should // give us the same key if (_hashKey == null) { - _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), UUID.randomUUID().toString()); + _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(), UUID.randomUUID().toString()); } return _hashKey; } @@ -3657,7 +3659,7 @@ public class ManagementServerImpl implements ManagementServer { DetailVO nv = _detailsDao.findDetail(h.getId(), ApiConstants.USERNAME); if (nv.getValue().equals(cmd.getUsername())) { DetailVO nvp = new DetailVO(h.getId(), ApiConstants.PASSWORD, cmd.getPassword()); - nvp.setValue(cmd.getPassword()); + nvp.setValue(DBEncryptionUtil.encrypt(cmd.getPassword())); _detailsDao.persist(nvp); } else { throw new InvalidParameterValueException("The username is not under use by management server."); @@ -3675,7 +3677,7 @@ public class ManagementServerImpl implements ManagementServer { DetailVO nv = _detailsDao.findDetail(h.getId(), ApiConstants.USERNAME); if (nv.getValue().equals(cmd.getUsername())) { DetailVO nvp = _detailsDao.findDetail(h.getId(), ApiConstants.PASSWORD); - nvp.setValue(cmd.getPassword()); + nvp.setValue(DBEncryptionUtil.encrypt(cmd.getPassword())); _detailsDao.persist(nvp); } else { // if one host in the cluster has diff username then rollback to maintain consistency diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 7833d18ab87..7a6da7fea09 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -222,8 +222,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag @Inject protected ConsoleProxyDao _consoleProxyDao; @Inject - protected HostDetailsDao _detailsDao; - @Inject protected SnapshotDao _snapshotDao; @Inject protected SnapshotManager _snapMgr; diff --git a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index 5725650aa40..c1151343c1a 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -575,7 +575,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem } } else if (templateFilter == TemplateFilter.all && caller.getType() == Account.ACCOUNT_TYPE_ADMIN) { whereClause += attr; - } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { + } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && !isIso) { return templateZonePairList; } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManager.java b/server/src/com/cloud/storage/snapshot/SnapshotManager.java index ad78e75874f..0aa53fe0250 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManager.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManager.java @@ -111,8 +111,6 @@ public interface SnapshotManager { */ boolean deleteSnapshotDirsForAccount(long accountId); - void validateSnapshot(Long userId, SnapshotVO snapshot); - SnapshotPolicyVO getPolicyForVolume(long volumeId); boolean destroySnapshotBackUp(long snapshotId); diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 5203ec7a513..b982b36cbce 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -81,7 +81,6 @@ import com.cloud.storage.Storage; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.SwiftVO; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; @@ -118,7 +117,6 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine.State; @@ -154,8 +152,6 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma @Inject protected SnapshotScheduleDao _snapshotScheduleDao; @Inject - protected HostDetailsDao _detailsDao; - @Inject protected DomainDao _domainDao; @Inject protected StorageManager _storageMgr; @@ -300,6 +296,8 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma s_logger.debug("CreateSnapshot: this is empty snapshot "); snapshot.setPath(preSnapshotPath); snapshot.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId()); + snapshot.setSwiftId(preSnapshotVO.getSwiftId()); + snapshot.setStatus(Snapshot.Status.BackedUp); snapshot.setPrevSnapshotId(preId); snapshot.setSecHostId(preSnapshotVO.getSecHostId()); @@ -368,32 +366,21 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma @Override @DB @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "creating snapshot", async = true) - public SnapshotVO createSnapshot(Long volumeId, Long policyId, Long snapshotId) { - VolumeVO volume = _volsDao.findById(volumeId); - + public SnapshotVO createSnapshot(Long volumeId, Long policyId, Long snapshotId, Account snapshotOwner) { + VolumeVO volume = _volsDao.findById(volumeId); if (volume == null) { throw new InvalidParameterValueException("No such volume exist"); } - Account owner = _accountMgr.getAccount(volume.getAccountId()); SnapshotVO snapshot = null; boolean backedUp = false; - + UserVmVO uservm = null; // does the caller have the authority to act on this volume _accountMgr.checkAccess(UserContext.current().getCaller(), null, volume); try { - if (volume != null && _volsDao.getHypervisorType(volume.getId()).equals(HypervisorType.KVM)) { - /* KVM needs to lock on the vm of volume, because it takes snapshot on behalf of vm, not volume */ - UserVmVO uservm = _vmDao.findById(volume.getInstanceId()); - if (uservm != null) { - UserVmVO vm = _vmDao.acquireInLockTable(uservm.getId(), 10); - if (vm == null) { - throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " is being used, try it later "); - } - } - } + Long poolId = volume.getPoolId(); if (poolId == null) { throw new CloudRuntimeException("You cannot take a snapshot of a volume until it has been attached to an instance"); @@ -422,7 +409,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma + userVm.getState().toString() + " state"); } - if(userVm.getHypervisorType() == HypervisorType.VMware) { + if(userVm.getHypervisorType() == HypervisorType.VMware || userVm.getHypervisorType() == HypervisorType.KVM) { List activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.Status.Creating, Snapshot.Status.CreatedOnPrimary, Snapshot.Status.BackingUp); if(activeSnapshots.size() > 1) throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later"); @@ -432,6 +419,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma //when taking snapshot, make sure nobody can delete/move the volume boolean stateTransit = false; + /* try { stateTransit = _storageMgr.stateTransitTo(volume, Volume.Event.SnapshotRequested); } catch (NoTransitionException e) { @@ -441,7 +429,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma _snapshotDao.expunge(snapshotId); throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " is being used, try it later "); } - } + }*/ snapshot = createSnapshotOnPrimary(volume, policyId, snapshotId); if (snapshot != null) { @@ -479,7 +467,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma snapshot.setStatus(Status.Error); _snapshotDao.update(snapshot.getId(), snapshot); } else { - _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.snapshot); + _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot); } } else { snapshot = _snapshotDao.findById(snapshotId); @@ -489,11 +477,12 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } } + /* try { _storageMgr.stateTransitTo(volume, Volume.Event.OperationSucceeded); } catch (NoTransitionException e) { s_logger.debug("Failed to transit volume state: " + e.toString()); - } + }*/ } @@ -509,34 +498,6 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma return createdSnapshot; } - @Override - @DB - @SuppressWarnings("fallthrough") - public void validateSnapshot(Long userId, SnapshotVO snapshot) { - assert snapshot != null; - Long id = snapshot.getId(); - Status status = snapshot.getStatus(); - s_logger.debug("Snapshot scheduler found a snapshot whose actual status is not clear. Snapshot id:" + id + " with DB status: " + status); - - switch (status) { - case Creating: - // else continue to the next case. - case CreatedOnPrimary: - // The snapshot has been created on the primary and the DB has been updated. - // However, it hasn't entered the backupSnapshotToSecondaryStorage, else - // status would have been backing up. - // So call backupSnapshotToSecondaryStorage without any fear. - case BackingUp: - // It has entered backupSnapshotToSecondaryStorage. - // But we have no idea whether it was backed up or not. - // So call backupSnapshotToSecondaryStorage again. - backupSnapshotToSecondaryStorage(snapshot); - break; - case BackedUp: - // No need to do anything as snapshot has already been backed up. - } - } - @Override public void deleteSnapshotsForVolume (String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId ){ @@ -603,9 +564,6 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } - private SwiftTO toSwiftTO(SwiftVO swift) { - return new SwiftTO(swift.getId(), swift.getUrl(), swift.getAccount(), swift.getUserName(), swift.getKey()); - } @Override @DB @@ -682,7 +640,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma if (backedUp) { if (backupSnapshotCommand.getSwift() != null ) { - snapshot.setSwiftId(1L); + snapshot.setSwiftId(swift.getId()); snapshot.setBackupSnapshotId(backedUpSnapshotUuid); } else { snapshot.setSecHostId(secHost.getId()); @@ -1157,7 +1115,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma @Override @DB - public SnapshotPolicyVO createPolicy(CreateSnapshotPolicyCmd cmd) { + public SnapshotPolicyVO createPolicy(CreateSnapshotPolicyCmd cmd, Account policyOwner) { Long volumeId = cmd.getVolumeId(); VolumeVO volume = _volsDao.findById(cmd.getVolumeId()); if (volume == null) { @@ -1170,7 +1128,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot."); } - if ( volume.getTemplateId() != null ) { + if (volume.getTemplateId() != null ) { VMTemplateVO template = _templateDao.findById(volume.getTemplateId()); if( template != null && template.getTemplateType() == Storage.TemplateType.SYSTEM ) { throw new InvalidParameterValueException("VolumeId: " + volumeId + " is for System VM , Creating snapshot against System VM volumes is not supported"); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index d2920f12469..f7bb30be385 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -357,7 +357,37 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe } } - if (tmpltHostRef == null ) { + if (tmpltHostRef == null && _swiftMgr.isSwiftEnabled()) { + SwiftTO swift = _swiftMgr.getSwiftTO(templateId); + if (swift != null && sservers != null) { + for (HostVO secondaryStorageHost : sservers) { + downloadTemplateFromSwiftToSecondaryStorageCommand cmd = new downloadTemplateFromSwiftToSecondaryStorageCommand(swift, secondaryStorageHost.getName(), zoneId, + template.getAccountId(), templateId, _primaryStorageDownloadWait); + try { + Answer answer = _agentMgr.sendToSSVM(zoneId, cmd); + if (answer == null || !answer.getResult()) { + String errMsg = "Failed to download template from Swift to secondary storage due to " + (answer == null ? "answer is null" : answer.getDetails()); + s_logger.warn(errMsg); + throw new CloudRuntimeException(errMsg); + } + tmpltHostRef = _tmpltHostDao.findByHostTemplate(secondaryStorageHost.getId(), templateId); + if (tmpltHostRef != null) { + if (tmpltHostRef.getDownloadState() != com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { + tmpltHostRef = null; + } else { + break; + } + } + + } catch (Exception e) { + String errMsg = "Failed to download template from Swift to secondary storage due to " + e.toString(); + s_logger.warn(errMsg); + throw new CloudRuntimeException(errMsg); + } + } + } + } + if (tmpltHostRef == null) { throw new InvalidParameterValueException("The " + desc + " has not been downloaded "); } @@ -463,7 +493,12 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe downloadTemplateFromSwiftToSecondaryStorageCommand cmd = new downloadTemplateFromSwiftToSecondaryStorageCommand(swift, secHost.getName(), dcId, template.getAccountId(), templateId, _primaryStorageDownloadWait); try { - _agentMgr.sendToSSVM(dcId, cmd); + Answer answer = _agentMgr.sendToSSVM(dcId, cmd); + if (answer == null || !answer.getResult()) { + String errMsg = "Failed to download template from Swift to secondary storage due to " + (answer == null ? "answer is null" : answer.getDetails()); + s_logger.warn(errMsg); + throw new CloudRuntimeException(errMsg); + } } catch (Exception e) { String errMsg = "Failed to download template from Swift to secondary storage due to " + e.toString(); s_logger.warn(errMsg); diff --git a/server/src/com/cloud/test/DatabaseConfig.java b/server/src/com/cloud/test/DatabaseConfig.java index b3e8d6bf6a3..2e71c6fc287 100755 --- a/server/src/com/cloud/test/DatabaseConfig.java +++ b/server/src/com/cloud/test/DatabaseConfig.java @@ -57,7 +57,6 @@ import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.dao.DiskOfferingDaoImpl; import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.ComponentLocator; -import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.net.NfsUtils; @@ -534,16 +533,16 @@ public class DatabaseConfig { stmt.setLong(2, 1); stmt.setString(3, "mount.path"); if (nfs) { - stmt.setString(4, DBEncryptionUtil.encrypt(mountPoint)); + stmt.setString(4, mountPoint); } else { - stmt.setString(4, DBEncryptionUtil.encrypt(url.replaceFirst("file:/", ""))); + stmt.setString(4, url.replaceFirst("file:/", "")); } stmt.executeUpdate(); stmt.setLong(1, 3); stmt.setLong(2, 1); stmt.setString(3, "orig.url"); - stmt.setString(4, DBEncryptionUtil.encrypt(url)); + stmt.setString(4, url); stmt.executeUpdate(); stmt = txn.prepareAutoCloseStatement(insertSql2); diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java b/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java index 5edec7beee4..9b808fcdf54 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java @@ -324,7 +324,7 @@ public class Upgrade2214to30 implements DbUpgrade { PreparedStatement pstmt = null; ResultSet rs = null; try { - pstmt = conn.prepareStatement("select name, value from configuration"); + pstmt = conn.prepareStatement("select name, value from configuration where category = 'Hidden'"); rs = pstmt.executeQuery(); while (rs.next()) { String name = rs.getString(1); @@ -360,7 +360,7 @@ public class Upgrade2214to30 implements DbUpgrade { PreparedStatement pstmt = null; ResultSet rs = null; try { - pstmt = conn.prepareStatement("select id, value from host_details"); + pstmt = conn.prepareStatement("select id, value from host_details where name = 'password'"); rs = pstmt.executeQuery(); while (rs.next()) { long id = rs.getLong(1); diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index 978c938aaf1..589c33e7f86 100755 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -88,5 +88,7 @@ public interface AccountManager extends AccountService { Pair findUserByApiKey(String apiKey); boolean lockAccount(long accountId); + + boolean enableAccount(long accountId); } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 295b96eff19..0baa2cdd70a 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -83,6 +83,7 @@ import com.cloud.network.security.dao.SecurityGroupDao; import com.cloud.network.vpn.RemoteAccessVpnService; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; +import com.cloud.projects.dao.ProjectAccountDao; import com.cloud.projects.dao.ProjectDao; import com.cloud.server.auth.UserAuthenticator; import com.cloud.storage.StorageManager; @@ -194,6 +195,8 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag private AccountDetailsDao _accountDetailsDao; @Inject private DomainDao _domainDao; + @Inject + private ProjectAccountDao _projectAccountDao; private Adapters _userAuthenticators; @@ -376,6 +379,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag return _userDao.update(Long.valueOf(userId), userForUpdate); } + @Override public boolean enableAccount(long accountId) { boolean success = false; AccountVO acctForUpdate = _accountDao.createForUpdate(); @@ -962,6 +966,17 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag throw new PermissionDeniedException("Account id : " + accountId + " is a system account, delete is not allowed"); } + //Account that manages project(s) can't be removed + List managedProjectIds = _projectAccountDao.listAdministratedProjects(accountId); + if (!managedProjectIds.isEmpty()) { + StringBuilder projectIds = new StringBuilder(); + for (Long projectId : managedProjectIds) { + projectIds.append(projectId + ", "); + } + + throw new InvalidParameterValueException("The account id=" + accountId + " manages project(s) with ids " + projectIds + "and can't be removed"); + } + return deleteAccount(account, callerUserId, caller); } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 0fc1e529f1a..4c0eec9e61a 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -18,6 +18,7 @@ package com.cloud.vm; import java.util.ArrayList; +import com.cloud.network.rules.FirewallRule; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -135,10 +136,13 @@ import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.rules.FirewallManager; +import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.network.security.SecurityGroup; import com.cloud.network.security.SecurityGroupManager; +import com.cloud.network.security.SecurityGroupVMMapVO; import com.cloud.network.security.dao.SecurityGroupDao; +import com.cloud.network.security.dao.SecurityGroupVMMapDao; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offering.ServiceOffering; @@ -236,8 +240,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager @Inject protected HostDao _hostDao = null; @Inject - protected HostDetailsDao _detailsDao = null; - @Inject protected DomainRouterDao _routerDao = null; @Inject protected ServiceOfferingDao _offeringDao = null; @@ -359,6 +361,8 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager protected ResourceManager _resourceMgr; @Inject protected NetworkServiceMapDao _ntwkSrvcDao; + @Inject + SecurityGroupVMMapDao _securityGroupVMMapDao; protected ScheduledExecutorService _executor = null; protected int _expungeInterval; @@ -1287,19 +1291,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager @Override @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) - public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd) throws ResourceAllocationException { + public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { Long userId = UserContext.current().getCallerUserId(); Account caller = UserContext.current().getCaller(); - boolean isAdmin = ((caller == null) || isAdmin(caller.getType())); + boolean isAdmin = (isAdmin(caller.getType())); - VMTemplateVO privateTemplate = null; - - UserVO user = _userDao.findById(userId); - - if (user == null) { - throw new InvalidParameterValueException("User " + userId + " does not exist"); - } + _accountMgr.checkAccess(caller, null, templateOwner); String name = cmd.getTemplateName(); if ((name == null) || (name.length() > 32)) { @@ -1307,7 +1305,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } if(cmd.getTemplateTag() != null){ - if(!_accountService.isRootAdmin(caller.getType())){ + if (!_accountService.isRootAdmin(caller.getType())){ throw new PermissionDeniedException("Parameter templatetag can only be specified by a Root Admin, permission denied"); } } @@ -1338,10 +1336,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager throw new InvalidParameterValueException("Failed to create private template record, please specify only one of volume ID (" + volumeId + ") and snapshot ID (" + snapshotId + ")"); } - long domainId; - long accountId; HypervisorType hyperType; VolumeVO volume = null; + VMTemplateVO privateTemplate = null; if (volumeId != null) { // create template from volume volume = _volsDao.findById(volumeId); if (volume == null) { @@ -1359,17 +1356,15 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } throw new CloudRuntimeException(msg); } - domainId = volume.getDomainId(); - accountId = volume.getAccountId(); hyperType = _volsDao.getHypervisorType(volumeId); } else { // create template from snapshot SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - volume = _volsDao.findById(snapshot.getVolumeId()); - VolumeVO snapshotVolume = _volsDao.findByIdIncludingRemoved(snapshot.getVolumeId()); - if (snapshot == null) { throw new InvalidParameterValueException("Failed to create private template record, unable to find snapshot " + snapshotId); } + + volume = _volsDao.findById(snapshot.getVolumeId()); + VolumeVO snapshotVolume = _volsDao.findByIdIncludingRemoved(snapshot.getVolumeId()); //check permissions _accountMgr.checkAccess(caller, null, snapshot); @@ -1383,13 +1378,10 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager throw new UnsupportedServiceException("operation not supported, snapshot with id " + snapshotId + " is created from Data Disk"); } - domainId = snapshot.getDomainId(); - accountId = snapshot.getAccountId(); hyperType = snapshot.getHypervisorType(); } - AccountVO ownerAccount = _accountDao.findById(accountId); - _resourceLimitMgr.checkResourceLimit(ownerAccount, ResourceType.template); + _resourceLimitMgr.checkResourceLimit(templateOwner, ResourceType.template); if (!isAdmin || featured == null) { featured = Boolean.FALSE; @@ -1421,7 +1413,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager s_logger.debug("Adding template tag: "+templateTag); } } - privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, name, ImageFormat.RAW, isPublic, featured, isExtractable, TemplateType.USER, null, null, requiresHvmValue, bitsValue, accountId, + privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, name, ImageFormat.RAW, isPublic, featured, isExtractable, TemplateType.USER, null, null, requiresHvmValue, bitsValue, templateOwner.getId(), null, description, passwordEnabledValue, guestOS.getId(), true, hyperType, templateTag, cmd.getDetails()); if(sourceTemplateId != null){ if(s_logger.isDebugEnabled()){ @@ -1437,7 +1429,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager _templateDetailsDao.persist(template.getId(), cmd.getDetails()); } - _resourceLimitMgr.incrementResourceCount(accountId, ResourceType.template); + _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.template); } if (template != null){ @@ -2206,7 +2198,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager // Verify that caller can perform actions in behalf of vm owner _accountMgr.checkAccess(caller, null, owner); - + if (networkIdList == null || networkIdList.isEmpty()) { NetworkVO defaultNetwork = null; @@ -3349,7 +3341,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager Account oldAccount = _accountService.getActiveAccountById(vm.getAccountId()); if (oldAccount == null) { - throw new InvalidParameterValueException("Invalid account for VM " + vm.getAccountId() + " in domain " + oldAccount.getDomainId()); + throw new InvalidParameterValueException("Invalid account for VM " + vm.getAccountId() + " in domain."); } //don't allow to move the vm from the project if (oldAccount.getType() == Account.ACCOUNT_TYPE_PROJECT) { @@ -3364,7 +3356,35 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager throw new InvalidParameterValueException("The new account owner " + cmd.getAccountName() + " is disabled."); } - //don't allow to move the vm if it's assigned to Isolated + // don't allow to move the vm if there are existing PF/LB/Static Nat rules, existing Security groups or vm is assigned to static Nat ip + IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(cmd.getVmId()); + if (ip != null){ + List firewall_rules = _rulesDao.listByIpAndPurposeAndNotRevoked(ip.getId(), FirewallRule.Purpose.Firewall); + if (firewall_rules.size() > 0){ + throw new InvalidParameterValueException("Remove the Firewall rules for this VM before assigning to another user."); + } + List lb_rules = _rulesDao.listByIpAndPurposeAndNotRevoked(ip.getId(), FirewallRule.Purpose.LoadBalancing); + if (lb_rules.size() > 0){ + throw new InvalidParameterValueException("Remove the LoadBalancing rules for this VM before assigning to another user."); + } + List nat_rules = _rulesDao.listByIpAndPurposeAndNotRevoked(ip.getId(), FirewallRule.Purpose.StaticNat); + if (nat_rules.size() > 0){ + throw new InvalidParameterValueException("Remove the StaticNat rules for this VM before assigning to another user."); + } + List vpn_rules = _rulesDao.listByIpAndPurposeAndNotRevoked(ip.getId(), FirewallRule.Purpose.Vpn); + if (vpn_rules.size() > 0){ + throw new InvalidParameterValueException("Remove the Vpn rules for this VM before assigning to another user."); + } + List securityGroupsToVmMap = _securityGroupVMMapDao.listByInstanceId(cmd.getVmId()); + if (securityGroupsToVmMap.size() > 0){ + throw new InvalidParameterValueException("Remove the VM from security groups before assigning to another user."); + } + } + + DataCenterVO zone = _dcDao.findById(vm.getDataCenterIdToDeployIn()); + + //Remove vm from instance group + removeInstanceFromInstanceGroup(cmd.getVmId()); //VV 2: check if account/domain is with in resource limits to create a new vm _resourceLimitMgr.checkResourceLimit(newAccount, ResourceType.user_vm); @@ -3380,12 +3400,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager DomainVO domain = _domainDao.findById(cmd.getDomainId()); _accountMgr.checkAccess(newAccount, domain); - DataCenterVO zone = _dcDao.findById(vm.getDataCenterIdToDeployIn()); - - //check is zone networking is advanced - //if (zone.getNetworkType() != NetworkType.Advanced) { - // throw new InvalidParameterValueException("Assing virtual machine to another account is only available for advanced networking " + vm); - //} VMInstanceVO vmoi = _itMgr.findByIdAndType(vm.getType(), vm.getId()); VirtualMachineProfileImpl vmOldProfile = new VirtualMachineProfileImpl(vmoi); @@ -3400,14 +3414,17 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager // OWNERSHIP STEP 1: update the vm owner vm.setAccountId(newAccount.getAccountId()); + vm.setDomainId(cmd.getDomainId()); _vmDao.persist(vm); // OS 2: update volume List volumes = _volsDao.findByInstance(cmd.getVmId()); for (VolumeVO volume : volumes) { + _usageEventDao.persist(new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName())); _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.volume, Long.valueOf(volumes.size())); volume.setAccountId(newAccount.getAccountId()); _volsDao.persist(volume); _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.volume, Long.valueOf(volumes.size())); + _usageEventDao.persist(new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName())); } _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.user_vm); @@ -3418,57 +3435,100 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager txn.commit(); // OS 3: update the network - if (zone.getNetworkType() == NetworkType.Advanced) { - //cleanup the network for the oldOwner - _networkMgr.cleanupNics(vmOldProfile); - _networkMgr.expungeNics(vmOldProfile); + List networkIdList = cmd.getNetworkIds(); + if (zone.getNetworkType() == NetworkType.Basic) { + //security groups will be recreated for the new account, when the VM is started + } else { + if (zone.isSecurityGroupEnabled()) { + throw new InvalidParameterValueException("not yet tested for SecurityGroupEnabled advanced networks."); + } else { + //cleanup the network for the oldOwner + _networkMgr.cleanupNics(vmOldProfile); + _networkMgr.expungeNics(vmOldProfile); + + // add the new nics + List networkList = new ArrayList(); + NetworkVO defaultNetwork = null; - // add the new nics - List networkList = new ArrayList(); - NetworkVO defaultNetwork = null; - - List oldNetworks = new ArrayList(); - List zoneNetworks = _networkDao.listByZone(zone.getId()); - - for (NetworkVO network : zoneNetworks) { // get the default networks for the account - NetworkOfferingVO no = _networkOfferingDao.findById(network.getNetworkOfferingId()); - if (!no.isSystemOnly()) { - if (network.getGuestType() == Network.GuestType.Shared || !_networkDao.listBy(oldAccount.getId(), network.getId()).isEmpty()) { - oldNetworks.add(network); + List applicableNetworks = new ArrayList(); + // create the default network + List zoneNetworks = _networkDao.listByZone(zone.getId()); // get the default networks for the account + for (NetworkVO network : zoneNetworks) { + NetworkOfferingVO no = _networkOfferingDao.findById(network.getNetworkOfferingId()); + if (!no.isSystemOnly()) { + if (network.getGuestType() == Network.GuestType.Shared || !_networkDao.listBy(oldAccount.getId(), network.getId()).isEmpty()) { + applicableNetworks.add(network); + } } } - } - for (NetworkVO oldNet: oldNetworks){ - long networkOffering = oldNet.getNetworkOfferingId(); - PhysicalNetwork physicalNetwork = _networkMgr.translateZoneIdToPhysicalNetwork(zone.getId()); - List virtualNetworks = _networkMgr.listNetworksForAccount(newAccount.getId(), zone.getId(), Network.GuestType.Isolated); - if (virtualNetworks.isEmpty()) { - Network newNetwork = _networkMgr.createGuestNetwork(networkOffering, newAccount.getAccountName() + "-network", newAccount.getAccountName() + "-network", null, null, - null, null, newAccount, false, null, physicalNetwork, zone.getId(), ACLType.Account, null); - defaultNetwork = _networkDao.findById(newNetwork.getId()); - } else if (virtualNetworks.size() > 1) { - throw new InvalidParameterValueException("More than 1 default Virtaul networks are found for account " + newAccount + "; please specify networkIds"); - } else { - defaultNetwork = virtualNetworks.get(0); + if (networkIdList != null && !networkIdList.isEmpty()){ + // add any additional networks + for (Long networkId : networkIdList) { + NetworkVO network = _networkDao.findById(networkId); + if (network == null) { + throw new InvalidParameterValueException("Unable to find network by id " + networkIdList.get(0).longValue()); + } + + // Perform account permission check + if (network.getGuestType() != Network.GuestType.Shared) { + List networkMap = _networkDao.listBy(newAccount.getId(), network.getId()); + if (networkMap == null || networkMap.isEmpty()) { + throw new PermissionDeniedException("Unable to create a vm using network with id " + network.getId() + ", permission denied"); + } + } else { + if (!_networkMgr.isNetworkAvailableInDomain(networkId, newAccount.getDomainId())) { + throw new PermissionDeniedException("Shared network id=" + networkId + " is not available in domain id=" + newAccount.getDomainId()); + } + } + + //don't allow to use system networks + NetworkOffering networkOffering = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); + if (networkOffering.isSystemOnly()) { + throw new InvalidParameterValueException("Network id=" + networkId + " is system only and can't be used for vm deployment"); + } + applicableNetworks.add(network); + } } - - networkList.add(defaultNetwork); - List> networks = new ArrayList>(); - for (NetworkVO network : networkList) { - networks.add(new Pair(network, null)); + for (NetworkVO appNet: applicableNetworks){ + long networkOffering = appNet.getNetworkOfferingId(); + PhysicalNetwork physicalNetwork = _networkMgr.translateZoneIdToPhysicalNetwork(zone.getId()); + List virtualNetworks = _networkMgr.listNetworksForAccount(newAccount.getId(), zone.getId(), Network.GuestType.Isolated); + if (virtualNetworks.isEmpty()) { + s_logger.debug("Creating network for account " + newAccount + " as a part of assignVM process"); + Network newNetwork = _networkMgr.createGuestNetwork(networkOffering, newAccount.getAccountName() + "-network", newAccount.getAccountName() + "-network", null, null, + null, null, newAccount, false, null, physicalNetwork, zone.getId(), ACLType.Account, null); + defaultNetwork = _networkDao.findById(newNetwork.getId()); + } else if (virtualNetworks.size() > 1) { + throw new InvalidParameterValueException("More than 1 default Virtaul networks are found for account " + newAccount + "; please specify networkIds"); + } else { + defaultNetwork = virtualNetworks.get(0); + } + + networkList.add(defaultNetwork); + + List> networks = new ArrayList>(); + int toggle=0; + for (NetworkVO network : networkList) { + NicProfile defaultNic = new NicProfile(); + if (toggle==0){ + defaultNic.setDefaultNic(true); + toggle++; + } + networks.add(new Pair(network, defaultNic)); + } + + VMInstanceVO vmi = _itMgr.findByIdAndType(vm.getType(), vm.getId()); + VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmi); + _networkMgr.allocate(vmProfile, networks); } - - VMInstanceVO vmi = _itMgr.findByIdAndType(vm.getType(), vm.getId()); - VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmi); - _networkMgr.allocate(vmProfile, networks); - } - } - + } //END IF NON SEC GRP ENABLED + } // END IF ADVANCED return vm; } + @Override public UserVm restoreVM(RestoreVMCmd cmd) { // Input validation diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 26cbb48ad9a..fd0533c970c 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -825,7 +825,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene } } catch (Exception e) { s_logger.error("Failed to start instance " + vm, e); - throw new AgentUnavailableException("Unable to start instance", destHostId, e); + throw new AgentUnavailableException("Unable to start instance due to " + e.getMessage(), destHostId, e); } finally { if (startedVm == null && canRetry) { _workDao.updateStep(work, Step.Release); diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index 8f411249041..f38f2a0d51a 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -260,7 +260,7 @@ public class MockUserVmManagerImpl implements UserVmManager, UserVmService, Mana } @Override - public VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd) throws ResourceAllocationException { + public VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { // TODO Auto-generated method stub return null; } diff --git a/setup/db/create-schema-simulator.sql b/setup/db/create-schema-simulator.sql index 8c01a025e4a..ac8f319c36d 100644 --- a/setup/db/create-schema-simulator.sql +++ b/setup/db/create-schema-simulator.sql @@ -103,7 +103,3 @@ CREATE TABLE `cloud`.`mocksecurityrules` ( INDEX `i_mocksecurityrules__vmid`(`vmid`), INDEX `i_mocksecurityrules__hostid`(`hostid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - --- Some alterations reqd for the simulator to work with a regular DB -ALTER TABLE `cloud`.`physical_network_traffic_types` ADD COLUMN `simulator_network_label` varchar(255) COMMENT 'The name labels needed for identifying the simulator' diff --git a/setup/db/db/schema-21to22.sql b/setup/db/db/schema-21to22.sql index 5d69f487bcd..0abe6473bd9 100755 --- a/setup/db/db/schema-21to22.sql +++ b/setup/db/db/schema-21to22.sql @@ -668,7 +668,7 @@ INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (127, 10, INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (128, 10, 'Ubuntu 9.04 (64-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (129, 10, 'Ubuntu 8.10 (64-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (130, 10, 'Ubuntu 8.04 (64-bit)'); -INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (131, 10, 'Red Hat Enterprise Linux 2'); +INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (131, 4, 'Red Hat Enterprise Linux 2'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (132, 2, 'Debian GNU/Linux 6(32-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (133, 2, 'Debian GNU/Linux 6(64-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (134, 3, 'Oracle Enterprise Linux 5.5 (32-bit)'); diff --git a/setup/db/db/schema-2214to30.sql b/setup/db/db/schema-2214to30.sql index 6ea206197c5..56178f103c2 100755 --- a/setup/db/db/schema-2214to30.sql +++ b/setup/db/db/schema-2214to30.sql @@ -496,3 +496,5 @@ CREATE TABLE `cloud`.`op_user_stats_log` ( `updated` datetime COMMENT 'stats update timestamp', UNIQUE KEY (`user_stats_id`, `updated`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud`.`physical_network_traffic_types` ADD COLUMN `simulator_network_label` varchar(255) COMMENT 'The name labels needed for identifying the simulator'; diff --git a/setup/db/templates.simulator.sql b/setup/db/templates.simulator.sql index a318bf5349f..7542cf9821b 100755 --- a/setup/db/templates.simulator.sql +++ b/setup/db/templates.simulator.sql @@ -161,7 +161,7 @@ INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (127, 10, INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (128, 10, 'Ubuntu 9.04 (64-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (129, 10, 'Ubuntu 8.10 (64-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (130, 10, 'Ubuntu 8.04 (64-bit)'); -INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (131, 10, 'Red Hat Enterprise Linux 2'); +INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (131, 4, 'Red Hat Enterprise Linux 2'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (132, 2, 'Debian GNU/Linux 6(32-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (133, 2, 'Debian GNU/Linux 6(64-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (134, 3, 'Oracle Enterprise Linux 5.5 (32-bit)'); diff --git a/setup/db/templates.sql b/setup/db/templates.sql index 399a3550165..f1e81fcad5e 100755 --- a/setup/db/templates.sql +++ b/setup/db/templates.sql @@ -159,7 +159,7 @@ INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (127, 10, INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (128, 10, 'Ubuntu 9.04 (64-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (129, 10, 'Ubuntu 8.10 (64-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (130, 10, 'Ubuntu 8.04 (64-bit)'); -INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (131, 10, 'Red Hat Enterprise Linux 2'); +INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (131, 4, 'Red Hat Enterprise Linux 2'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (132, 2, 'Debian GNU/Linux 6(32-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (133, 2, 'Debian GNU/Linux 6(64-bit)'); INSERT INTO `cloud`.`guest_os` (id, category_id, display_name) VALUES (134, 3, 'Oracle Enterprise Linux 5.5 (32-bit)'); diff --git a/tools/testClient/deployDataCenter.py b/tools/testClient/deployDataCenter.py index 470b59aaee8..b8f4fafa24c 100644 --- a/tools/testClient/deployDataCenter.py +++ b/tools/testClient/deployDataCenter.py @@ -142,6 +142,8 @@ class deployDataCenters(): self.createVlanIpRanges("Advanced", ipranges, zoneId, networkId=networkId) def configureProviders(self, providers, zoneid, networktype): + if providers == None: + return for prov in providers: pnets = listPhysicalNetworks.listPhysicalNetworksCmd() pnets.zoneid = zoneid diff --git a/tools/testClient/sandbox/advanced/xen.properties b/tools/testClient/sandbox/advanced/xen.properties index 4d44e07e067..90c2f710fe3 100644 --- a/tools/testClient/sandbox/advanced/xen.properties +++ b/tools/testClient/sandbox/advanced/xen.properties @@ -15,22 +15,22 @@ check.pod.cidrs=true secstorage.allowed.internal.sites=10.147.28.0/24 [environment] dns=10.147.28.6 -mshost=localhost +mshost=10.147.29.110 database=localhost hypervisor=XenServer [cloudstack] -guest.vlan=675-679 +guest.vlan=670-674 #pod configuration private.gateway=10.147.29.1 -private.pod.startip=10.147.29.150 -private.pod.endip=10.147.29.159 +private.pod.startip=10.147.29.140 +private.pod.endip=10.147.29.149 #public vlan range public.gateway=10.147.31.1 public.vlan=31 -public.vlan.startip=10.147.31.150 -public.vlan.endip=10.147.31.159 +public.vlan.startip=10.147.31.140 +public.vlan.endip=10.147.31.149 #hosts -host=10.147.29.57 +host=10.147.29.56 #pools -pool=nfs://10.147.28.6:/export/home/prasanna/budhgaya -secondary=nfs://10.147.28.6:/export/home/prasanna/sstor +pool=nfs://10.147.28.6:/export/home/prasanna/taxila +secondary=nfs://10.147.28.6:/export/home/prasanna/secondary diff --git a/tools/testClient/sandbox/simulator/setup.py b/tools/testClient/sandbox/simulator/setup.py index 194e8f716ea..3dda7d62a3b 100644 --- a/tools/testClient/sandbox/simulator/setup.py +++ b/tools/testClient/sandbox/simulator/setup.py @@ -8,106 +8,87 @@ ############################################################ ''' +from ConfigParser import SafeConfigParser from optparse import OptionParser from configGenerator import * import random -def getGlobalSettings(): - global_settings = {'expunge.delay': '60', - 'expunge.interval': '60', - 'expunge.workers': '3', - 'workers': '10', - 'use.user.concentrated.pod.allocation': 'false', - 'vm.allocation.algorithm': 'random', - 'vm.op.wait.interval': '5', - 'guest.domain.suffix': 'sandbox.simulator', - 'instance.name': 'SIMQA', - 'direct.agent.load.size': '1000', - 'default.page.size': '10000', - 'linkLocalIp.nums': '10', - 'check.pod.cidrs': 'false', - } - for k, v in global_settings.iteritems(): +def getGlobalSettings(config): + for k, v in dict(config.items('globals')).iteritems(): cfg = configuration() cfg.name = k cfg.value = v yield cfg -def describeResources(dbnode='localhost', mshost='localhost'): +def describeResources(config): zs = cloudstackConfiguration() - numberofpods = 1 - - clustersPerPod = 10 - hostsPerCluster = 2 z = zone() - z.dns1 = '4.2.2.2' - z.dns2 = '10.223.110.254' - z.internaldns1 = '10.147.28.6' - z.internaldns2 = '10.223.110.254' - z.name = 'Sandbox-Simulator' + z.dns1 = config.get('environment', 'dns') + z.internaldns1 = config.get('environment', 'dns') + z.name = 'Sandbox-%s'%(config.get('environment', 'hypervisor')) z.networktype = 'Advanced' z.guestcidraddress = '10.1.1.0/24' - z.vlan='100-300' + + prov = provider() + prov.vlan = config.get('cloudstack','guest.vlan') + z.providers.append(prov) p = pod() p.name = 'POD0' - p.gateway = '172.1.1.1' - p.startip = '172.1.1.2' - p.endip = '172.1.1.200' + p.gateway = config.get('cloudstack', 'private.gateway') + p.startip = config.get('cloudstack', 'private.pod.startip') + p.endip = config.get('cloudstack', 'private.pod.endip') p.netmask = '255.255.255.0' v = iprange() - v.vlan = '30' - v.gateway = '172.1.2.1' - v.startip = '172.1.2.2' - v.endip = '172.1.2.200' + v.gateway = config.get('cloudstack', 'public.gateway') + v.startip = config.get('cloudstack', 'public.vlan.startip') + v.endip = config.get('cloudstack', 'public.vlan.endip') v.netmask = '255.255.255.0' + v.vlan = config.get('cloudstack', 'public.vlan') + z.ipranges.append(v) - curhost = 1 - for i in range(1, clustersPerPod + 1): - c = cluster() - c.clustername = 'POD1-CLUSTER' + str(i) - c.hypervisor = 'Simulator' - c.clustertype = 'CloudManaged' + c = cluster() + c.clustername = 'C0' + c.hypervisor = config.get('environment', 'hypervisor') + c.clustertype = 'CloudManaged' - for j in range(1, hostsPerCluster + 1): - h = host() - h.username = 'root' - h.password = 'password' - h.url = 'http://sim/test-%d'%(curhost) - c.hosts.append(h) - curhost = curhost + 1 + h = host() + h.username = 'root' + h.password = 'password' + h.url = 'http://%s'%(config.get('cloudstack', 'host')) + c.hosts.append(h) - ps = primaryStorage() - ps.name = 'spool'+str(i) - ps.url = 'nfs://172.16.24.32/export/path/'+str(i) - c.primaryStorages.append(ps) - p.clusters.append(c) + ps = primaryStorage() + ps.name = 'PS0' + ps.url = config.get('cloudstack', 'pool') + c.primaryStorages.append(ps) + p.clusters.append(c) + z.pods.append(p) secondary = secondaryStorage() - secondary.url = 'nfs://172.16.25.32/secondary/path' - - z.pods.append(p) - z.ipranges.append(v) + secondary.url = config.get('cloudstack', 'secondary') z.secondaryStorages.append(secondary) + + '''Add zone''' zs.zones.append(z) '''Add mgt server''' mgt = managementServer() - mgt.mgtSvrIp = mshost + mgt.mgtSvrIp = config.get('environment', 'mshost') zs.mgtSvr.append(mgt) '''Add a database''' db = dbServer() - db.dbSvr = opts.dbnode + db.dbSvr = config.get('environment', 'database') zs.dbSvr = db '''Add some configuration''' - [zs.globalConfig.append(cfg) for cfg in getGlobalSettings()] + [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)] ''''add loggers''' testClientLogger = logger() @@ -125,10 +106,16 @@ def describeResources(dbnode='localhost', mshost='localhost'): if __name__ == '__main__': parser = OptionParser() - parser.add_option('-o', '--output', action='store', default='./sandbox.cfg', dest='output', help='the path where the json config file generated') - parser.add_option('-d', '--dbnode', dest='dbnode', help='hostname/ip of the database node', action='store') - parser.add_option('-m', '--mshost', dest='mshost', help='hostname/ip of management server', action='store') + parser.add_option('-i', '--input', action='store', default='setup.properties', \ + dest='input', help='file containing environment setup information') + parser.add_option('-o', '--output', action='store', default='./sandbox.cfg', \ + dest='output', help='path where environment json will be generated') + (opts, args) = parser.parse_args() - cfg = describeResources(opts.dbnode, opts.mshost) + + cfg_parser = SafeConfigParser() + cfg_parser.read(opts.input) + + cfg = describeResources(cfg_parser) generate_setup_config(cfg, opts.output) diff --git a/tools/testClient/sandbox/simulator/tests/testProvision.py b/tools/testClient/sandbox/simulator/tests/testProvision.py index 5388d1041ec..ebaf6eee176 100644 --- a/tools/testClient/sandbox/simulator/tests/testProvision.py +++ b/tools/testClient/sandbox/simulator/tests/testProvision.py @@ -1,9 +1,4 @@ #!/usr/bin/env python -try: - import unittest2 as unittest -except ImportError: - import unittest - import random import hashlib from cloudstackTestCase import * diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 156746c1bc2..9ca983990a3 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -6666,6 +6666,70 @@ div.panel.ui-dialog div.list-view div.fixed-header { left: 0; } +/*** Resource management*/ +.project-dashboard .resources { +} + +.project-dashboard .resources form { + background: #FFFFFF; + width: 87%; + /*+border-radius:11px;*/ + -moz-border-radius: 11px; + -webkit-border-radius: 11px; + -khtml-border-radius: 11px; + border-radius: 11px 11px 11px 11px; + padding: 26px; + margin-top: 17px; + margin-left: 22px; + /*+box-shadow:inset 0px 3px 4px #979797;*/ + -moz-box-shadow: inset 0px 3px 4px #979797; + -webkit-box-shadow: inset 0px 3px 4px #979797; + -o-box-shadow: inset 0px 3px 4px #979797; + box-shadow: inset 0px 3px 4px #979797; + display: inline-block; +} + +.project-dashboard .resources form .field { + width: 100%; + float: left; + clear: both; + margin: auto auto 30px; +} + +.project-dashboard .resources form label { + float: left; +} + +.project-dashboard .resources form input[type=text] { + float: right; + width: 176px; + font-size: 16px; + margin: 0 287px 0 0; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px 4px 4px 4px; + border: 1px solid #C6C6C6; + padding: 6px; +} + +.project-dashboard .resources form input[type=submit] { + display: block; + border: none; + background: transparent url(../images/bg-gradients.png) 0px -220px; + float: left; + padding: 9px 20px; + cursor: pointer; + color: #FFFFFF; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px 4px 4px 4px; + clear: both; +} + /*** Dashboard*/ .project-dashboard .toolbar { position: relative; @@ -6837,6 +6901,8 @@ div.panel.ui-dialog div.list-view div.fixed-header { .info-boxes .info-box.events { margin-top: 4px; + min-height: 100px; + width: 228px; } .info-boxes .info-box.events ul { @@ -6854,7 +6920,7 @@ div.panel.ui-dialog div.list-view div.fixed-header { .info-boxes .info-box ul li { width: 224px; margin: 0 2px 0 0; - height: 36px; + display: inline-block; border-bottom: 1px solid #BDD2DF; border-top: 1px solid #FFFFFF; } @@ -6895,6 +6961,7 @@ div.panel.ui-dialog div.list-view div.fixed-header { position: relative; left: 0px; top: 2px; + float: left; } .info-boxes .info-box .title .button { diff --git a/ui/images/bg-breadcrumb.png b/ui/images/bg-breadcrumb.png index 796b5982a9e..82d632771a8 100644 Binary files a/ui/images/bg-breadcrumb.png and b/ui/images/bg-breadcrumb.png differ diff --git a/ui/images/bg-breadcrumbs.png b/ui/images/bg-breadcrumbs.png index c6ea1fe7d29..c1d1416fcb1 100644 Binary files a/ui/images/bg-breadcrumbs.png and b/ui/images/bg-breadcrumbs.png differ diff --git a/ui/images/bg-nav-item-active.png b/ui/images/bg-nav-item-active.png index 811c24adb89..8b7ff59e6db 100644 Binary files a/ui/images/bg-nav-item-active.png and b/ui/images/bg-nav-item-active.png differ diff --git a/ui/images/bg-nav-item.png b/ui/images/bg-nav-item.png index 46ee8ef6333..3d49df72229 100644 Binary files a/ui/images/bg-nav-item.png and b/ui/images/bg-nav-item.png differ diff --git a/ui/images/buttons.png b/ui/images/buttons.png index d422012e012..7e31acb7d05 100644 Binary files a/ui/images/buttons.png and b/ui/images/buttons.png differ diff --git a/ui/images/gradients.png b/ui/images/gradients.png index 8d1de9d0f39..d6b9488c6f6 100644 Binary files a/ui/images/gradients.png and b/ui/images/gradients.png differ diff --git a/ui/index-test.html b/ui/index-test.html index 6f3219b9a72..8f90da40ceb 100644 --- a/ui/index-test.html +++ b/ui/index-test.html @@ -1,5 +1,5 @@ +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> CloudStack @@ -433,22 +433,6 @@
Choose this network model if you wish to enable VLAN support. This network model provides the most flexibility in allowing administrators to provide custom network offerings such as providing firewall, vpn, or load balancer support as well as enabling direct vs virtual networking.
- -
-

Isolation mode

-
- - -
Choose this if you wish to use zone-wide VLANs to provide guest VM isolation.
-
-
- - -
Choose this if you wish to use security groups to provide guest VM isolation.
-
-
@@ -544,13 +528,22 @@
+ +
+
+ Enable security groups +
+
+ +
+
Network Offering
- +
@@ -571,7 +564,7 @@ Name
- +
@@ -581,7 +574,7 @@ Gateway
- +
@@ -591,7 +584,7 @@ Netmask
- +
@@ -601,9 +594,9 @@ Reserved IP
- + - - +
diff --git a/ui/index.jsp b/ui/index.jsp index 359c63d9ca9..eb809e126cd 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -433,22 +433,6 @@
Choose this network model if you wish to enable VLAN support. This network model provides the most flexibility in allowing administrators to provide custom network offerings such as providing firewall, vpn, or load balancer support as well as enabling direct vs virtual networking.
- -
-

Isolation mode

-
- - -
Choose this if you wish to use zone-wide VLANs to provide guest VM isolation.
-
-
- - -
Choose this if you wish to use security groups to provide guest VM isolation.
-
-
@@ -544,6 +528,15 @@
+ +
+
+ Enable security groups +
+
+ +
+
@@ -779,13 +772,13 @@
-
12
+
5
Running
-
2
+
10
Stopped
@@ -796,27 +789,18 @@ Storage
-
171
-
GB/mo
+
10
+
volumes
-
  • +
  • Bandwidth
    - -
    -
    2.3
    -
    In GB
    -
    - - -
    -
    1.5
    -
    Out GB
    -
    +
    200
    +
    mb/s
  • @@ -829,47 +813,9 @@
    Users
    -
      +
      • - Will -
        -
      • - -
      • - Brian -
        -
      • - -
      • - Sonny -
        -
      • -
      • - Will -
        -
      • - -
      • - Brian -
        -
      • - -
      • - Sonny -
        -
      • -
      • - Will -
        -
      • - -
      • - Brian -
        -
      • - -
      • - Sonny +
      @@ -886,20 +832,20 @@
      • -
        171
        +
        IP addresses
      • -
        04
        +
        Load balancing policies
      • - +
      • -
        23
        -
        Security groups
        +
        +
        Port forwarding policies
      • @@ -930,50 +876,10 @@
    -
      +
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        -
      • -
      • -
        12/01
        -
        Event
        +
        +
    diff --git a/ui/scripts-test/installWizard.js b/ui/scripts-test/installWizard.js index 3f4c9342560..7a2b6a13e1f 100644 --- a/ui/scripts-test/installWizard.js +++ b/ui/scripts-test/installWizard.js @@ -218,7 +218,9 @@ action: function(args) { var complete = args.response.success; + var error = args.response.error; var message = args.response.message; + var startFn = args.startFn; var createZone = function(args) { message('Creating zone'); @@ -245,6 +247,7 @@ message('Creating cluster'); setTimeout(function() { createHost(); + //error('addCluster', 'Could not create cluster.', createPod); }, 500); }; @@ -274,7 +277,11 @@ setTimeout(complete, 5000); }; - createZone(); + if (startFn) { + startFn(); + } else { + createZone(); + } } }; }(jQuery, cloudStack, testData)); diff --git a/ui/scripts-test/network.js b/ui/scripts-test/network.js index 9beeed1cda5..7613713f843 100644 --- a/ui/scripts-test/network.js +++ b/ui/scripts-test/network.js @@ -402,7 +402,7 @@ staticNATDataProvider: function(args) { args.response.success({ - data: testData.data.ipAddresses[0] + data: testData.data.networks[0] }); }, @@ -667,7 +667,7 @@ vpn: { title: 'VPN', custom: function(args) { - var ipAddress = args.context.ipAddresses[0].ipaddress; + var ipAddress = args.context.networks[0].ipaddress; var psk = '081XufGFmEDBAEfsfdXTNpramSZ'; return $('
    ').append( diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index 4cb45d8e2dc..09df9ba26c0 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -37,7 +37,9 @@ /** * Generic error handling */ + $.ajaxSetup({ + url: clientApiUrl, async: true, dataType: 'json', cache: false, @@ -161,8 +163,8 @@ } $.ajax({ - //type: "POST", - url: createURL("login") + array1.join(""), + type: "POST", + data: "command=login" + array1.join("") + "&response=json", dataType: "json", async: false, success: function(json) { diff --git a/ui/scripts/installWizard.js b/ui/scripts/installWizard.js index f995c258774..d844c72a874 100644 --- a/ui/scripts/installWizard.js +++ b/ui/scripts/installWizard.js @@ -230,8 +230,10 @@ action: function(args) { var complete = args.response.success; + var error = args.response.error; var message = args.response.message; var data = args.data; + var startFn = args.startFn; var createZone = function(args) { message('Creating zone'); @@ -388,10 +390,7 @@ args.complete({ data: { zone: zoneObj } }); } }, - error: function(XMLHttpResponse) { - var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - alert("updateNetworkServiceProvider failed. Error: " + errorMsg); - } + error: args.error }); }); } @@ -402,13 +401,12 @@ } } }, - error: function(XMLHttpResponse) { - var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - alert("configureVirtualRouterElement failed. Error: " + errorMsg); - } + error: args.error }); }); - } + }, + + error: args.error }); } else if (result.jobstatus == 2) { @@ -416,24 +414,21 @@ } } }, - error: function(XMLHttpResponse) { - var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - alert("updatePhysicalNetwork failed. Error: " + errorMsg); - } + error: args.error }); }); } }); //NaaS (end) }, - error: function(XMLHttpResponse) { - var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - args.response.error(errorMsg); - } + error: args.error }); }; - addZoneAction({ data: data.zone, complete: createPod }); + addZoneAction({ data: data.zone, complete: createPod, error: function(json) { + debugger; + error('addZone', parseXMLHttpResponse(json), createZone); + } }); }; var createPod = function(args) { @@ -458,7 +453,7 @@ }, error: function(XMLHttpResponse) { var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - args.response.error(errorMsg); + error(errorMsg); } }); }; @@ -571,17 +566,19 @@ success: function(json) { //var item = json.createvlaniprangeresponse.vlan; }, - error: function(XMLHttpResponse) { - //var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - //args.response.error(errorMsg); + error: function(json) { + error('addNetwork', parseXMLHttpResponse(json), function() { + createNetwork(args); + }); } }); } }, - error: function(XMLHttpResponse) { - var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - args.response.error(errorMsg); + error: function(json) { + error('addNetwork', parseXMLHttpResponse(json), function() { + createNetwork(args); + }); } }); }; @@ -602,6 +599,11 @@ response: { success: function(successArgs) { createCluster({ data: $.extend(args.data, { guestNetwork: successArgs.data })}); + }, + error: function(json) { + error('addNetwork', parseXMLHttpResponse(json), function() { + createNetwork(args); + }); } }, data: { @@ -615,7 +617,7 @@ networkOfferingId: networkOfferingID } }); - } + } }); }; @@ -638,6 +640,11 @@ cluster: data.addclusterresponse.cluster[0] }) }); + }, + error: function(json) { + error('addCluster', parseXMLHttpResponse(json), function() { + createCluster(args); + }); } }); }; @@ -664,6 +671,11 @@ host: data.addhostresponse.host[0] }) }); + }, + error: function(json) { + error('addHost', parseXMLHttpResponse(json), function() { + createHost(args); + }); } }); }; @@ -734,7 +746,11 @@ }, 5000); }; - createZone(); + if (startFn) { + startFn(); + } else { + createZone(); + } } }; }(jQuery, cloudStack, testData)); diff --git a/ui/scripts/network.js b/ui/scripts/network.js index d1c4e60802b..8cd5606ad82 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -86,8 +86,8 @@ name: { label: 'Name' }, zonename: { label: 'Zone' }, type: { label: 'Type' }, - traffictype: { label: 'Traffic Type' }, - gateway: { label: 'Gateway' }, + vlan: { label: 'VLAN' }, + cidr: { label: 'CIDR' }, state: { label: 'State', indicator: { 'Implemented': 'on', 'Setup': 'on' } } }, dataProvider: function(args) { @@ -114,6 +114,33 @@ detailView: { name: 'Network details', viewAll: { path: 'network.ipAddresses', label: 'Associated IP Addresses' }, + actions: { + edit: { + label: 'Edit network', + messages: { + notification: function() { return 'Updated network'; } + }, + action: function(args) { + $.ajax({ + url: createURL('updateNetwork'), + data: $.extend(args.data, { + id: args.context.networks[0].id + }), + success: function(json) { + args.response.success({ + _custom: { + jobId: json.updatenetworkresponse.jobid + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { poll: pollAsyncJobResult } + } + }, tabs: { details: { title: 'Details', @@ -125,7 +152,37 @@ type: { label: 'Type' }, displaytext: { label: 'Description' }, traffictype: { label: 'Traffic Type' }, - gateway: { label: 'Gateway' } + gateway: { label: 'Gateway' }, + networkofferingid: { + label: 'Network Offering', + isEditable: true, + select: function(args) { + $.ajax({ + url: createURL('listNetworkOfferings'), + data: { + state: 'enabled', + traffictype: args.context.networks[0].traffictype, + guestiptype: args.context.networks[0].type + }, + success: function(json) { + args.response.success({ + data: $.map( + json.listnetworkofferingsresponse.networkoffering, + function(networkOffering) { + return { + id: networkOffering.id, + description: networkOffering.name + }; + } + ) + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } }, { startip: { label: 'Start IP' }, diff --git a/ui/scripts/projects.js b/ui/scripts/projects.js index 3947ba7b965..7fcd805c283 100644 --- a/ui/scripts/projects.js +++ b/ui/scripts/projects.js @@ -4,6 +4,220 @@ return window.g_projectsInviteRequired; }, + resourceManagement: { + update: function(args) { + var totalResources = 5; + var updatedResources = 0; + $.each(args.data, function(key, value) { + $.ajax({ + url: createURL('updateResourceLimit'), + data: { + resourcetype: key, + max: args.data[key] + }, + success: function(json) { + updatedResources++; + if (updatedResources == totalResources) { + args.response.success(); + } + } + }); + }); + }, + + dataProvider: function(args) { + $.ajax({ + url: createURL('listResourceLimits'), + success: function(json) { + args.response.success({ + data: $.map( + json.listresourcelimitsresponse.resourcelimit, + function(resource) { + var resourceMap = { + 0: { + id: 'user_vm', + label: 'Max. User VMs' + }, + 1: { + id: 'public_ip', + label: 'Max. Public IPs' + }, + 2: { + id: 'volume', + label: 'Max. Volumes' + }, + 3: { + id: 'snapshot', + label: 'Max. Snapshots' + }, + 4: { + id: 'template', + label: 'Max. Templates' + }, + 5: { + id: 'project', + label: 'Max. Projects' + } + }; + return { + id: resourceMap[resource.resourcetype].id, + label: resourceMap[resource.resourcetype].label, + type: resource.resourcetype, + value: resource.max + }; + } + ) + }); + } + }); + + } + }, + + dashboard: function(args) { + var dataFns = { + instances: function(data) { + $.ajax({ + url: createURL('listVirtualMachines'), + success: function(json) { + var instances = json.listvirtualmachinesresponse.virtualmachine ? + json.listvirtualmachinesresponse.virtualmachine : []; + + dataFns.storage($.extend(data, { + runningInstances: $.grep(instances, function(instance) { + return instance.state == 'Running'; + }).length, + stoppedInstances: $.grep(instances, function(instance) { + return instance.state != 'Running'; + }).length, + totalInstances: instances.length + })); + } + }); + }, + + storage: function(data) { + $.ajax({ + url: createURL('listVolumes'), + success: function(json) { + dataFns.bandwidth($.extend(data, { + totalVolumes: json.listvolumesresponse.volume ? + json.listvolumesresponse.count : 0 + })); + } + }); + }, + + bandwidth: function(data) { + var totalBandwidth = 0; + $.ajax({ + url: createURL('listNetworks'), + success: function(json) { + var networks = json.listnetworksresponse.network ? + json.listnetworksresponse.network : []; + $(networks).each(function() { + var network = this; + $.ajax({ + url: createURL('listNetworkOfferings'), + async: false, + data: { + id: network.networkofferingid + }, + success: function(json) { + totalBandwidth += + json.listnetworkofferingsresponse.networkoffering[0].networkrate; + } + }); + }); + + dataFns.ipAddresses($.extend(data, { + totalBandwidth: totalBandwidth + })); + } + }); + }, + + ipAddresses: function(data) { + $.ajax({ + url: createURL('listPublicIpAddresses'), + success: function(json) { + dataFns.loadBalancingRules($.extend(data, { + totalIPAddresses: json.listpublicipaddressesresponse ? + json.listpublicipaddressesresponse.count : 0 + })); + } + }); + }, + + loadBalancingRules: function(data) { + $.ajax({ + url: createURL('listLoadBalancerRules'), + success: function(json) { + dataFns.portForwardingRules($.extend(data, { + totalLoadBalancers: json.listloadbalancerrulesresponse ? + json.listloadbalancerrulesresponse.count : 0 + })); + } + }); + }, + + portForwardingRules: function(data) { + $.ajax({ + url: createURL('listPortForwardingRules'), + success: function(json) { + dataFns.users($.extend(data, { + totalPortForwards: json.listportforwardingrulesresponse ? + json.listportforwardingrulesresponse.count : 0 + })); + } + }); + }, + + users: function(data) { + $.ajax({ + url: createURL('listProjectAccounts'), + success: function(json) { + var users = json.listprojectaccountsresponse.projectaccount; + + dataFns.events($.extend(data, { + users: $.map(users, function(user) { + return { + account: user.account + }; + }) + })); + } + }); + }, + + events: function(data) { + $.ajax({ + url: createURL('listEvents', { ignoreProject: true }), + success: function(json) { + var events = json.listeventsresponse.event; + + complete($.extend(data, { + events: $.map(events, function(event) { + return { + date: event.created.substr(5, 2) + '/' + event.created.substr(8, 2) + '/' + event.created.substr(2, 2), + desc: event.description + }; + }) + })); + } + }); + } + }; + + var complete = function(data) { + args.response.success({ + data: data + }); + }; + + dataFns.instances(); + }, + add: function(args) { setTimeout(function() { $.ajax({ diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 90f4d393156..8b4225c37f4 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -258,31 +258,7 @@ }, 'management': { - detailView: { - viewAll: { path: '_zone.pods', label: 'Pods' }, - actions: { - edit: { - label: 'Edit', - action: function(args) { - var array1 = []; - array1.push("&name=" +todb(args.data.name)); - array1.push("&dns1=" + todb(args.data.dns1)); - array1.push("&dns2=" + todb(args.data.dns2)); //dns2 can be empty ("") when passed to API - array1.push("&internaldns1=" + todb(args.data.internaldns1)); - array1.push("&internaldns2=" + todb(args.data.internaldns2)); //internaldns2 can be empty ("") when passed to API - array1.push("&domain=" + todb(args.data.domain)); - $.ajax({ - url: createURL("updateZone&id=" + args.context.zones[0].id + array1.join("")), - dataType: "json", - async: false, - success: function(json) { - selectedZoneObj = json.updatezoneresponse.zone; //override selectedZoneObj after update zone - args.response.success({data: selectedZoneObj}); - } - }); - } - } - }, + detailView: { tabs: { details: { title: 'Details', @@ -303,99 +279,28 @@ }); } }, - - ipAddresses: { - title: 'IP Ranges', - custom: function(args) { - return $('
    ').multiEdit({ - context: args.context, - noSelect: true, - fields: { - 'gateway': { edit: true, label: 'Gateway' }, - 'netmask': { edit: true, label: 'Netmask' }, - 'vlan': { edit: true, label: 'VLAN', isOptional: true }, - 'startip': { edit: true, label: 'Start IP' }, - 'endip': { edit: true, label: 'End IP' }, - 'add-rule': { label: 'Add', addButton: true } - }, - add: { - label: 'Add', - action: function(args) { - var array1 = []; - array1.push("&zoneId=" + args.context.zones[0].id); - - if (args.data.vlan != null && args.data.vlan.length > 0) - array1.push("&vlan=" + todb(args.data.vlan)); - else - array1.push("&vlan=untagged"); - - array1.push("&gateway=" + args.data.gateway); - array1.push("&netmask=" + args.data.netmask); - array1.push("&startip=" + args.data.startip); - if(args.data.endip != null && args.data.endip.length > 0) - array1.push("&endip=" + args.data.endip); - - if(args.context.zones[0].securitygroupsenabled == false) - array1.push("&forVirtualNetwork=true"); - else - array1.push("&forVirtualNetwork=false"); - - $.ajax({ - url: createURL("createVlanIpRange" + array1.join("")), - dataType: "json", - success: function(json) { - var item = json.createvlaniprangeresponse.vlan; - args.response.success({ - data: item, - notification: { - label: 'IP range is added', - poll: function(args) { - args.complete(); - } - } - }); - }, - error: function(XMLHttpResponse) { - var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - args.response.error(errorMsg); - } - }); - } - }, - actions: { - destroy: { - label: 'Delete', - action: function(args) { - $.ajax({ - url: createURL('deleteVlanIpRange&id=' + args.context.multiRule[0].id), - dataType: 'json', - async: true, - success: function(json) { - args.response.success({ - notification: { - label: 'Remove IP range ' + args.context.multiRule[0].id, - poll: function(args) { - args.complete(); - } - } - }); - } - }); - } - } - }, - dataProvider: function(args) { - $.ajax({ - url: createURL("listVlanIpRanges&zoneid=" + args.context.zones[0].id + "&networkId=" + selectedManagementNetworkObj.id), - dataType: "json", - success: function(json) { - var items = json.listvlaniprangesresponse.vlaniprange; - args.response.success({data: items}); - } - }); - } - }); - } + ipAddresses: { //read-only listView (no actions) filled with pod info (not VlanIpRange info) + title: 'IP Ranges', + listView: { + fields: { + name: { label: 'Pod name' }, + gateway: { label: 'Gateway' }, + netmask: { label: 'Netmask' }, + startip: { label: 'Start IP' }, + endip: { label: 'End IP' } + }, + dataProvider: function(args) { + $.ajax({ + url: createURL("listPods&zoneid=" + selectedZoneObj.id + "&page=" + args.page + "&pagesize=" + pageSize), + dataType: "json", + async: true, + success: function(json) { + var items = json.listpodsresponse.pod; + args.response.success({ data:items }); + } + }); + } + } } } } @@ -446,8 +351,7 @@ return hiddenFields; }, fields: [ - { - id: { label: 'ID' }, + { state: { label: 'State' }, startVlan: { label: 'Start Vlan', @@ -496,39 +400,46 @@ context: args.context, noSelect: true, fields: { + 'podid': { + label: 'Pod', + select: function(args) { + $.ajax({ + url: createURL("listPods&zoneid=" + selectedZoneObj.id), + dataType: "json", + success: function(json) { + var items = []; + var pods = json.listpodsresponse.pod; + $(pods).each(function(){ + items.push({name: this.id, description: this.name}); //should be "{id: this.id, description: this.name}" (to be consistent with dropdown in createFrom and edit mode) (Brian will fix widget later) + }); + args.response.success({ data: items }); + } + }); + } + }, 'gateway': { edit: true, label: 'Gateway' }, - 'netmask': { edit: true, label: 'Netmask' }, - 'vlan': { edit: true, label: 'VLAN', isOptional: true }, + 'netmask': { edit: true, label: 'Netmask' }, 'startip': { edit: true, label: 'Start IP' }, 'endip': { edit: true, label: 'End IP' }, 'add-rule': { label: 'Add', addButton: true } }, add: { label: 'Add', - action: function(args) { - var array1 = []; - array1.push("&zoneId=" + args.context.zones[0].id); - - if (args.data.vlan != null && args.data.vlan.length > 0) - array1.push("&vlan=" + todb(args.data.vlan)); - else - array1.push("&vlan=untagged"); - + action: function(args) { + var array1 = []; + array1.push("&podid=" + args.data.podid); + array1.push("&networkid=" + selectedGuestNetworkObj.id) array1.push("&gateway=" + args.data.gateway); array1.push("&netmask=" + args.data.netmask); array1.push("&startip=" + args.data.startip); if(args.data.endip != null && args.data.endip.length > 0) array1.push("&endip=" + args.data.endip); - - if(args.context.zones[0].securitygroupsenabled == false) - array1.push("&forVirtualNetwork=true"); - else - array1.push("&forVirtualNetwork=false"); - + array1.push("&forVirtualNetwork=false"); //indicates this new IP range is for guest network, not public network + $.ajax({ url: createURL("createVlanIpRange" + array1.join("")), dataType: "json", - success: function(json) { + success: function(json) { var item = json.createvlaniprangeresponse.vlan; args.response.success({ data: item, @@ -1045,7 +956,23 @@ detailView: { name: 'Guest network details', - viewAll: { path: '_zone.guestIpRanges', label: 'IP ranges' }, + viewAll: { + path: '_zone.guestIpRanges', + label: 'IP ranges', + preFilter: function(args) { + if(selectedGuestNetworkObj.type == "Isolated") { + var services = selectedGuestNetworkObj.service; + if(services != null) { + for(var i=0; i < services.length; i++) { + var service = services[i]; + if(service.name == "SourceNat") + return false; + } + } + } + return true; + } + }, actions: { edit: { label: 'Edit', @@ -1098,6 +1025,47 @@ poll: pollAsyncJobResult } }, + + 'restart': { + label: 'Restart network', + action: function(args) { + $.ajax({ + url: createURL("restartNetwork&cleanup=true&id=" + args.context.networks[0].id), + dataType: "json", + async: true, + success: function(json) { + var jid = json.restartnetworkresponse.jobid; + args.response.success( + {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.network; + } + } + } + ); + } + }); + }, + messages: { + confirm: function(args) { + return 'Please confirm that you want to restart network'; + }, + success: function(args) { + return 'Network is being restarted'; + }, + notification: function(args) { + return 'Restarting network'; + }, + complete: function(args) { + return 'Network has been restarted'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + 'delete': { label: 'Delete network', messages: { @@ -2938,16 +2906,38 @@ } }); + var networkOfferingObjsWithoutSG = []; $.ajax({ url: createURL("listNetworkOfferings&state=Enabled&guestiptype=Shared"), dataType: "json", async: false, success: function(json) { networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; + + $(networkOfferingObjs).each(function() { + var includingSGP = false; + var serviceObjArray = this.service; + for(var k = 0; k < serviceObjArray.length; k++) { + if(serviceObjArray[k].name == "SecurityGroup") { + includingSGP = true; + break; + } + } + if(includingSGP == false) //withoutSG + networkOfferingObjsWithoutSG.push(this); + }); } }); + + args.response.success({ + domains: domainObjs, - args.response.success({domains: domainObjs, networkOfferings: networkOfferingObjs}); + // Non-security-group-enabled offerings + networkOfferings: networkOfferingObjsWithoutSG, + + // Security group-enabled offerings + securityGroupNetworkOfferings: networkOfferingObjs + }); }, // Step 3: Setup Pod @@ -3040,7 +3030,7 @@ //alert("updatePhysicalNetwork succeeded."); // get network service provider ID of Virtual Router - var networkServiceProviderId; + var virtualRouterProviderId; $.ajax({ url: createURL("listNetworkServiceProviders&name=VirtualRouter&physicalNetworkId=" + physicalNetworkId), dataType: "json", @@ -3048,18 +3038,18 @@ success: function(json) { var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; if(items != null && items.length > 0) { - networkServiceProviderId = items[0].id; + virtualRouterProviderId = items[0].id; } } }); - if(networkServiceProviderId == null) { - alert("error: listNetworkServiceProviders API doesn't return Network Service Provider ID"); + if(virtualRouterProviderId == null) { + alert("error: listNetworkServiceProviders API doesn't return VirtualRouter provider ID"); return; } var virtualRouterElementId; $.ajax({ - url: createURL("listVirtualRouterElements&nspid=" + networkServiceProviderId), + url: createURL("listVirtualRouterElements&nspid=" + virtualRouterProviderId), dataType: "json", async: false, success: function(json) { @@ -3096,7 +3086,7 @@ //alert("configureVirtualRouterElement succeeded."); $.ajax({ - url: createURL("updateNetworkServiceProvider&state=Enabled&id=" + networkServiceProviderId), + url: createURL("updateNetworkServiceProvider&state=Enabled&id=" + virtualRouterProviderId), dataType: "json", async: false, success: function(json) { @@ -3114,52 +3104,170 @@ else { $("body").stopTime(timerKey); if (result.jobstatus == 1) { - //alert("updateNetworkServiceProvider succeeded."); - - //create network if it's basic zone - if(newZoneObj.networktype == "Basic") { - var array2 = []; - array2.push("&zoneid=" + newZoneObj.id); - array2.push("&name=guestNetworkForBasicZone"); - array2.push("&displaytext=guestNetworkForBasicZone"); - array2.push("&networkofferingid=" + args.data.networkOfferingId); - $.ajax({ - url: createURL("createNetwork" + array2.join("")), - dataType: "json", - async: false, - success: function(json) { - - } - }); - } + //alert("Virtual Router Provider is enabled"); - //create pod - var array3 = []; - array3.push("&zoneId=" + newZoneObj.id); - array3.push("&name=" + todb(args.data.podName)); - array3.push("&gateway=" + todb(args.data.podGateway)); - array3.push("&netmask=" + todb(args.data.podNetmask)); - array3.push("&startIp=" + todb(args.data.podStartIp)); + if(newZoneObj.networktype == "Basic") { + if(args.data["security-groups-enabled"] == "on") { //need to Enable security group provider first + // get network service provider ID of Security Group + var securityGroupProviderId; + $.ajax({ + url: createURL("listNetworkServiceProviders&name=SecurityGroupProvider&physicalNetworkId=" + physicalNetworkId), + dataType: "json", + async: false, + success: function(json) { + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if(items != null && items.length > 0) { + securityGroupProviderId = items[0].id; + } + } + }); + if(securityGroupProviderId == null) { + alert("error: listNetworkServiceProviders API doesn't return security group provider ID"); + return; + } + + $.ajax({ + url: createURL("updateNetworkServiceProvider&state=Enabled&id=" + securityGroupProviderId), + dataType: "json", + async: false, + success: function(json) { + var jobId = json.updatenetworkserviceproviderresponse.jobid; + var timerKey = "updateNetworkServiceProviderJob_"+jobId; + $("body").everyTime(2000, timerKey, function() { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId="+jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + $("body").stopTime(timerKey); + if (result.jobstatus == 1) { + //alert("Security group provider is enabled"); - var endip = args.data.podEndIp; //optional - if (endip != null && endip.length > 0) - array3.push("&endIp=" + todb(endip)); + //create network (for basic zone only) + var array2 = []; + array2.push("&zoneid=" + newZoneObj.id); + array2.push("&name=guestNetworkForBasicZone"); + array2.push("&displaytext=guestNetworkForBasicZone"); + array2.push("&networkofferingid=" + args.data.networkOfferingId); + $.ajax({ + url: createURL("createNetwork" + array2.join("")), + dataType: "json", + async: false, + success: function(json) { + //create pod + var array3 = []; + array3.push("&zoneId=" + newZoneObj.id); + array3.push("&name=" + todb(args.data.podName)); + array3.push("&gateway=" + todb(args.data.podGateway)); + array3.push("&netmask=" + todb(args.data.podNetmask)); + array3.push("&startIp=" + todb(args.data.podStartIp)); - $.ajax({ - url: createURL("createPod" + array3.join("")), - dataType: "json", - async: false, - success: function(json) { - - }, - error: function(XMLHttpResponse) { - var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - alert("createPod failed. Error: " + errorMsg); - } - }); + var endip = args.data.podEndIp; //optional + if (endip != null && endip.length > 0) + array3.push("&endIp=" + todb(endip)); + + $.ajax({ + url: createURL("createPod" + array3.join("")), + dataType: "json", + async: false, + success: function(json) { + + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("createPod failed. Error: " + errorMsg); + } + }); + } + }); + } + else if (result.jobstatus == 2) { + alert("failed to enable security group provider. Error: " + fromdb(result.jobresult.errortext)); + } + } + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("updateNetworkServiceProvider failed. Error: " + errorMsg); + } + }); + }); + } + }); + } + else { + //create network (for basic zone only) + var array2 = []; + array2.push("&zoneid=" + newZoneObj.id); + array2.push("&name=guestNetworkForBasicZone"); + array2.push("&displaytext=guestNetworkForBasicZone"); + array2.push("&networkofferingid=" + args.data.networkOfferingId); + $.ajax({ + url: createURL("createNetwork" + array2.join("")), + dataType: "json", + async: false, + success: function(json) { + //create pod + var array3 = []; + array3.push("&zoneId=" + newZoneObj.id); + array3.push("&name=" + todb(args.data.podName)); + array3.push("&gateway=" + todb(args.data.podGateway)); + array3.push("&netmask=" + todb(args.data.podNetmask)); + array3.push("&startIp=" + todb(args.data.podStartIp)); + + var endip = args.data.podEndIp; //optional + if (endip != null && endip.length > 0) + array3.push("&endIp=" + todb(endip)); + + $.ajax({ + url: createURL("createPod" + array3.join("")), + dataType: "json", + async: false, + success: function(json) { + + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("createPod failed. Error: " + errorMsg); + } + }); + } + }); + } + } + else { //Advanced zone + //create pod + var array3 = []; + array3.push("&zoneId=" + newZoneObj.id); + array3.push("&name=" + todb(args.data.podName)); + array3.push("&gateway=" + todb(args.data.podGateway)); + array3.push("&netmask=" + todb(args.data.podNetmask)); + array3.push("&startIp=" + todb(args.data.podStartIp)); + + var endip = args.data.podEndIp; //optional + if (endip != null && endip.length > 0) + array3.push("&endIp=" + todb(endip)); + + $.ajax({ + url: createURL("createPod" + array3.join("")), + dataType: "json", + async: false, + success: function(json) { + + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("createPod failed. Error: " + errorMsg); + } + }); + } } else if (result.jobstatus == 2) { - alert("updateNetworkServiceProvider failed. Error: " + fromdb(result.jobresult.errortext)); + alert("failed to enable Virtual Router Provider. Error: " + fromdb(result.jobresult.errortext)); } } }, @@ -7934,8 +8042,8 @@ section: 'guest-IP-range', fields: { //id: { label: 'ID' }, - podname: { label: 'Pod' }, - vlan: { label: 'VLAN' }, + //podname: { label: 'Pod' }, + //vlan: { label: 'VLAN' }, startip: { label: 'Start IP' }, endip: { label: 'End IP' } }, @@ -8045,6 +8153,7 @@ }, action: function(args) { + /* if(selectedZoneObj.networktype == "Basic") { var array2 = []; @@ -8052,7 +8161,7 @@ if(args.data.podId != "0") { podId = args.data.podId; } - else { //args.data.podId==0, create pod first + else { var array1 = []; array1.push("&zoneId=" + selectedZoneObj.id); array1.push("&name=" + todb(args.data.podname)); @@ -8060,7 +8169,7 @@ array1.push("&netmask=" + todb(args.data.reservedSystemNetmask)); array1.push("&startIp=" + todb(args.data.reservedSystemStartIp)); - var endip = args.data.reservedSystemEndIp; //optional + var endip = args.data.reservedSystemEndIp; if (endip != null && endip.length > 0) array1.push("&endIp=" + todb(endip)); @@ -8071,10 +8180,6 @@ success: function(json) { var item = json.createpodresponse.pod; podId = item.id; - }, - error: function(XMLHttpResponse) { - //var errorMsg = parseXMLHttpResponse(XMLHttpResponse); - //args.response.error(errorMsg); } }); } @@ -8085,7 +8190,7 @@ array2.push("&podId=" + podId); array2.push("&vlan=untagged"); array2.push("&zoneid=" + selectedZoneObj.id); - array2.push("&forVirtualNetwork=false"); //direct VLAN + array2.push("&forVirtualNetwork=false"); array2.push("&gateway=" + todb(args.data.guestGateway)); array2.push("&netmask=" + todb(args.data.guestNetmask)); array2.push("&startip=" + todb(args.data.guestStartIp)); @@ -8106,7 +8211,9 @@ } }); } - else { //selectedZoneObj.networktype == "Advanced" + */ + + //else { //selectedZoneObj.networktype == "Advanced" var array2 = []; array2.push("&startip=" + args.data.guestStartIp); var endip = args.data.guestEndIp; @@ -8124,7 +8231,7 @@ args.response.error(errorMsg); } }); - } + //} }, notification: { diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js index a61c2d1a7d3..6fcf5b9bd4b 100644 --- a/ui/scripts/templates.js +++ b/ui/scripts/templates.js @@ -1507,8 +1507,11 @@ //do nothing } else { - allowedActions.push("edit"); - allowedActions.push("copyTemplate"); + allowedActions.push("edit"); + + if(jsonObj.zoneid != null || jsonObj.zoneid != "-1") + allowedActions.push("copyTemplate"); + //allowedActions.push("createVm"); // For Beta2, this simply doesn't work without a network. } @@ -1546,8 +1549,10 @@ //do nothing } else { - allowedActions.push("edit"); - allowedActions.push("copyISO"); + allowedActions.push("edit"); + + if(jsonObj.zoneid != null || jsonObj.zoneid != "-1") + allowedActions.push("copyISO"); } // "Create VM" diff --git a/ui/scripts/ui-custom/installWizard.js b/ui/scripts/ui-custom/installWizard.js index c999b7482e0..360c8abe22d 100644 --- a/ui/scripts/ui-custom/installWizard.js +++ b/ui/scripts/ui-custom/installWizard.js @@ -5,6 +5,9 @@ var $container = args.$container; var state = {}; // Hold wizard form state + var launchStart; // Holds last launch callback, in case of error + var $launchState; + /** * Successful installation action */ @@ -36,8 +39,10 @@ * @param stateStepID ID to group state elements in (i.e., zone, pod, cluster, ...) * @param $elem (optional) Element containing
    , to serialize for state */ - var goTo = cloudStack._goto = function(stepID, stateID, $elem) { - var $nextStep = steps[stepID](); + var goTo = cloudStack._goto = function(stepID, stateID, $elem, options) { + if (!options) options = {}; + + var $nextStep = steps[stepID]({ nextStep: options.nextStep }); var $body = $installWizard.find('.body'); if (stateID && $elem) { @@ -83,7 +88,7 @@ $prev.click(function() { goTo(prevStepID); }); - + return function(args) { showDiagram(diagram); @@ -95,7 +100,7 @@ ); }; }, - + /** * A standard form-based wizard step template * -- relies on createForm for form generation @@ -134,7 +139,7 @@ $form.find('.form-item').addClass('field'); $prev.appendTo($form.find('form')); $save.appendTo($form.find('form')); - + // Submit handler $form.find('form').submit(function() { form.completeAction($form); @@ -153,8 +158,19 @@ $container.append($form.prepend($title)); showTooltip($form, tooltipID); - + return function(args) { + var overrideGotoEvent = function(event) { + goTo(args.nextStep); + + return false; + }; + + if (args && args.nextStep) { + $save.unbind('click'); + $save.click(overrideGotoEvent); + } + // Setup diagram, tooltips showDiagram(diagram); setTimeout(function() { @@ -350,7 +366,7 @@ nextStepID: 'addZone', diagram: '.part.zone' }), - + /** * Add zone form */ @@ -622,31 +638,66 @@ launch: function(args) { var $intro = $('
    ').addClass('intro'); var $title = $('
    ').addClass('title') - .html('Now building your cloud...'); - var $subtitle = $('
    ').addClass('subtitle') - .html(''); + .html('Now building your cloud...').appendTo($intro); + var $subtitle = $('
    ').addClass('subtitle').html('').appendTo($intro); - cloudStack.installWizard.action({ - data: state, - response: { - message: function(msg) { - var $li = $('
  • ').html(msg); - - $subtitle.append($li); - - $li.siblings().addClass('complete'); - }, - success: function() { - goTo('complete'); - } + var doAction = function() { + if (launchStart) { + $('.subtitle').children().remove(); } - }); + + cloudStack.installWizard.action({ + data: state, + startFn: launchStart, + response: { + message: function(msg) { + var $li = $('
  • ').html(msg); + if (launchStart) { + $li.appendTo('.subtitle'); + $li.parent().find('li') + .filter(function() { + return this != $li.get(0); + }).addClass('complete'); + } else { + $subtitle.append($li); + $li.siblings().addClass('complete'); + } + }, + success: function() { + goTo('complete'); + }, + error: function(stepID, message, callback) { + if (launchStart) { + $subtitle = $('.subtitle'); + $subtitle.children().remove(); + $('li').children().remove(); + } + + launchStart = callback; + $subtitle.find('li:last').addClass('error'); + + $subtitle.append( + $('

    ').html( + 'Something went wrong; you may go back and correct any errors.' + ), + $('

    ').addClass('button').append( + $('').html('Go back') + ).click(function() { + goTo(stepID, null, null, { + nextStep: 'launch' + }); + }) + ); + } + } + }); + }; + + doAction(); showDiagram('.part.loading'); - return $intro.append( - $title, $subtitle - ); + return $intro; }, complete: function(args) { diff --git a/ui/scripts/ui-custom/projects.js b/ui/scripts/ui-custom/projects.js index a5132411b76..72afa1685f6 100644 --- a/ui/scripts/ui-custom/projects.js +++ b/ui/scripts/ui-custom/projects.js @@ -20,8 +20,65 @@ var tabs = { overview: function() { var $dashboard = $('#template').find('.project-dashboard-view').clone(); + $dashboard.data('tab-title', 'Dashboard'); - $dashboard.data('tab-title', 'Dashboard') + var getData = function() { + // Populate data + $dashboard.find('[data-item]').hide(); + var $loading = $('
    ').addClass('loading-overlay').prependTo($dashboard); + cloudStack.projects.dashboard({ + response: { + success: function(args) { + $loading.remove(); + var data = args.data; + + // Iterate over data; populate corresponding DOM elements + $.each(data, function(key, value) { + var $elem = $dashboard.find('[data-item=' + key + ']'); + + // This assumes an array of data + if ($elem.is('ul')) { + $elem.show(); + var $liTmpl = $elem.find('li').remove(); + $(value).each(function() { + var item = this; + var $li = $liTmpl.clone().appendTo($elem).hide(); + + $.each(item, function(arrayKey, arrayValue) { + var $arrayElem = $li.find('[data-list-item=' + arrayKey + ']'); + + $arrayElem.html(arrayValue); + }); + + $li.attr({ title: item.description }); + + $li.fadeIn(); + }); + } else { + $elem.each(function() { + var $item = $(this); + if ($item.hasClass('chart-line')) { + $item.show().animate({ width: value + '%' }); + } else { + $item.hide().html(value).fadeIn(); + } + }); + } + }); + } + } + }); + }; + + getData(); + + $dashboard.find('.button.manage-resources').click(function() { + $('.navigation-item.network').click(); + }); + + $dashboard.find('.info-box.events .button').click(function() { + $('.navigation-item.events').click(); + }); return $dashboard; } @@ -39,6 +96,69 @@ return $('
    ').addClass('management-invite').data('tab-title', 'Invitations'); }; } + + tabs.resources = function() { + var $resources = $('
    ').addClass('resources').data('tab-title', 'Resources'); + var $form = $(''); + var $submit = $('').attr({ + type: 'submit' + }).val('Apply'); + + cloudStack.projects.resourceManagement.dataProvider({ + response: { + success: function(args) { + $(args.data).each(function() { + var resource = this; + var $field = $('
    ').addClass('field'); + var $label = $('