Skip to content

Commit 5184929

Browse files
New changes
1 parent 45f6735 commit 5184929

File tree

19 files changed

+538
-80
lines changed

19 files changed

+538
-80
lines changed

api/src/main/java/org/apache/cloudstack/api/command/admin/host/AddHostCmd.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,27 @@ public Long getExtensionId() {
155155
}
156156

157157
public Map<String, String> getExternalDetails() {
158-
Map<String, String> customparameterMap = convertDetailsToMap(externalDetails);
159-
Map<String, String> details = new HashMap<>();
160-
for (String key : customparameterMap.keySet()) {
161-
String value = customparameterMap.get(key);
162-
details.put(VmDetailConstants.EXTERNAL_DETAIL_PREFIX + key, value);
158+
boolean isstringmap = true;
159+
if (externaldetails instanceof map<?, ?>) {
160+
for (map.entry<?, ?> entry : ((map<?, ?>) externaldetails).entryset()) {
161+
if (!(entry.getkey() instanceof string) || !(entry.getvalue() instanceof string)) {
162+
isstringmap = false;
163+
break;
164+
}
165+
}
166+
}
167+
168+
if (!isstringmap) {
169+
map<string, string> customparametermap = convertdetailstomap(externaldetails);
170+
map<string, string> details = new hashmap<>();
171+
for (string key : customparametermap.keyset()) {
172+
string value = customparametermap.get(key);
173+
details.put(vmdetailconstants.external_detail_prefix + key, value);
174+
}
175+
return details;
163176
}
164-
return details;
177+
178+
return externaldetails;
165179
}
166180

167181
/////////////////////////////////////////////////////

engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,9 @@ CREATE TABLE IF NOT EXISTS `cloud`.`extension` (
4545
`uuid` varchar(40) NOT NULL UNIQUE,
4646
`name` varchar(255) NOT NULL,
4747
`type` varchar(255) NOT NULL,
48-
`pod_id` bigint unsigned NOT NULL,
4948
`created` datetime NOT NULL,
5049
`removed` datetime DEFAULT NULL,
51-
PRIMARY KEY (`id`),
52-
CONSTRAINT `fk_extension__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `cloud`.`host_pod_ref`(`id`) ON DELETE CASCADE
50+
PRIMARY KEY (`id`)
5351
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
5452

5553
CREATE TABLE `cloud`.`extension_details` (
@@ -62,3 +60,27 @@ CREATE TABLE `cloud`.`extension_details` (
6260
CONSTRAINT `fk_extension_details__extension_id` FOREIGN KEY (`extension_id`)
6361
REFERENCES `extension` (`id`) ON DELETE CASCADE
6462
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
63+
64+
CREATE TABLE IF NOT EXISTS `cloud`.`extension_resource_map` (
65+
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
66+
`extension_id` bigint(20) unsigned NOT NULL,
67+
`resource_id` bigint(20) unsigned NOT NULL,
68+
`resource_type` varchar(255) NOT NULL,
69+
`created` datetime NOT NULL,
70+
`removed` datetime DEFAULT NULL,
71+
PRIMARY KEY (`id`),
72+
CONSTRAINT `fk_extension_resource_map__extension_id` FOREIGN KEY (`extension_id`)
73+
REFERENCES `cloud`.`extension`(`id`) ON DELETE CASCADE,
74+
INDEX `idx_extension_resource` (`resource_id`, `resource_type`),
75+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
76+
77+
CREATE TABLE `cloud`.`extension_resource_map_details` (
78+
`id` bigint unsigned UNIQUE NOT NULL AUTO_INCREMENT COMMENT 'id',
79+
`extension_resource_map_id` bigint unsigned NOT NULL COMMENT 'mapping to which the detail is related',
80+
`name` varchar(255) NOT NULL COMMENT 'name of the detail',
81+
`value` varchar(255) NOT NULL COMMENT 'value of the detail',
82+
`display` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'True if the detail can be displayed to the end user',
83+
PRIMARY KEY (`id`),
84+
CONSTRAINT `fk_extension_resource_map_details__map_id` FOREIGN KEY (`extension_resource_map_id`)
85+
REFERENCES `extension_resource_map` (`id`) ON DELETE CASCADE
86+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

plugins/hypervisors/external/src/main/java/com/cloud/agent/manager/ExternalAgentManager.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.cloud.hypervisor.ExternalProvisioner;
2222
import com.cloud.hypervisor.external.provisioner.api.ExtensionResponse;
2323
import com.cloud.hypervisor.external.provisioner.api.ListExtensionsCmd;
24+
import com.cloud.hypervisor.external.provisioner.api.CreateExtensionCmd;
2425
import com.cloud.hypervisor.external.provisioner.api.RegisterExtensionCmd;
2526
import com.cloud.hypervisor.external.provisioner.api.RunCustomActionCmd;
2627
import com.cloud.hypervisor.external.provisioner.vo.Extension;
@@ -43,7 +44,9 @@ public interface ExternalAgentManager extends Manager {
4344

4445
RunCustomActionAnswer runCustomAction(RunCustomActionCmd cmd);
4546

46-
Extension registerExternalOrchestrator(RegisterExtensionCmd cmd);
47+
Extension createExtension(CreateExtensionCmd cmd);
4748

4849
List<ExtensionResponse> listExtensions(ListExtensionsCmd cmd);
50+
51+
boolean registerExtensionWithResource(RegisterExtensionCmd cmd);
4952
}

plugins/hypervisors/external/src/main/java/com/cloud/agent/manager/ExternalAgentManagerImpl.java

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,18 @@
3737
import com.cloud.hypervisor.HypervisorGuruManagerImpl;
3838
import com.cloud.hypervisor.external.provisioner.api.ExtensionResponse;
3939
import com.cloud.hypervisor.external.provisioner.api.ListExtensionsCmd;
40+
import com.cloud.hypervisor.external.provisioner.api.CreateExtensionCmd;
4041
import com.cloud.hypervisor.external.provisioner.api.RegisterExtensionCmd;
4142
import com.cloud.hypervisor.external.provisioner.api.RunCustomActionCmd;
43+
import com.cloud.hypervisor.external.provisioner.dao.ExtensionResourceMapDao;
44+
import com.cloud.hypervisor.external.provisioner.dao.ExtensionResourceMapDetailsDao;
4245
import com.cloud.hypervisor.external.provisioner.dao.ExternalOrchestratorDao;
4346
import com.cloud.hypervisor.external.provisioner.dao.ExternalOrchestratorDetailDao;
44-
import com.cloud.hypervisor.external.provisioner.dao.ExternalOrchestratorDetailVO;
47+
import com.cloud.hypervisor.external.provisioner.vo.ExtensionResourceMapDetailsVO;
48+
import com.cloud.hypervisor.external.provisioner.vo.ExternalOrchestratorDetailVO;
4549
import com.cloud.hypervisor.external.provisioner.simpleprovisioner.SimpleExternalProvisioner;
4650
import com.cloud.hypervisor.external.provisioner.vo.Extension;
51+
import com.cloud.hypervisor.external.provisioner.vo.ExtensionResourceMapVO;
4752
import com.cloud.hypervisor.external.provisioner.vo.ExtensionVO;
4853
import com.cloud.hypervisor.external.resource.ExternalResourceBase;
4954
import com.cloud.org.Cluster;
@@ -82,6 +87,12 @@ public class ExternalAgentManagerImpl extends ManagerBase implements ExternalAge
8287
@Inject
8388
ExternalOrchestratorDetailDao externalOrchestratorDetailDao;
8489

90+
@Inject
91+
ExtensionResourceMapDao extensionResourceMapDao;
92+
93+
@Inject
94+
ExtensionResourceMapDetailsDao extensionResourceMapDetailsDao;
95+
8596
@Inject
8697
HostPodDao podDao;
8798

@@ -123,6 +134,7 @@ public boolean start() {
123134
public List<Class<?>> getCommands() {
124135
List<Class<?>> cmds = new ArrayList<Class<?>>();
125136
cmds.add(RunCustomActionCmd.class);
137+
cmds.add(CreateExtensionCmd.class);
126138
cmds.add(RegisterExtensionCmd.class);
127139
cmds.add(ListExtensionsCmd.class);
128140
return cmds;
@@ -191,11 +203,10 @@ public RunCustomActionAnswer runCustomAction(RunCustomActionCmd cmd) {
191203
}
192204

193205
@Override
194-
public Extension registerExternalOrchestrator(RegisterExtensionCmd cmd) {
206+
public Extension createExtension(CreateExtensionCmd cmd) {
195207
ExtensionVO extension = new ExtensionVO();
196208
extension.setName(cmd.getName());
197209
extension.setType(cmd.getType());
198-
extension.setPodId(cmd.getPodId());
199210
ExtensionVO savedExtension = externalOrchestratorDao.persist(extension);
200211

201212
Map<String, String> externalDetails = cmd.getExternalDetails();
@@ -207,8 +218,6 @@ public Extension registerExternalOrchestrator(RegisterExtensionCmd cmd) {
207218
externalOrchestratorDetailDao.saveDetails(detailsVOList);
208219
}
209220

210-
createRequiredResourcesForExtension(savedExtension, cmd);
211-
212221
return savedExtension;
213222
}
214223

@@ -241,7 +250,7 @@ public List<ExtensionResponse> listExtensions(ListExtensionsCmd cmd) {
241250
List<ExtensionResponse> responses = new ArrayList<>();
242251
for (ExtensionVO extension : result.first()) {
243252
Map<String, String> details = externalOrchestratorDetailDao.listDetailsKeyPairs(extension.getId());
244-
ExtensionResponse response = new ExtensionResponse(extension.getName(), extension.getType(), extension.getPodId(), extension.getUuid(), details);
253+
ExtensionResponse response = new ExtensionResponse(extension.getName(), extension.getType(), extension.getUuid(), details);
245254
String destinationPath = String.format(SimpleExternalProvisioner.EXTENSION_SCRIPT_PATH, extension.getId());
246255
response.setScriptPath(destinationPath);
247256
response.setObjectName(ApiConstants.EXTENSIONS);
@@ -251,9 +260,48 @@ public List<ExtensionResponse> listExtensions(ListExtensionsCmd cmd) {
251260
return responses;
252261
}
253262

254-
private void createRequiredResourcesForExtension(ExtensionVO extension, RegisterExtensionCmd registerExtensionCmd) {
255-
String clusterName = extension.getName() + "-" + extension.getId() + "-cluster";
256-
HostPodVO pod = podDao.findById(extension.getPodId());
263+
@Override
264+
public boolean registerExtensionWithResource(RegisterExtensionCmd cmd) {
265+
String resourceId = cmd.getResourceId();
266+
Long extensionId = cmd.getExtensionId();
267+
String resourceType = cmd.getResourceType();
268+
if ("POD".equalsIgnoreCase(resourceType)) {
269+
HostPodVO pod = podDao.findByUuid(resourceId);
270+
ExtensionResourceMapVO extensionMap = new ExtensionResourceMapVO();
271+
extensionMap.setExtensionId(extensionId);
272+
extensionMap.setResourceId(pod.getId());
273+
extensionMap.setResourceType(resourceType);
274+
ExtensionResourceMapVO savedExtensionMap = extensionResourceMapDao.persist(extensionMap);
275+
276+
Map<String, String> externalDetails = cmd.getExternalDetails();
277+
List<ExtensionResourceMapDetailsVO> detailsVOList = new ArrayList<>();
278+
if (externalDetails != null && !externalDetails.isEmpty()) {
279+
for (Map.Entry<String, String> entry : externalDetails.entrySet()) {
280+
detailsVOList.add(new ExtensionResourceMapDetailsVO(savedExtensionMap.getId(), entry.getKey(), entry.getValue()));
281+
}
282+
extensionResourceMapDetailsDao.saveDetails(detailsVOList);
283+
}
284+
createRequiredResourcesForExtensionInPod(cmd, savedExtensionMap);
285+
} else {
286+
throw new CloudRuntimeException("Currently only pod can be used to register an extension of type Orchestrator");
287+
}
288+
289+
return true;
290+
}
291+
292+
private void createRequiredResourcesForExtensionInPod(RegisterExtensionCmd cmd, ExtensionResourceMapVO extensionResourceMap) {
293+
String resourceId = cmd.getResourceId();
294+
Long extensionId = cmd.getExtensionId();
295+
ExtensionVO extension = externalOrchestratorDao.findById(extensionId);
296+
297+
Map<String, String> details = new HashMap<>();
298+
Map<String, String> externalDetails = cmd.getExternalDetails();
299+
Map<String, String> extensionDetails = externalOrchestratorDetailDao.listDetailsKeyPairs(extensionId);
300+
details.putAll(extensionDetails);
301+
details.putAll(externalDetails);
302+
303+
String clusterName = extension.getName() + "-" + extension.getId() + "-" + extensionResourceMap.getId() + "-cluster";
304+
HostPodVO pod = podDao.findByUuid(resourceId);
257305
AddClusterCmd clusterCmd = new AddClusterCmd(clusterName, pod.getDataCenterId(), pod.getId(), Cluster.ClusterType.CloudManaged.toString(),
258306
Hypervisor.HypervisorType.External.toString(), SimpleExternalProvisioner.class.getSimpleName());
259307
List<? extends Cluster> clusters;
@@ -265,9 +313,9 @@ private void createRequiredResourcesForExtension(ExtensionVO extension, Register
265313

266314
Cluster cluster = clusters.get(0);
267315

268-
String hosturl = "http://" + extension.getName() + "-" + extension.getId() + "-host";
316+
String hosturl = "http://" + extension.getName() + "-" + extension.getId() + "-" + extensionResourceMap.getId() + "-host";
269317
AddHostCmd addHostCmd = new AddHostCmd(pod.getDataCenterId(), pod.getId(), cluster.getId(), Hypervisor.HypervisorType.External.toString(),
270-
"External", "External", hosturl, registerExtensionCmd.getDetails(), extension.getId());
318+
"External", "External", hosturl, details, extension.getId());
271319

272320
List<? extends Host> hosts;
273321
try {
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package com.cloud.hypervisor.external.provisioner.api;
19+
20+
import com.cloud.agent.manager.ExternalAgentManager;
21+
import com.cloud.exception.ConcurrentOperationException;
22+
import com.cloud.exception.InsufficientCapacityException;
23+
import com.cloud.exception.NetworkRuleConflictException;
24+
import com.cloud.exception.ResourceAllocationException;
25+
import com.cloud.exception.ResourceUnavailableException;
26+
import com.cloud.hypervisor.external.provisioner.simpleprovisioner.SimpleExternalProvisioner;
27+
import com.cloud.hypervisor.external.provisioner.vo.Extension;
28+
import com.cloud.user.Account;
29+
import com.cloud.vm.VmDetailConstants;
30+
import org.apache.cloudstack.api.APICommand;
31+
import org.apache.cloudstack.api.ApiConstants;
32+
import org.apache.cloudstack.api.BaseCmd;
33+
import org.apache.cloudstack.api.Parameter;
34+
import org.apache.cloudstack.api.ServerApiException;
35+
import org.apache.cloudstack.api.response.SuccessResponse;
36+
37+
import javax.inject.Inject;
38+
import java.util.HashMap;
39+
import java.util.Map;
40+
41+
@APICommand(name = CreateExtensionCmd.APINAME, description = "create the external extension",
42+
responseObject = SuccessResponse.class, responseHasSensitiveInfo = false, since = "4.21.0")
43+
public class CreateExtensionCmd extends BaseCmd {
44+
45+
@Inject
46+
ExternalAgentManager _externalMgr;
47+
48+
public static final String APINAME = "createExtension";
49+
50+
/////////////////////////////////////////////////////
51+
//////////////// API parameters /////////////////////
52+
/////////////////////////////////////////////////////
53+
54+
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true,
55+
description = "Name of the extension")
56+
private String name;
57+
58+
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true,
59+
description = "Type of the extension. Supported value is orchestrate")
60+
private String type;
61+
62+
@Parameter(name = ApiConstants.EXTERNAL_DETAILS, type = CommandType.MAP,
63+
description = "Details in key/value pairs using format externaldetails[i].keyname=keyvalue. Example: externaldetails[0].endpoint.url=urlvalue")
64+
protected Map externalDetails;
65+
66+
/////////////////////////////////////////////////////
67+
/////////////////// Accessors ///////////////////////
68+
/////////////////////////////////////////////////////
69+
70+
public String getName() {
71+
return name;
72+
}
73+
74+
public String getType() {
75+
return type;
76+
}
77+
78+
public Map<String, String> getExternalDetails() {
79+
Map<String, String> customparameterMap = convertDetailsToMap(externalDetails);
80+
Map<String, String> details = new HashMap<>();
81+
for (String key : customparameterMap.keySet()) {
82+
String value = customparameterMap.get(key);
83+
details.put(VmDetailConstants.EXTERNAL_DETAIL_PREFIX + key, value);
84+
}
85+
return details;
86+
}
87+
88+
public Map getDetails() {
89+
return externalDetails;
90+
}
91+
92+
/////////////////////////////////////////////////////
93+
/////////////// API Implementation///////////////////
94+
/////////////////////////////////////////////////////
95+
96+
@Override
97+
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
98+
Extension extension = _externalMgr.createExtension(this);
99+
ExtensionResponse response = new ExtensionResponse(name, type, extension.getUuid(), getExternalDetails());
100+
String destinationPath = String.format(SimpleExternalProvisioner.EXTENSION_SCRIPT_PATH, extension.getId());
101+
response.setScriptPath(destinationPath);
102+
response.setResponseName(getCommandName());
103+
response.setObjectName(ApiConstants.EXTENSION);
104+
setResponseObject(response);
105+
}
106+
107+
@Override
108+
public long getEntityOwnerId() {
109+
return Account.ACCOUNT_ID_SYSTEM;
110+
}
111+
}

plugins/hypervisors/external/src/main/java/com/cloud/hypervisor/external/provisioner/api/ExtensionResponse.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ public class ExtensionResponse extends BaseResponse {
4646
@Param(description = "Type of the extension")
4747
private String type;
4848

49-
@SerializedName(ApiConstants.POD_ID)
50-
@Param(description = "Pod ID associated with the extension")
51-
private long podId;
52-
5349
@SerializedName(ApiConstants.DETAILS)
5450
@Param(description = "the details of the network")
5551
private Map<String, String> details;
@@ -66,10 +62,9 @@ public class ExtensionResponse extends BaseResponse {
6662
@Param(description = "Removal timestamp of the extension, if applicable")
6763
private Date removed;
6864

69-
public ExtensionResponse(String name, String type, long podId, String uuid, Map<String, String> details) {
65+
public ExtensionResponse(String name, String type, String uuid, Map<String, String> details) {
7066
this.name = name;
7167
this.type = type;
72-
this.podId = podId;
7368
this.uuid = uuid;
7469
this.details = details;
7570
}
@@ -98,14 +93,6 @@ public void setType(String type) {
9893
this.type = type;
9994
}
10095

101-
public long getPodId() {
102-
return podId;
103-
}
104-
105-
public void setPodId(long podId) {
106-
this.podId = podId;
107-
}
108-
10996
public void setDetails(Map<String, String> details) {
11097
this.details = details;
11198
}

0 commit comments

Comments
 (0)