mirror of https://github.com/apache/cloudstack.git
veeam control changes
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
2bc3114120
commit
3460a5de99
|
|
@ -28,6 +28,7 @@ import org.apache.cloudstack.acl.RolePermissionEntity;
|
|||
import org.apache.cloudstack.acl.RoleService;
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.acl.Rule;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
|
||||
import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
|
||||
|
|
@ -70,6 +71,7 @@ import com.cloud.hypervisor.Hypervisor;
|
|||
import com.cloud.org.Grouping;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeApiService;
|
||||
import com.cloud.storage.dao.VolumeDetailsDao;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.user.AccountVO;
|
||||
|
|
@ -116,6 +118,9 @@ public class UserResourceAdapter extends ManagerBase {
|
|||
@Inject
|
||||
VolumeJoinDao volumeJoinDao;
|
||||
|
||||
@Inject
|
||||
VolumeDetailsDao volumeDetailsDao;
|
||||
|
||||
@Inject
|
||||
VolumeApiService volumeApiService;
|
||||
|
||||
|
|
@ -222,19 +227,26 @@ public class UserResourceAdapter extends ManagerBase {
|
|||
if (pool == null) {
|
||||
throw new InvalidParameterValueException("Storage domain with ID " + domain.id + " not found");
|
||||
}
|
||||
if (StringUtils.isBlank(request.provisionedSize)) {
|
||||
String sizeStr = request.provisionedSize;
|
||||
if (StringUtils.isBlank(sizeStr)) {
|
||||
throw new InvalidParameterValueException("Provisioned size must be specified");
|
||||
}
|
||||
long sizeInGb;
|
||||
long provisionedSizeInGb;
|
||||
try {
|
||||
sizeInGb = Long.parseLong(request.provisionedSize);
|
||||
provisionedSizeInGb = Long.parseLong(sizeStr);
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new InvalidParameterValueException("Invalid provisioned size: " + request.provisionedSize);
|
||||
throw new InvalidParameterValueException("Invalid provisioned size: " + sizeStr);
|
||||
}
|
||||
if (sizeInGb <= 0) {
|
||||
if (provisionedSizeInGb <= 0) {
|
||||
throw new InvalidParameterValueException("Provisioned size must be greater than zero");
|
||||
}
|
||||
sizeInGb = Math.max(1L, sizeInGb / (1024L * 1024L * 1024L));
|
||||
provisionedSizeInGb = Math.max(1L, provisionedSizeInGb / (1024L * 1024L * 1024L));
|
||||
Long initialSize = null;
|
||||
if (StringUtils.isNotBlank(request.initialSize)) {
|
||||
try {
|
||||
initialSize = Long.parseLong(request.initialSize);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
Account serviceAccount = createServiceAccountIfNeeded();
|
||||
DataCenterVO zone = dataCenterDao.findById(pool.getDataCenterId());
|
||||
if (zone == null || !Grouping.AllocationState.Enabled.equals(zone.getAllocationState())) {
|
||||
|
|
@ -246,14 +258,14 @@ public class UserResourceAdapter extends ManagerBase {
|
|||
}
|
||||
CallContext.register(serviceAccount.getId(), serviceAccount.getId());
|
||||
try {
|
||||
return createDisk(serviceAccount, pool, name, diskOfferingId, sizeInGb);
|
||||
return createDisk(serviceAccount, pool, name, diskOfferingId, provisionedSizeInGb, initialSize);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Disk createDisk(Account serviceAccount, StoragePoolVO pool, String name, Long diskOfferingId, long sizeInGb) {
|
||||
private Disk createDisk(Account serviceAccount, StoragePoolVO pool, String name, Long diskOfferingId, long sizeInGb, Long initialSize) {
|
||||
Volume volume;
|
||||
try {
|
||||
volume = volumeApiService.allocVolume(serviceAccount.getId(), pool.getDataCenterId(), diskOfferingId, null,
|
||||
|
|
@ -265,6 +277,9 @@ public class UserResourceAdapter extends ManagerBase {
|
|||
throw new CloudRuntimeException("Failed to create volume");
|
||||
}
|
||||
volume = volumeApiService.createVolume(volume.getId(), null, null, pool.getId(), true);
|
||||
if (initialSize != null) {
|
||||
volumeDetailsDao.addDetail(volume.getId(), ApiConstants.VIRTUAL_SIZE, String.valueOf(initialSize), true);
|
||||
}
|
||||
|
||||
// Implementation for creating a Disk resource
|
||||
return VolumeJoinVOToDiskConverter.toDisk(volumeJoinDao.findById(volume.getId()));
|
||||
|
|
|
|||
|
|
@ -31,12 +31,12 @@ import org.apache.cloudstack.veeam.api.dto.Cluster;
|
|||
import org.apache.cloudstack.veeam.api.dto.Clusters;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.DataCenterJoinDao;
|
||||
import com.cloud.api.query.vo.DataCenterJoinVO;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
import com.cloud.dc.dao.ClusterDao;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class ClustersRouteHandler extends ManagerBase implements RouteHandler {
|
||||
|
|
@ -76,21 +76,19 @@ public class ClustersRouteHandler extends ManagerBase implements RouteHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (idAndSubPath != null) {
|
||||
// /api/clusters/{id}
|
||||
if (idAndSubPath.first() != null) {
|
||||
if (idAndSubPath.second() == null) {
|
||||
handleGetById(idAndSubPath.first(), resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final List<Cluster> result = ClusterVOToClusterConverter.toClusterList(listClusters(), this::getZoneById);
|
||||
final Clusters response = new Clusters(result);
|
||||
|
|
@ -102,7 +100,7 @@ public class ClustersRouteHandler extends ManagerBase implements RouteHandler {
|
|||
return clusterDao.listAll();
|
||||
}
|
||||
|
||||
public void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final ClusterVO vo = clusterDao.findByUuid(id);
|
||||
if (vo == null) {
|
||||
|
|
@ -114,7 +112,7 @@ public class ClustersRouteHandler extends ManagerBase implements RouteHandler {
|
|||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
private DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
protected DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
if (zoneId == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import org.apache.cloudstack.veeam.api.dto.StorageDomain;
|
|||
import org.apache.cloudstack.veeam.api.dto.StorageDomains;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.DataCenterJoinDao;
|
||||
import com.cloud.api.query.dao.ImageStoreJoinDao;
|
||||
|
|
@ -46,7 +47,6 @@ import com.cloud.api.query.vo.ImageStoreJoinVO;
|
|||
import com.cloud.api.query.vo.StoragePoolJoinVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class DataCentersRouteHandler extends ManagerBase implements RouteHandler {
|
||||
|
|
@ -95,20 +95,20 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
|
|||
return;
|
||||
}
|
||||
|
||||
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (idAndSubPath != null) {
|
||||
// /api/datacenters/{id}
|
||||
if (idAndSubPath.first() != null) {
|
||||
if (idAndSubPath.second() == null) {
|
||||
handleGetById(idAndSubPath.first(), resp, outFormat, io);
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
} else if (idAndSubPath.size() == 2) {
|
||||
String subPath = idAndSubPath.get(1);
|
||||
if ("storagedomains".equals(subPath)) {
|
||||
handleGetStorageDomainsByDcId(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
if ("storagedomains".equals(idAndSubPath.second())) {
|
||||
handleGetStorageDomainsByDcId(idAndSubPath.first(), resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
if ("networks".equals(idAndSubPath.second())) {
|
||||
handleGetNetworksByDcId(idAndSubPath.first(), resp, outFormat, io);
|
||||
if ("networks".equals(subPath)) {
|
||||
handleGetNetworksByDcId(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
|
|||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final List<DataCenter> result = DataCenterJoinVOToDataCenterConverter.toDCList(listDCs());
|
||||
final DataCenters response = new DataCenters(result);
|
||||
|
|
@ -129,7 +129,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
|
|||
return dataCenterJoinDao.listAll();
|
||||
}
|
||||
|
||||
public void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.findByUuid(id);
|
||||
if (dataCenterVO == null) {
|
||||
|
|
@ -153,7 +153,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
|
|||
return networkDao.listAll();
|
||||
}
|
||||
|
||||
public void handleGetStorageDomainsByDcId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetStorageDomainsByDcId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.findByUuid(id);
|
||||
if (dataCenterVO == null) {
|
||||
|
|
@ -168,7 +168,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
|
|||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
public void handleGetNetworksByDcId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetNetworksByDcId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.findByUuid(id);
|
||||
if (dataCenterVO == null) {
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ import org.apache.cloudstack.veeam.api.dto.Disk;
|
|||
import org.apache.cloudstack.veeam.api.dto.Disks;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
|
@ -78,21 +78,19 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler {
|
|||
io.methodNotAllowed(resp, "GET", outFormat);
|
||||
return;
|
||||
}
|
||||
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (idAndSubPath != null) {
|
||||
// /api/disks/{id}
|
||||
if (idAndSubPath.first() != null) {
|
||||
if (idAndSubPath.second() == null) {
|
||||
handleGetById(idAndSubPath.first(), resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final List<Disk> result = userResourceAdapter.listAllDisks();
|
||||
final Disks response = new Disks(result);
|
||||
|
|
@ -100,7 +98,7 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler {
|
|||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
public void handlePost(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handlePost(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
String data = RouteHandler.getRequestData(req);
|
||||
logger.info("Received POST request on /api/disks endpoint, but method: POST is not supported atm. Request-data: {}", data);
|
||||
|
|
@ -113,7 +111,7 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler {
|
|||
}
|
||||
}
|
||||
|
||||
public void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
Disk response = userResourceAdapter.getDisk(id);
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ import org.apache.cloudstack.veeam.api.dto.Host;
|
|||
import org.apache.cloudstack.veeam.api.dto.Hosts;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.HostJoinDao;
|
||||
import com.cloud.api.query.vo.HostJoinVO;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class HostsRouteHandler extends ManagerBase implements RouteHandler {
|
||||
|
|
@ -71,21 +71,19 @@ public class HostsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (idAndSubPath != null) {
|
||||
// /api/hosts/{id}
|
||||
if (idAndSubPath.first() != null) {
|
||||
if (idAndSubPath.second() == null) {
|
||||
handleGetById(idAndSubPath.first(), resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final List<Host> result = HostJoinVOToHostConverter.toHostList(listHosts());
|
||||
final Hosts response = new Hosts(result);
|
||||
|
|
@ -97,7 +95,7 @@ public class HostsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
return hostJoinDao.listAll();
|
||||
}
|
||||
|
||||
public void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final HostJoinVO vo = hostJoinDao.findByUuid(id);
|
||||
if (vo == null) {
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ import org.apache.cloudstack.veeam.api.dto.ImageTransfer;
|
|||
import org.apache.cloudstack.veeam.api.dto.ImageTransfers;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
|
@ -73,17 +73,28 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!"GET".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET", outFormat);
|
||||
return;
|
||||
}
|
||||
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (idAndSubPath != null) {
|
||||
// /api/imagetransfers/{id}
|
||||
if (idAndSubPath.first() != null) {
|
||||
if (idAndSubPath.second() == null) {
|
||||
handleGetById(idAndSubPath.first(), resp, outFormat, io);
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
if (!"GET".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET", outFormat);
|
||||
return;
|
||||
}
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
} else if (idAndSubPath.size() == 2) {
|
||||
if (!"POST".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "POST", outFormat);
|
||||
return;
|
||||
}
|
||||
String subPath = idAndSubPath.get(1);
|
||||
if ("cancel".equals(subPath)) {
|
||||
handleCancelById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
if ("finalize".equals(subPath)) {
|
||||
handleFinalizeById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +103,7 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand
|
|||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final List<ImageTransfer> result = userResourceAdapter.listAllImageTransfers();
|
||||
final ImageTransfers response = new ImageTransfers();
|
||||
|
|
@ -101,10 +112,10 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand
|
|||
io.getWriter().write(resp, 400, response, outFormat);
|
||||
}
|
||||
|
||||
public void handlePost(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handlePost(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
String data = RouteHandler.getRequestData(req);
|
||||
logger.info("Received POST request on /api/imagetransfers endpoint, but method: POST is not supported atm. Request-data: {}", data);
|
||||
logger.info("Received POST request on /api/imagetransfers endpoint. Request-data: {}", data);
|
||||
try {
|
||||
ImageTransfer request = io.getMapper().jsonMapper().readValue(data, ImageTransfer.class);
|
||||
ImageTransfer response = userResourceAdapter.handleCreateImageTransfer(request);
|
||||
|
|
@ -114,7 +125,7 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand
|
|||
}
|
||||
}
|
||||
|
||||
public void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
ImageTransfer response = userResourceAdapter.getImageTransfer(id);
|
||||
|
|
@ -123,4 +134,16 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand
|
|||
io.getWriter().write(resp, 404, e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleCancelById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
//ToDo: implement cancel logic
|
||||
io.getWriter().write(resp, 200, "Image transfer cancelled successfully", outFormat);
|
||||
}
|
||||
|
||||
protected void handleFinalizeById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
//ToDo: implement finalize logic
|
||||
io.getWriter().write(resp, 200, "Image transfer finalized successfully", outFormat);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,12 +31,12 @@ import org.apache.cloudstack.veeam.api.dto.Network;
|
|||
import org.apache.cloudstack.veeam.api.dto.Networks;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.DataCenterJoinDao;
|
||||
import com.cloud.api.query.vo.DataCenterJoinVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class NetworksRouteHandler extends ManagerBase implements RouteHandler {
|
||||
|
|
@ -76,21 +76,19 @@ public class NetworksRouteHandler extends ManagerBase implements RouteHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (idAndSubPath != null) {
|
||||
// /api/networks/{id}
|
||||
if (idAndSubPath.first() != null) {
|
||||
if (idAndSubPath.second() == null) {
|
||||
handleGetById(idAndSubPath.first(), resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final List<Network> result = NetworkVOToNetworkConverter.toNetworkList(listNetworks(), this::getZoneById);
|
||||
final Networks response = new Networks(result);
|
||||
|
|
@ -102,7 +100,7 @@ public class NetworksRouteHandler extends ManagerBase implements RouteHandler {
|
|||
return networkDao.listAll();
|
||||
}
|
||||
|
||||
public void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final NetworkVO vo = networkDao.findByUuid(id);
|
||||
if (vo == null) {
|
||||
|
|
@ -114,7 +112,7 @@ public class NetworksRouteHandler extends ManagerBase implements RouteHandler {
|
|||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
private DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
protected DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
if (zoneId == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,13 +40,13 @@ import org.apache.cloudstack.veeam.api.response.VmCollectionResponse;
|
|||
import org.apache.cloudstack.veeam.api.response.VmEntityResponse;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.HostJoinDao;
|
||||
import com.cloud.api.query.dao.UserVmJoinDao;
|
||||
import com.cloud.api.query.dao.VolumeJoinDao;
|
||||
import com.cloud.api.query.vo.HostJoinVO;
|
||||
import com.cloud.api.query.vo.UserVmJoinVO;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
||||
|
|
@ -97,16 +97,17 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
handleGet(req, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (idAndSubPath != null) {
|
||||
// /api/vms/{id}
|
||||
if (idAndSubPath.first() != null) {
|
||||
if (idAndSubPath.second() == null) {
|
||||
handleGetById(idAndSubPath.first(), resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
if ("diskattachments".equals(idAndSubPath.second())) {
|
||||
handleGetDisAttachmentsByVmId(idAndSubPath.first(), resp, outFormat, io);
|
||||
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
} else if (idAndSubPath.size() == 2) {
|
||||
String subPath = idAndSubPath.get(1);
|
||||
if ("diskattachments".equals(subPath)) {
|
||||
handleGetDisAttachmentsByVmId(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -115,7 +116,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final VmListQuery q = fromRequest(req);
|
||||
|
||||
|
|
@ -154,7 +155,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
private static VmListQuery fromRequest(final HttpServletRequest req) {
|
||||
protected static VmListQuery fromRequest(final HttpServletRequest req) {
|
||||
final VmListQuery q = new VmListQuery();
|
||||
q.setSearch(req.getParameter("search"));
|
||||
q.setMax(parseIntOrNull(req.getParameter("max")));
|
||||
|
|
@ -162,7 +163,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
return q;
|
||||
}
|
||||
|
||||
private static Integer parseIntOrNull(final String s) {
|
||||
protected static Integer parseIntOrNull(final String s) {
|
||||
if (s == null || s.trim().isEmpty()) return null;
|
||||
try {
|
||||
return Integer.parseInt(s.trim());
|
||||
|
|
@ -176,7 +177,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
return userVmJoinDao.listAll();
|
||||
}
|
||||
|
||||
public void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final UserVmJoinVO userVmJoinVO = userVmJoinDao.findByUuid(id);
|
||||
if (userVmJoinVO == null) {
|
||||
|
|
@ -188,7 +189,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
public void handleGetDisAttachmentsByVmId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetDisAttachmentsByVmId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final UserVmJoinVO userVmJoinVO = userVmJoinDao.findByUuid(id);
|
||||
if (userVmJoinVO == null) {
|
||||
|
|
@ -202,7 +203,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
private HostJoinVO getHostById(Long hostId) {
|
||||
protected HostJoinVO getHostById(Long hostId) {
|
||||
if (hostId == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,12 +31,12 @@ import org.apache.cloudstack.veeam.api.dto.VnicProfile;
|
|||
import org.apache.cloudstack.veeam.api.dto.VnicProfiles;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.DataCenterJoinDao;
|
||||
import com.cloud.api.query.vo.DataCenterJoinVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class VnicProfilesRouteHandler extends ManagerBase implements RouteHandler {
|
||||
|
|
@ -76,21 +76,19 @@ public class VnicProfilesRouteHandler extends ManagerBase implements RouteHandle
|
|||
return;
|
||||
}
|
||||
|
||||
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (idAndSubPath != null) {
|
||||
// /api/vnicprofiles/{id}
|
||||
if (idAndSubPath.first() != null) {
|
||||
if (idAndSubPath.second() == null) {
|
||||
handleGetById(idAndSubPath.first(), resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final List<VnicProfile> result = NetworkVOToVnicProfileConverter.toVnicProfileList(listNetworks(), this::getZoneById);
|
||||
final VnicProfiles response = new VnicProfiles(result);
|
||||
|
|
@ -102,7 +100,7 @@ public class VnicProfilesRouteHandler extends ManagerBase implements RouteHandle
|
|||
return networkDao.listAll();
|
||||
}
|
||||
|
||||
public void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final NetworkVO vo = networkDao.findByUuid(id);
|
||||
if (vo == null) {
|
||||
|
|
@ -114,7 +112,7 @@ public class VnicProfilesRouteHandler extends ManagerBase implements RouteHandle
|
|||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
private DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
protected DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
if (zoneId == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.apache.cloudstack.veeam.VeeamControlService;
|
|||
import org.apache.cloudstack.veeam.api.DisksRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.HostsRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.ImageTransfersRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.dto.Actions;
|
||||
import org.apache.cloudstack.veeam.api.dto.ImageTransfer;
|
||||
import org.apache.cloudstack.veeam.api.dto.Link;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ref;
|
||||
|
|
@ -41,11 +42,16 @@ public class ImageTransferVOToImageTransferConverter {
|
|||
final String basePath = VeeamControlService.ContextPath.value();
|
||||
imageTransfer.setId(vo.getUuid());
|
||||
imageTransfer.setHref(basePath + ImageTransfersRouteHandler.BASE_ROUTE + "/" + vo.getUuid());
|
||||
imageTransfer.setActive(Boolean.toString(true));
|
||||
imageTransfer.setActive(Boolean.toString(vo.getProgress() != null && vo.getProgress() > 0 && vo.getProgress() < 100));
|
||||
imageTransfer.setDirection(vo.getDirection().name());
|
||||
imageTransfer.setFormat("cow");
|
||||
imageTransfer.setInactivityTimeout(Integer.toString(60));
|
||||
imageTransfer.setInactivityTimeout(Integer.toString(3600));
|
||||
imageTransfer.setPhase(vo.getPhase().name());
|
||||
if (org.apache.cloudstack.backup.ImageTransfer.Phase.finished.equals(vo.getPhase())) {
|
||||
imageTransfer.setPhase("finished_success");
|
||||
} else if (org.apache.cloudstack.backup.ImageTransfer.Phase.failed.equals(vo.getPhase())) {
|
||||
imageTransfer.setPhase("finished_failed");
|
||||
}
|
||||
imageTransfer.setProxyUrl(vo.getTransferUrl());
|
||||
imageTransfer.setShallow(Boolean.toString(false));
|
||||
imageTransfer.setTimeoutPolicy("legacy");
|
||||
|
|
@ -61,14 +67,13 @@ public class ImageTransferVOToImageTransferConverter {
|
|||
VolumeJoinVO volumeVo = volumeResolver.apply(vo.getDiskId());
|
||||
if (volumeVo != null) {
|
||||
imageTransfer.setDisk(Ref.of(basePath + DisksRouteHandler.BASE_ROUTE + "/" + volumeVo.getUuid(), volumeVo.getUuid()));
|
||||
imageTransfer.setImage(Ref.of(null, volumeVo.getUuid()));
|
||||
}
|
||||
}
|
||||
final List<Link> links = new ArrayList<>();
|
||||
links.add(getLink(imageTransfer, "cancel"));
|
||||
links.add(getLink(imageTransfer, "resume"));
|
||||
links.add(getLink(imageTransfer, "pause"));
|
||||
links.add(getLink(imageTransfer, "finalize"));
|
||||
links.add(getLink(imageTransfer, "extend"));
|
||||
imageTransfer.setActions(new Actions(links));
|
||||
return imageTransfer;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,173 @@
|
|||
// 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 org.apache.cloudstack.veeam.services;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.cloudstack.utils.server.ServerPropertiesUtil;
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class PkiResourceRouteHandler extends ManagerBase implements RouteHandler {
|
||||
private static final String BASE_ROUTE = "/services/pki-resource";
|
||||
private static final String RESOURCE_KEY = "resource";
|
||||
private static final String RESOURCE_VALUE = "ca-certificate";
|
||||
private static final String FORMAT_KEY = "format";
|
||||
private static final String FORMAT_VALUE = "X509-PEM-CA";
|
||||
private static final Charset OUTPUT_CHARSET = StandardCharsets.ISO_8859_1;
|
||||
|
||||
@Override
|
||||
public boolean canHandle(String method, String path) {
|
||||
return getSanitizedPath(path).startsWith(BASE_ROUTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest req, HttpServletResponse resp, String path, Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final String sanitizedPath = getSanitizedPath(path);
|
||||
if (sanitizedPath.equals(BASE_ROUTE) && "GET".equalsIgnoreCase(req.getMethod())) {
|
||||
handleGet(req, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
|
||||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
protected void handleGet(HttpServletRequest req, HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
final String resource = req.getParameter(RESOURCE_KEY);
|
||||
final String format = req.getParameter(FORMAT_KEY);
|
||||
|
||||
if (StringUtils.isNotBlank(resource) && !RESOURCE_VALUE.equals(resource)) {
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unsupported resource");
|
||||
return;
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(format) && !FORMAT_VALUE.equals(format)) {
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unsupported format");
|
||||
return;
|
||||
}
|
||||
|
||||
final String keystorePath = ServerPropertiesUtil.getKeystoreFile();
|
||||
final String keystorePassword = ServerPropertiesUtil.getKeystorePassword();
|
||||
|
||||
Path path = Path.of(keystorePath);
|
||||
if (keystorePath.isBlank() || !Files.exists(path)) {
|
||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "CloudStack HTTPS keystore not found");
|
||||
return;
|
||||
}
|
||||
|
||||
final X509Certificate caCert =
|
||||
extractCaFromKeystore(path, keystorePassword);
|
||||
|
||||
// DER encoding → browser downloads as .cer (oVirt behavior)
|
||||
final byte[] pemBytes =
|
||||
toPem(caCert).getBytes(OUTPUT_CHARSET);
|
||||
resp.setStatus(HttpServletResponse.SC_OK);
|
||||
resp.setHeader("Cache-Control", "no-store");
|
||||
resp.setContentType("application/x-x509-ca-cert; charset=" + OUTPUT_CHARSET.name());
|
||||
resp.setHeader("Content-Disposition",
|
||||
"attachment; filename=\"pki-resource.cer\"");
|
||||
resp.setContentLength(pemBytes.length);
|
||||
|
||||
try (OutputStream os = resp.getOutputStream()) {
|
||||
os.write(pemBytes);
|
||||
}
|
||||
} catch (IOException | KeyStoreException | CertificateException | NoSuchAlgorithmException e) {
|
||||
String msg = "Failed to retrieve server CA certificate";
|
||||
logger.error(msg, e);
|
||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static X509Certificate extractCaFromKeystore(Path ksPath, String ksPassword)
|
||||
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
|
||||
|
||||
final String path = ksPath.toString().toLowerCase();
|
||||
final String storeType =
|
||||
(path.endsWith(".p12") || path.endsWith(".pfx"))
|
||||
? "PKCS12"
|
||||
: KeyStore.getDefaultType();
|
||||
|
||||
KeyStore ks = KeyStore.getInstance(storeType);
|
||||
try (var in = Files.newInputStream(ksPath)) {
|
||||
ks.load(in, ksPassword != null ? ksPassword.toCharArray() : new char[0]);
|
||||
}
|
||||
|
||||
// Prefer HTTPS keypair alias (one with a chain)
|
||||
String alias = null;
|
||||
Enumeration<String> aliases = ks.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String a = aliases.nextElement();
|
||||
Certificate[] chain = ks.getCertificateChain(a);
|
||||
if (chain != null && chain.length > 0) {
|
||||
alias = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alias == null && ks.aliases().hasMoreElements()) {
|
||||
alias = ks.aliases().nextElement();
|
||||
}
|
||||
|
||||
if (alias == null) {
|
||||
throw new IllegalStateException("No certificate aliases in keystore");
|
||||
}
|
||||
|
||||
Certificate[] chain = ks.getCertificateChain(alias);
|
||||
Certificate cert =
|
||||
(chain != null && chain.length > 0)
|
||||
? chain[chain.length - 1] // root-most
|
||||
: ks.getCertificate(alias);
|
||||
|
||||
if (!(cert instanceof X509Certificate)) {
|
||||
throw new IllegalStateException("Certificate is not X509");
|
||||
}
|
||||
|
||||
return (X509Certificate) cert;
|
||||
}
|
||||
|
||||
private static String toPem(X509Certificate cert) throws CertificateEncodingException {
|
||||
String base64 = Base64.getMimeEncoder(64, new byte[]{'\n'})
|
||||
.encodeToString(cert.getEncoded());
|
||||
return "-----BEGIN CERTIFICATE-----\n"
|
||||
+ base64
|
||||
+ "\n-----END CERTIFICATE-----\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -17,46 +17,58 @@
|
|||
|
||||
package org.apache.cloudstack.veeam.utils;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.utils.UuidUtils;
|
||||
|
||||
public class PathUtil {
|
||||
|
||||
public static Pair<String, String> extractIdAndSubPath(final String path, final String baseRoute) {
|
||||
public static List<String> extractIdAndSubPath(final String path, final String baseRoute) {
|
||||
|
||||
// baseRoute = "/api/datacenters"
|
||||
if (!path.startsWith(baseRoute)) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isBlank(path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Remove base route
|
||||
String rest = path.substring(baseRoute.length());
|
||||
// Remove base route (be tolerant of trailing slash in baseRoute)
|
||||
String rest = path;
|
||||
if (StringUtils.isNotBlank(baseRoute)) {
|
||||
String normalizedBase = baseRoute.endsWith("/") && baseRoute.length() > 1
|
||||
? baseRoute.substring(0, baseRoute.length() - 1)
|
||||
: baseRoute;
|
||||
if (rest.startsWith(normalizedBase)) {
|
||||
rest = rest.substring(normalizedBase.length());
|
||||
}
|
||||
}
|
||||
|
||||
// Expect "" or "/{id}" or "/{id}/{sub}"
|
||||
if (rest.isEmpty()) {
|
||||
return null; // /api/datacenters (no id)
|
||||
}
|
||||
// Expect "/{id}" or "/{id}/..." (no empty segments)
|
||||
if (StringUtils.isBlank(rest) || !rest.startsWith("/")) {
|
||||
return null; // /api/datacenters (no id) or invalid format
|
||||
}
|
||||
|
||||
if (!rest.startsWith("/")) {
|
||||
return null;
|
||||
}
|
||||
rest = rest.substring(1); // remove leading '/'
|
||||
|
||||
rest = rest.substring(1); // remove leading '/'
|
||||
if (StringUtils.isBlank(rest)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String[] parts = rest.split("/", -1);
|
||||
final String[] parts = rest.split("/", -1);
|
||||
|
||||
if (parts.length == 1) {
|
||||
// /api/datacenters/{id}
|
||||
if (parts[0].isEmpty()) return null;
|
||||
return new Pair<>(parts[0], null);
|
||||
}
|
||||
// Collect non-blank segments
|
||||
List<String> validParts = new ArrayList<>();
|
||||
for (String part : parts) {
|
||||
if (StringUtils.isNotBlank(part)) {
|
||||
validParts.add(part);
|
||||
}
|
||||
}
|
||||
|
||||
if (parts.length == 2) {
|
||||
// /api/datacenters/{id}/{subPath}
|
||||
if (parts[0].isEmpty() || parts[1].isEmpty()) return null;
|
||||
return new Pair<>(parts[0], parts[1]);
|
||||
}
|
||||
// Validate first segment is a UUID
|
||||
if (validParts.isEmpty() || !UuidUtils.isUuid(validParts.get(0))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// deeper paths not handled here
|
||||
return null;
|
||||
return validParts;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
</bean>
|
||||
|
||||
<bean id="veeamControlSsoService" class="org.apache.cloudstack.veeam.sso.SsoService"/>
|
||||
<bean id="pkiResourceRouteHandler" class="org.apache.cloudstack.veeam.services.PkiResourceRouteHandler"/>
|
||||
<bean id="veeamControlApiService" class="org.apache.cloudstack.veeam.api.ApiService" />
|
||||
<bean id="dataCentersRouteHandler" class="org.apache.cloudstack.veeam.api.DataCentersRouteHandler"/>
|
||||
<bean id="clustersRouteHandler" class="org.apache.cloudstack.veeam.api.ClustersRouteHandler"/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue