blob: aca756502e84c1102b60e523895ae454f81e78f8 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.baremetal.manager;
import com.cloud.baremetal.database.BaremetalRctDao;
import com.cloud.baremetal.database.BaremetalRctVO;
import com.cloud.baremetal.networkservice.BaremetalRctResponse;
import com.cloud.baremetal.networkservice.BaremetalSwitchBackend;
import com.cloud.baremetal.networkservice.BaremetalVlanStruct;
import com.cloud.deploy.DeployDestination;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.network.Network;
import com.cloud.network.Networks;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VirtualMachineProfile;
import com.google.gson.Gson;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.AddBaremetalRctCmd;
import org.apache.cloudstack.api.DeleteBaremetalRctCmd;
import org.apache.cloudstack.api.ListBaremetalRctCmd;
import org.apache.cloudstack.utils.baremetal.BaremetalUtils;
import org.springframework.web.client.RestTemplate;
import javax.inject.Inject;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Created by frank on 5/8/14.
*/
public class BaremetalVlanManagerImpl extends ManagerBase implements BaremetalVlanManager {
private Gson gson = new Gson();
@Inject
private BaremetalRctDao rctDao;
@Inject
private HostDao hostDao;
@Inject
private AccountDao acntDao;
@Inject
private UserDao userDao;
@Inject
private AccountManager acntMgr;
private Map<String, BaremetalSwitchBackend> backends;
private class RackPair {
BaremetalRct.Rack rack;
BaremetalRct.HostEntry host;
}
public void setBackends(Map<String, BaremetalSwitchBackend> backends) {
this.backends = backends;
}
@Override
public BaremetalRctResponse addRct(AddBaremetalRctCmd cmd) {
try {
List<BaremetalRctVO> existings = rctDao.listAll();
if (!existings.isEmpty()) {
throw new CloudRuntimeException(String.format("there is some RCT existing. A CloudStack deployment accepts only one RCT"));
}
URL url = new URL(cmd.getRctUrl());
RestTemplate rest = new RestTemplate();
String rctStr = rest.getForObject(url.toString(), String.class);
// validate it's right format
BaremetalRct rct = gson.fromJson(rctStr, BaremetalRct.class);
QueryBuilder<BaremetalRctVO> sc = QueryBuilder.create(BaremetalRctVO.class);
sc.and(sc.entity().getUrl(), SearchCriteria.Op.EQ, cmd.getRctUrl());
BaremetalRctVO vo = sc.find();
if (vo == null) {
vo = new BaremetalRctVO();
vo.setRct(gson.toJson(rct));
vo.setUrl(cmd.getRctUrl());
vo = rctDao.persist(vo);
} else {
vo.setRct(gson.toJson(rct));
rctDao.update(vo.getId(), vo);
}
BaremetalRctResponse rsp = new BaremetalRctResponse();
rsp.setUrl(vo.getUrl());
rsp.setId(vo.getUuid());
rsp.setObjectName("baremetalrct");
return rsp;
} catch (MalformedURLException e) {
throw new IllegalArgumentException(String.format("%s is not a legal http url", cmd.getRctUrl()));
}
}
@Override
public void prepareVlan(Network nw, DeployDestination destHost) {
List<BaremetalRctVO> vos = rctDao.listAll();
if (vos.isEmpty()) {
throw new CloudRuntimeException("no rack configuration found, please call addBaremetalRct to add one");
}
BaremetalRctVO vo = vos.get(0);
BaremetalRct rct = gson.fromJson(vo.getRct(), BaremetalRct.class);
RackPair rp = findRack(rct, destHost.getHost().getPrivateMacAddress());
if (rp == null) {
throw new CloudRuntimeException(String.format("cannot find any rack contains host[mac:%s], please double check your rack configuration file, update it and call addBaremetalRct again", destHost.getHost().getPrivateMacAddress()));
}
int vlan = Integer.parseInt(Networks.BroadcastDomainType.getValue(nw.getBroadcastUri()));
BaremetalSwitchBackend backend = getSwitchBackend(rp.rack.getL2Switch().getType());
BaremetalVlanStruct struct = new BaremetalVlanStruct();
struct.setHostMac(rp.host.getMac());
struct.setPort(rp.host.getPort());
struct.setSwitchIp(rp.rack.getL2Switch().getIp());
struct.setSwitchPassword(rp.rack.getL2Switch().getPassword());
struct.setSwitchType(rp.rack.getL2Switch().getType());
struct.setSwitchUsername(rp.rack.getL2Switch().getUsername());
struct.setVlan(vlan);
backend.prepareVlan(struct);
}
@Override
public void releaseVlan(Network nw, VirtualMachineProfile vm) {
List<BaremetalRctVO> vos = rctDao.listAll();
if (vos.isEmpty()) {
throw new CloudRuntimeException("no rack configuration found, please call addBaremetalRct to add one");
}
BaremetalRctVO vo = vos.get(0);
BaremetalRct rct = gson.fromJson(vo.getRct(), BaremetalRct.class);
HostVO host = hostDao.findById(vm.getVirtualMachine().getHostId());
RackPair rp = findRack(rct, host.getPrivateMacAddress());
assert rp != null : String.format("where is my rack???");
int vlan = Integer.parseInt(Networks.BroadcastDomainType.getValue(nw.getBroadcastUri()));
BaremetalVlanStruct struct = new BaremetalVlanStruct();
struct.setHostMac(rp.host.getMac());
struct.setPort(rp.host.getPort());
struct.setSwitchIp(rp.rack.getL2Switch().getIp());
struct.setSwitchPassword(rp.rack.getL2Switch().getPassword());
struct.setSwitchType(rp.rack.getL2Switch().getType());
struct.setSwitchUsername(rp.rack.getL2Switch().getUsername());
struct.setVlan(vlan);
BaremetalSwitchBackend backend = getSwitchBackend(rp.rack.getL2Switch().getType());
backend.removePortFromVlan(struct);
}
@Override
public void registerSwitchBackend(BaremetalSwitchBackend backend) {
backends.put(backend.getSwitchBackendType(), backend);
}
@Override
public void deleteRct(DeleteBaremetalRctCmd cmd) {
rctDao.remove(cmd.getId());
}
@Override
public BaremetalRctResponse listRct() {
List<BaremetalRctVO> vos = rctDao.listAll();
if (!vos.isEmpty()) {
BaremetalRctVO vo = vos.get(0);
BaremetalRctResponse rsp = new BaremetalRctResponse();
rsp.setId(vo.getUuid());
rsp.setUrl(vo.getUrl());
rsp.setObjectName("baremetalrct");
return rsp;
}
return null;
}
private BaremetalSwitchBackend getSwitchBackend(String type) {
BaremetalSwitchBackend backend = backends.get(type);
if (backend == null) {
throw new CloudRuntimeException(String.format("cannot find switch backend[type:%s]", type));
}
return backend;
}
private RackPair findRack(BaremetalRct rct, String mac) {
for (BaremetalRct.Rack rack : rct.getRacks()) {
for (BaremetalRct.HostEntry host : rack.getHosts()) {
if (mac.equals(host.getMac())) {
RackPair p = new RackPair();
p.host = host;
p.rack = rack;
return p;
}
}
}
return null;
}
@Override
public String getName() {
return "Baremetal Vlan Manager";
}
@Override
public List<Class<?>> getCommands() {
List<Class<?>> cmds = new ArrayList<Class<?>>();
cmds.add(AddBaremetalRctCmd.class);
cmds.add(ListBaremetalRctCmd.class);
cmds.add(DeleteBaremetalRctCmd.class);
return cmds;
}
@Override
public boolean start() {
QueryBuilder<AccountVO> acntq = QueryBuilder.create(AccountVO.class);
acntq.and(acntq.entity().getAccountName(), SearchCriteria.Op.EQ, BaremetalUtils.BAREMETAL_SYSTEM_ACCOUNT_NAME);
AccountVO acnt = acntq.find();
if (acnt != null) {
return true;
}
acnt = new AccountVO();
acnt.setAccountName(BaremetalUtils.BAREMETAL_SYSTEM_ACCOUNT_NAME);
acnt.setUuid(UUID.randomUUID().toString());
acnt.setState(Account.State.enabled);
acnt.setDomainId(1);
acnt.setType(RoleType.User.getAccountType());
acnt.setRoleId(RoleType.User.getId());
acnt = acntDao.persist(acnt);
UserVO user = new UserVO();
user.setState(Account.State.enabled);
user.setUuid(UUID.randomUUID().toString());
user.setAccountId(acnt.getAccountId());
user.setUsername(BaremetalUtils.BAREMETAL_SYSTEM_ACCOUNT_NAME);
user.setFirstname(BaremetalUtils.BAREMETAL_SYSTEM_ACCOUNT_NAME);
user.setLastname(BaremetalUtils.BAREMETAL_SYSTEM_ACCOUNT_NAME);
user.setPassword(UUID.randomUUID().toString());
user.setSource(User.Source.UNKNOWN);
user = userDao.persist(user);
String[] keys = acntMgr.createApiKeyAndSecretKey(user.getId());
user.setApiKey(keys[0]);
user.setSecretKey(keys[1]);
userDao.update(user.getId(), user);
return true;
}
}