| // Copyright 2012 Citrix Systems, Inc. Licensed under the |
| // Apache License, Version 2.0 (the "License"); you may not use this |
| // file except in compliance with the License. Citrix Systems, Inc. |
| // reserves all rights not expressly granted by the License. |
| // You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Automatically generated by addcopyright.py at 04/03/2012 |
| package com.cloud.network;
|
|
|
| import java.sql.Connection;
|
| import java.sql.PreparedStatement;
|
| import java.sql.SQLException;
|
| import java.util.List;
|
| import java.util.Map;
|
|
|
| import javax.ejb.Local;
|
| import javax.naming.ConfigurationException;
|
|
|
| import org.apache.log4j.Logger;
|
|
|
| import com.cloud.api.commands.CreateStorageNetworkIpRangeCmd;
|
| import com.cloud.api.commands.DeleteStorageNetworkIpRangeCmd;
|
| import com.cloud.api.commands.UpdateStorageNetworkIpRangeCmd;
|
| import com.cloud.api.commands.listStorageNetworkIpRangeCmd;
|
| import com.cloud.dc.HostPodVO;
|
| import com.cloud.dc.StorageNetworkIpRange;
|
| import com.cloud.dc.StorageNetworkIpAddressVO;
|
| import com.cloud.dc.StorageNetworkIpRangeVO;
|
| import com.cloud.dc.dao.HostPodDao;
|
| import com.cloud.dc.dao.StorageNetworkIpAddressDao;
|
| import com.cloud.dc.dao.StorageNetworkIpRangeDao;
|
| import com.cloud.exception.InsufficientAddressCapacityException;
|
| import com.cloud.exception.InvalidParameterValueException;
|
| import com.cloud.host.HostVO;
|
| import com.cloud.network.Networks.TrafficType;
|
| import com.cloud.network.dao.NetworkDao;
|
| import com.cloud.utils.Pair;
|
| import com.cloud.utils.component.Inject;
|
| import com.cloud.utils.db.DB;
|
| import com.cloud.utils.db.SearchCriteria2;
|
| import com.cloud.utils.db.SearchCriteriaService;
|
| import com.cloud.utils.db.Transaction;
|
| import com.cloud.utils.db.SearchCriteria.Op;
|
| import com.cloud.utils.exception.CloudRuntimeException;
|
| import com.cloud.utils.net.NetUtils;
|
| import com.cloud.vm.SecondaryStorageVmVO;
|
| import com.cloud.vm.VirtualMachine;
|
| import com.cloud.vm.dao.SecondaryStorageVmDao;
|
| import com.cloud.vm.dao.VMInstanceDao;
|
|
|
| @Local(value = {StorageNetworkManager.class, StorageNetworkService.class})
|
| public class StorageNetworkManagerImpl implements StorageNetworkManager, StorageNetworkService {
|
| private static final Logger s_logger = Logger.getLogger(StorageNetworkManagerImpl.class);
|
|
|
| String _name;
|
| @Inject
|
| StorageNetworkIpAddressDao _sNwIpDao;
|
| @Inject
|
| StorageNetworkIpRangeDao _sNwIpRangeDao;
|
| @Inject
|
| NetworkDao _networkDao;
|
| @Inject
|
| HostPodDao _podDao;
|
| @Inject
|
| SecondaryStorageVmDao _ssvmDao;
|
|
|
| @Override
|
| public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
| _name = name;
|
| return true;
|
| }
|
|
|
| @Override
|
| public boolean start() {
|
| // TODO Auto-generated method stub
|
| return true;
|
| }
|
|
|
| @Override
|
| public boolean stop() {
|
| // TODO Auto-generated method stub
|
| return true;
|
| }
|
|
|
| @Override
|
| public String getName() {
|
| // TODO Auto-generated method stub
|
| return null;
|
| }
|
|
|
| private void checkOverlapPrivateIpRange(long podId, String startIp, String endIp) {
|
| HostPodVO pod = _podDao.findById(podId);
|
| if (pod == null) {
|
| throw new CloudRuntimeException("Cannot find pod " + podId);
|
| }
|
| String[] IpRange = pod.getDescription().split("-");
|
| if ((IpRange[0] == null || IpRange[1] == null) || (!NetUtils.isValidIp(IpRange[0]) || !NetUtils.isValidIp(IpRange[1]))) {
|
| return;
|
| }
|
| if (NetUtils.ipRangesOverlap(startIp, endIp, IpRange[0], IpRange[1])) {
|
| throw new InvalidParameterValueException("The Storage network Start IP and endIP address range overlap with private IP :" + IpRange[0] + ":" + IpRange[1]);
|
| }
|
| }
|
|
|
| private void checkOverlapStorageIpRange(long podId, String startIp, String endIp) {
|
| List<StorageNetworkIpRangeVO> curRanges = _sNwIpRangeDao.listByPodId(podId);
|
| for (StorageNetworkIpRangeVO range : curRanges) {
|
| if (NetUtils.ipRangesOverlap(startIp, endIp, range.getStartIp(), range.getEndIp())) {
|
| throw new InvalidParameterValueException("The Storage network Start IP and endIP address range overlap with private IP :" + range.getStartIp() + " - " + range.getEndIp());
|
| }
|
| }
|
| }
|
|
|
| private void createStorageIpEntires(Transaction txn, long rangeId, String startIp, String endIp, long zoneId) throws SQLException {
|
| long startIPLong = NetUtils.ip2Long(startIp);
|
| long endIPLong = NetUtils.ip2Long(endIp);
|
| String insertSql = "INSERT INTO `cloud`.`op_dc_storage_network_ip_address` (range_id, ip_address, mac_address, taken) VALUES (?, ?, (select mac_address from `cloud`.`data_center` where id=?), ?)";
|
| String updateSql = "UPDATE `cloud`.`data_center` set mac_address = mac_address+1 where id=?";
|
| PreparedStatement stmt = null;
|
| Connection conn = txn.getConnection();
|
|
|
| while (startIPLong <= endIPLong) {
|
| stmt = conn.prepareStatement(insertSql);
|
| stmt.setLong(1, rangeId);
|
| stmt.setString(2, NetUtils.long2Ip(startIPLong++));
|
| stmt.setLong(3, zoneId);
|
| stmt.setNull(4, java.sql.Types.DATE);
|
| stmt.executeUpdate();
|
| stmt.close();
|
|
|
| stmt = txn.prepareStatement(updateSql);
|
| stmt.setLong(1, zoneId);
|
| stmt.executeUpdate();
|
| stmt.close();
|
| }
|
| }
|
|
|
| @Override
|
| @DB
|
| public StorageNetworkIpRange updateIpRange(UpdateStorageNetworkIpRangeCmd cmd) {
|
| Integer vlan = cmd.getVlan();
|
| Long rangeId = cmd.getId();
|
| String startIp = cmd.getStartIp();
|
| String endIp = cmd.getEndIp();
|
| String netmask = cmd.getNetmask();
|
|
|
| if (netmask != null && !NetUtils.isValidNetmask(netmask)) {
|
| throw new CloudRuntimeException("Invalid netmask:" + netmask);
|
| }
|
|
|
| if (_sNwIpDao.countInUseIpByRangeId(rangeId) > 0) {
|
| throw new CloudRuntimeException("Cannot update the range," + getInUseIpAddress(rangeId));
|
| }
|
|
|
| StorageNetworkIpRangeVO range = _sNwIpRangeDao.findById(rangeId);
|
| if (range == null) {
|
| throw new CloudRuntimeException("Cannot find storage ip range " + rangeId);
|
| }
|
|
|
| if (startIp != null || endIp != null) {
|
| long podId = range.getPodId();
|
| startIp = startIp == null ? range.getStartIp() : startIp;
|
| endIp = endIp == null ? range.getEndIp() : endIp;
|
| checkOverlapPrivateIpRange(podId, startIp, endIp);
|
| checkOverlapStorageIpRange(podId, startIp, endIp);
|
| }
|
|
|
| Transaction txn = Transaction.currentTxn();
|
| txn.start();
|
| try {
|
| range = _sNwIpRangeDao.acquireInLockTable(range.getId());
|
| if (range == null) {
|
| throw new CloudRuntimeException("Cannot acquire lock on storage ip range " + rangeId);
|
| }
|
| StorageNetworkIpRangeVO vo = _sNwIpRangeDao.createForUpdate();
|
| if (vlan != null) {
|
| vo.setVlan(vlan);
|
| }
|
| if (startIp != null) {
|
| vo.setStartIp(startIp);
|
| }
|
| if (endIp != null) {
|
| vo.setEndIp(endIp);
|
| }
|
| if (netmask != null) {
|
| vo.setNetmask(netmask);
|
| }
|
| _sNwIpRangeDao.update(rangeId, vo);
|
| } finally {
|
| if (range != null) {
|
| _sNwIpRangeDao.releaseFromLockTable(range.getId());
|
| }
|
| }
|
| txn.commit();
|
|
|
| return _sNwIpRangeDao.findById(rangeId);
|
| }
|
|
|
| @Override
|
| @DB
|
| public StorageNetworkIpRange createIpRange(CreateStorageNetworkIpRangeCmd cmd) throws SQLException {
|
| Long podId = cmd.getPodId();
|
| String startIp = cmd.getStartIp();
|
| String endIp = cmd.getEndIp();
|
| Integer vlan = cmd.getVlan();
|
| String netmask = cmd.getNetmask();
|
|
|
| if (endIp == null) {
|
| endIp = startIp;
|
| }
|
|
|
| if (!NetUtils.isValidNetmask(netmask)) {
|
| throw new CloudRuntimeException("Invalid netmask:" + netmask);
|
| }
|
|
|
| HostPodVO pod = _podDao.findById(podId);
|
| if (pod == null) {
|
| throw new CloudRuntimeException("Cannot find pod " + podId);
|
| }
|
| Long zoneId = pod.getDataCenterId();
|
|
|
| List<NetworkVO> nws = _networkDao.listByZoneAndTrafficType(zoneId, TrafficType.Storage);
|
| if (nws.size() == 0) {
|
| throw new CloudRuntimeException("Cannot find storage network in zone " + zoneId);
|
| }
|
| if (nws.size() > 1) {
|
| throw new CloudRuntimeException("Find more than one storage network in zone " + zoneId + "," + nws.size() + " found");
|
| }
|
| NetworkVO nw = nws.get(0);
|
|
|
| checkOverlapPrivateIpRange(podId, startIp, endIp);
|
| checkOverlapStorageIpRange(podId, startIp, endIp);
|
|
|
| Transaction txn = Transaction.currentTxn();
|
| StorageNetworkIpRangeVO range = null;
|
|
|
| txn.start();
|
| range = new StorageNetworkIpRangeVO(zoneId, podId, nw.getId(), startIp, endIp, vlan, netmask, cmd.getGateWay());
|
| _sNwIpRangeDao.persist(range);
|
| try {
|
| createStorageIpEntires(txn, range.getId(), startIp, endIp, zoneId);
|
| } catch (SQLException e) {
|
| txn.rollback();
|
| StringBuilder err = new StringBuilder();
|
| err.append("Create storage network range failed.");
|
| err.append("startIp=" + startIp);
|
| err.append("endIp=" + endIp);
|
| err.append("netmask=" + netmask);
|
| err.append("zoneId=" + zoneId);
|
| s_logger.debug(err.toString(), e);
|
| throw e;
|
| }
|
|
|
| txn.commit();
|
|
|
| return range;
|
| }
|
|
|
| private String getInUseIpAddress(long rangeId) {
|
| List<String> ips = _sNwIpDao.listInUseIpByRangeId(rangeId);
|
| StringBuilder res = new StringBuilder();
|
| res.append("Below IP of range " + rangeId + " is still in use:");
|
| for (String ip : ips) {
|
| res.append(ip).append(",");
|
| }
|
| return res.toString();
|
| }
|
|
|
| @Override
|
| @DB
|
| public void deleteIpRange(DeleteStorageNetworkIpRangeCmd cmd) {
|
| long rangeId = cmd.getId();
|
| StorageNetworkIpRangeVO range = _sNwIpRangeDao.findById(rangeId);
|
| if (range == null) {
|
| throw new CloudRuntimeException("Can not find storage network ip range " + rangeId);
|
| }
|
|
|
| if (_sNwIpDao.countInUseIpByRangeId(rangeId) > 0) {
|
| throw new CloudRuntimeException(getInUseIpAddress(rangeId));
|
| }
|
|
|
| final Transaction txn = Transaction.currentTxn();
|
| txn.start();
|
| try {
|
| range = _sNwIpRangeDao.acquireInLockTable(rangeId);
|
| if (range == null) {
|
| String msg = "Unable to acquire lock on storage network ip range id=" + rangeId + ", delete failed";
|
| s_logger.warn(msg);
|
| throw new CloudRuntimeException(msg);
|
| }
|
| /* entries in op_dc_storage_network_ip_address will be deleted automatically due to fk_storage_ip_address__range_id constraint key */
|
| _sNwIpRangeDao.remove(rangeId);
|
| } finally {
|
| if (range != null) {
|
| _sNwIpRangeDao.releaseFromLockTable(rangeId);
|
| }
|
| }
|
| txn.commit();
|
| }
|
|
|
| @Override
|
| public List<StorageNetworkIpRange> listIpRange(listStorageNetworkIpRangeCmd cmd) {
|
| Long rangeId = cmd.getRangeId();
|
| Long podId = cmd.getPodId();
|
| Long zoneId = cmd.getZoneId();
|
|
|
| List result = null;
|
| if (rangeId != null) {
|
| result = _sNwIpRangeDao.listByRangeId(rangeId);
|
| } else if (podId != null) {
|
| result = _sNwIpRangeDao.listByPodId(podId);
|
| } else if (zoneId != null) {
|
| result = _sNwIpRangeDao.listByDataCenterId(zoneId);
|
| } else {
|
| result = _sNwIpRangeDao.listAll();
|
| }
|
|
|
| return (List<StorageNetworkIpRange>)result;
|
| }
|
|
|
| @Override
|
| public void releaseIpAddress(String ip) {
|
| _sNwIpDao.releaseIpAddress(ip);
|
| }
|
|
|
| @Override
|
| public StorageNetworkIpAddressVO acquireIpAddress(long podId) {
|
| List<StorageNetworkIpRangeVO> ranges = _sNwIpRangeDao.listByPodId(podId);
|
| for (StorageNetworkIpRangeVO r : ranges) {
|
| try {
|
| r = _sNwIpRangeDao.acquireInLockTable(r.getId());
|
| if (r == null) {
|
| String msg = "Unable to acquire lock on storage network ip range id=" + r.getId() + ", delete failed";
|
| s_logger.warn(msg);
|
| throw new CloudRuntimeException(msg);
|
| }
|
|
|
| StorageNetworkIpAddressVO ip = _sNwIpDao.takeIpAddress(r.getId());
|
| if (ip != null) {
|
| return ip;
|
| }
|
| } finally {
|
| if (r != null) {
|
| _sNwIpRangeDao.releaseFromLockTable(r.getId());
|
| }
|
| }
|
| }
|
|
|
| return null;
|
| }
|
|
|
| @Override
|
| public boolean isStorageIpRangeAvailable(long zoneId) {
|
| SearchCriteriaService<StorageNetworkIpRangeVO, StorageNetworkIpRangeVO> sc = SearchCriteria2.create(StorageNetworkIpRangeVO.class);
|
| sc.addAnd(sc.getEntity().getDataCenterId(), Op.EQ, zoneId);
|
| List<StorageNetworkIpRangeVO> entries = sc.list();
|
| return entries.size() > 0;
|
| }
|
|
|
| @Override
|
| public List<SecondaryStorageVmVO> getSSVMWithNoStorageNetwork(long zoneId) {
|
| List<SecondaryStorageVmVO> ssvms = _ssvmDao.getSecStorageVmListInStates(null, zoneId, VirtualMachine.State.Starting, VirtualMachine.State.Running, VirtualMachine.State.Stopping);
|
| return ssvms;
|
| }
|
|
|
| @Override
|
| public boolean isAnyStorageIpInUseInZone(long zoneId) {
|
| List<StorageNetworkIpRangeVO> ranges = _sNwIpRangeDao.listByDataCenterId(zoneId);
|
| for (StorageNetworkIpRangeVO r : ranges) {
|
| if (_sNwIpDao.countInUseIpByRangeId(r.getId()) > 0) {
|
| return true;
|
| }
|
| }
|
| return false;
|
| }
|
| }
|