diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/AttachVnfTemplateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/AttachVnfTemplateCmd.java new file mode 100644 index 000000000000..8cb389ca6b8b --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/AttachVnfTemplateCmd.java @@ -0,0 +1,38 @@ +/* + * 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.api.command.user.vnf; + +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; +import javax.inject.Inject; + +@APICommand(name="attachVnfTemplate", responseObject=SuccessResponse.class, + description="Bind an existing VM as the VNF for the network") +public class AttachVnfTemplateCmd extends BaseAsyncCmd { + @Parameter(name="networkid", type=CommandType.UUID, entityType=NetworkResponse.class, required=true) private Long networkId; + @Parameter(name="vmid", type=CommandType.UUID, entityType=UserVmResponse.class, required=true) private Long vmId; + + @Inject private org.apache.cloudstack.vnf.VnfNetworkService vnfSvc; + @Override public void execute() { + vnfSvc.attachVnfVm(networkId, vmId, getEntityOwnerId()); + setResponseObject(new SuccessResponse(getCommandName())); + } + @Override public String getCommandName(){return "attachvnftemplateresponse";} + @Override public long getEntityOwnerId(){return CallContext.current().getCallingAccountId();} +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/CreateVnfNetworkCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/CreateVnfNetworkCmd.java new file mode 100644 index 000000000000..1a779d9020c3 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/CreateVnfNetworkCmd.java @@ -0,0 +1,49 @@ +/* + * 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.api.command.user.vnf; + +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; +import javax.inject.Inject; + +@APICommand(name = "createVnfNetwork", + description = "Create a VNF network (deploy VR broker + VNF VM)", + responseObject = CreateNetworkResponse.class) +public class CreateVnfNetworkCmd extends BaseAsyncCreateCmd { + @Parameter(name="name", type=CommandType.STRING, required=true) private String name; + @Parameter(name="displaytext", type=CommandType.STRING) private String displayText; + @Parameter(name="zoneid", type=CommandType.UUID, entityType=ZoneResponse.class, required=true) private Long zoneId; + @Parameter(name="vnftemplateid", type=CommandType.UUID, entityType=TemplateResponse.class, required=true) private Long vnfTemplateId; + @Parameter(name="servicehelpers", type=CommandType.STRING) private String serviceHelpers; + @Parameter(name="dictionaryyaml", type=CommandType.STRING) private String dictionaryYaml; + + @Inject private org.apache.cloudstack.vnf.VnfNetworkService vnfSvc; + + @Override public void execute() { + CreateNetworkResponse resp = vnfSvc.createVnfNetwork(this); + setResponseObject(resp); resp.setResponseName(getCommandName()); + } + @Override public String getCommandName() { return "createvnfnetworkresponse"; } + @Override public long getEntityOwnerId() { return CallContext.current().getCallingAccountId(); } + + // getters... + public String getName(){return name;} public String getDisplayText(){return displayText;} + public Long getZoneId(){return zoneId;} public Long getVnfTemplateId(){return vnfTemplateId;} + public String getServiceHelpers(){return serviceHelpers;} public String getDictionaryYaml(){return dictionaryYaml;} +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/GetVnfNetworkStatusCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/GetVnfNetworkStatusCmd.java new file mode 100644 index 000000000000..9a5537b5708e --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/GetVnfNetworkStatusCmd.java @@ -0,0 +1,35 @@ +/* + * 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.api.command.user.vnf; + +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; +import javax.inject.Inject; + +@APICommand(name="getVnfNetworkStatus", + description="Return broker/VNF/dictionary status for a VNF network", + responseObject=org.apache.cloudstack.api.response.SuccessResponse.class) +public class GetVnfNetworkStatusCmd extends BaseCmd { + @Parameter(name="networkid", type=CommandType.UUID, entityType=NetworkResponse.class, required=true) private Long networkId; + @Inject private org.apache.cloudstack.vnf.VnfNetworkService vnfSvc; + @Override public void execute() { + setResponseObject(vnfSvc.getStatus(networkId)); + } + @Override public String getCommandName(){ return "getvnfnetworkstatusresponse"; } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/UploadVnfDictionaryCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/UploadVnfDictionaryCmd.java new file mode 100644 index 000000000000..34370d41044f --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vnf/UploadVnfDictionaryCmd.java @@ -0,0 +1,40 @@ +/* + * 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.api.command.user.vnf; + +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; +import javax.inject.Inject; + +@APICommand(name="uploadVnfDictionary", responseObject=SuccessResponse.class, + description="Upload/replace a dictionary YAML for a VNF network") +public class UploadVnfDictionaryCmd extends BaseAsyncCmd { + @Parameter(name="networkid", type=CommandType.UUID, entityType=NetworkResponse.class, required=true) private Long networkId; + @Parameter(name="name", type=CommandType.STRING) private String name; + @Parameter(name="yaml", type=CommandType.STRING, required=true) private String yaml; + + @Inject private org.apache.cloudstack.vnf.VnfNetworkService vnfSvc; + + @Override public void execute() { + vnfSvc.uploadDictionary(networkId, name, yaml, getEntityOwnerId()); + setResponseObject(new SuccessResponse(getCommandName())); + } + @Override public String getCommandName() { return "uploadvnfdictionaryresponse"; } + @Override public long getEntityOwnerId() { return CallContext.current().getCallingAccountId(); } +} diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42100to42200/42110-vnf-network.xml b/engine/schema/src/main/resources/META-INF/db/schema-42100to42200/42110-vnf-network.xml new file mode 100644 index 000000000000..2f25b3f0f4f9 --- /dev/null +++ b/engine/schema/src/main/resources/META-INF/db/schema-42100to42200/42110-vnf-network.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42100to42200/upgrade.xml b/engine/schema/src/main/resources/META-INF/db/schema-42100to42200/upgrade.xml new file mode 100644 index 000000000000..6950977fb4ed --- /dev/null +++ b/engine/schema/src/main/resources/META-INF/db/schema-42100to42200/upgrade.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/server/src/main/java/org/apache/cloudstack/vnf/VnfNetworkService.java b/server/src/main/java/org/apache/cloudstack/vnf/VnfNetworkService.java new file mode 100644 index 000000000000..850f462453a1 --- /dev/null +++ b/server/src/main/java/org/apache/cloudstack/vnf/VnfNetworkService.java @@ -0,0 +1,29 @@ +/* + * 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.vnf; + +import org.apache.cloudstack.api.command.user.vnf.*; +import org.apache.cloudstack.api.response.CreateNetworkResponse; + +public interface VnfNetworkService { + CreateNetworkResponse createVnfNetwork(CreateVnfNetworkCmd cmd); + void uploadDictionary(long networkId, String name, String yaml, long ownerId); + void attachVnfVm(long networkId, long vmId, long ownerId); + org.apache.cloudstack.api.response.SuccessResponse getStatus(long networkId); +} diff --git a/server/src/main/java/org/apache/cloudstack/vnf/VnfNetworkServiceImpl.java b/server/src/main/java/org/apache/cloudstack/vnf/VnfNetworkServiceImpl.java new file mode 100644 index 000000000000..45f96baa170c --- /dev/null +++ b/server/src/main/java/org/apache/cloudstack/vnf/VnfNetworkServiceImpl.java @@ -0,0 +1,58 @@ +/* + * 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.vnf; + +import com.cloud.network.Network; +import com.cloud.user.Account; +import org.apache.cloudstack.api.response.CreateNetworkResponse; +import javax.inject.Inject; +import javax.ejb.Local; + +@Local(value=VnfNetworkService.class) +public class VnfNetworkServiceImpl implements VnfNetworkService { + + @Inject private dao.VnfDictionaryDao dictDao; + @Inject private dao.VnfNetworkBindingDao bindingDao; + @Inject private dao.VnfRuleMapDao ruleDao; + @Inject private VnfTemplateRenderer renderer; + @Inject private VnfTransport transport; + + @Override + public CreateNetworkResponse createVnfNetwork(org.apache.cloudstack.api.command.user.vnf.CreateVnfNetworkCmd cmd) { + // TODO: create network record (like Isolated), deploy VR broker + VNF VM from template, + // persist binding + optional dictionary, return response with IDs + return new CreateNetworkResponse(); + } + + @Override + public void uploadDictionary(long networkId, String name, String yaml, long ownerId) { + // TODO: validate YAML placeholders; persist versioned dictionary + } + + @Override + public void attachVnfVm(long networkId, long vmId, long ownerId) { + // TODO: bind a VM as the VNF; update egress allowlist for broker + } + + @Override + public org.apache.cloudstack.api.response.SuccessResponse getStatus(long networkId) { + // TODO: query broker health + VNF reachability + dict version + return new org.apache.cloudstack.api.response.SuccessResponse("getvnfnetworkstatus"); + } +} diff --git a/server/src/main/java/org/apache/cloudstack/vnf/VnfTemplateRenderer.java b/server/src/main/java/org/apache/cloudstack/vnf/VnfTemplateRenderer.java new file mode 100644 index 000000000000..dd0e4e6c96bc --- /dev/null +++ b/server/src/main/java/org/apache/cloudstack/vnf/VnfTemplateRenderer.java @@ -0,0 +1,34 @@ +/* + * 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.vnf; + +import java.util.Map; + +public class VnfTemplateRenderer { + public RenderedRequest render(Dictionary dict, String key, Map inputs, Map injectedHeaders) { + // TODO: SnakeYAML load -> map; replace ${...}; build method/path/body/headers; return RenderedRequest + return new RenderedRequest("POST", "/api/v2/firewall/rule", Map.of(), injectedHeaders); + } + + public static class Dictionary { public Map root; } + public static class RenderedRequest { + public final String method, path; public final Object body; public final Map headers; + public RenderedRequest(String m, String p, Object b, Map h){ method=m; path=p; body=b; headers=h; } + } +} diff --git a/server/src/main/java/org/apache/cloudstack/vnf/VnfTransport.java b/server/src/main/java/org/apache/cloudstack/vnf/VnfTransport.java new file mode 100644 index 000000000000..49c428223cb2 --- /dev/null +++ b/server/src/main/java/org/apache/cloudstack/vnf/VnfTransport.java @@ -0,0 +1,30 @@ +/* + * 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.vnf; + +public class VnfTransport { + public static class VnfResponse { public final int status; public final String body; + public VnfResponse(int s, String b){ status=s; body=b; } } + + public VnfResponse forward(long networkId, String vnfIp, int port, + VnfTemplateRenderer.RenderedRequest req, String idemKey) { + // TODO: POST https://:8443/v1/forward with mTLS + JWT; return status/body + return new VnfResponse(200, "{}"); + } +}