summaryrefslogtreecommitdiffstats
path: root/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/packagetransformer/OnapR2HeatPackageBuilder.java
blob: f437a902b8608866770b9443923edd883dc4be6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
 * Copyright 2016-2017, Nokia Corporation
 *
 * Licensed 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.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.packagetransformer;

import com.google.common.collect.Sets;
import com.google.gson.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.LifecycleManager;
import org.slf4j.Logger;
import org.yaml.snakeyaml.Yaml;

import static java.util.stream.Collectors.toSet;

import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.CbamUtils.*;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * Transforms a CBAM package into an ONAP package
 */
public class OnapR2HeatPackageBuilder {
    public static final String ETSI_MODIFIABLE_ATTRIBUTES_EXTENSTION = "etsi_modifiable_attributes_extenstion_";
    public static final String IMAGE_NAME = "_image_name";
    public static final String FLAVOR_NAME = "_flavor_name";
    public static final String NET_ID = "_net_id";
    private static Logger logger = getLogger(OnapR2HeatPackageBuilder.class);
    public static final String BASE_ENV_FILE_NAME = "base.env";
    public static final String BASE_YAML_FILE_NAME = "base.yaml";

    private Set<String> autoManagedExtensions = Sets.newHashSet(LifecycleManager.ONAP_CSAR_ID, LifecycleManager.EXTERNAL_VNFM_ID);

    Map<String, String> processVnfd(String cbamVnfd) {
        Map<String, String> files = new HashMap<>();
        JsonObject root = new Gson().toJsonTree(new Yaml().load(cbamVnfd)).getAsJsonObject();
        JsonObject topologyTemplate = child(root, "topology_template");
        JsonObject substitutionMappings = child(topologyTemplate, "substitution_mappings");
        JsonObject capabilities = child(substitutionMappings, "capabilities");
        JsonObject deploymentFlavour = child(capabilities, "deployment_flavour");
        JsonArray policies = childElement(topologyTemplate, "policies").getAsJsonArray();
        JsonObject manifest = new JsonObject();
        manifest.addProperty("name", "ONAP VNF package");
        manifest.addProperty("description", "");
        JsonArray data = new JsonArray();
        manifest.add("data", data);
        JsonObject deploymentFlavorProperties = child(deploymentFlavour, "properties");
        if (deploymentFlavorProperties.has("scaling_aspects")) {
            JsonObject scalingAspects = child(deploymentFlavorProperties, "scaling_aspects");
            for (Map.Entry<String, JsonElement> scalingAspect : scalingAspects.entrySet()) {
                processAspect(files, data, policies, scalingAspect.getKey(), childElement(scalingAspect.getValue().getAsJsonObject(), "max_scale_level").getAsLong());
            }
        }
        processBaseIncrement(topologyTemplate, files, policies, data);
        files.put("MANIFEST.json", new GsonBuilder().setPrettyPrinting().create().toJson(manifest));
        return files;
    }

    private void processBaseIncrement(JsonObject topologyTemplate, Map<String, String> files, JsonArray policies, JsonArray data) {
        StringBuilder envContent = prepareEvnContent();
        StringBuilder yamlContent = prepareYamlContent();
        if (topologyTemplate.has("node_templates")) {
            JsonObject nodeTemplates = child(topologyTemplate, "node_templates");
            processEcps(nodeTemplates, envContent, yamlContent);
            for (Map.Entry<String, JsonElement> vdu : filterType(nodeTemplates, "tosca.nodes.nfv.VDU")) {
                addImageAndFlavor(envContent, yamlContent, vdu);
            }
        }
        processModifiableAttributes(topologyTemplate, envContent, yamlContent);
        data.add(buildManifestEntry(BASE_ENV_FILE_NAME, BASE_YAML_FILE_NAME, true));
        files.put(BASE_ENV_FILE_NAME, envContent.toString());
        files.put(BASE_YAML_FILE_NAME, yamlContent.toString());
    }

    private void processModifiableAttributes(JsonObject topologyTemplate, StringBuilder envContent, StringBuilder yamlContent) {
        JsonObject capabilities = child(child(topologyTemplate, "substitution_mappings"), "capabilities");
        if (capabilities.has("vnf")) {
            JsonObject vnf = child(capabilities, "vnf");
            if (vnf.has("properties")) {
                JsonObject properties = child(vnf, "properties");
                if (properties.has("modifiable_attributes")) {
                    JsonObject modifiableAttributes = child(properties, "modifiable_attributes");
                    if (modifiableAttributes.has("extensions")) {
                        JsonObject extensions = child(modifiableAttributes, "extensions");
                        for (Map.Entry<String, JsonElement> extension : extensions.entrySet()) {
                            if (!autoManagedExtensions.contains(extension.getKey())) {
                                addParameter(yamlContent, envContent, ETSI_MODIFIABLE_ATTRIBUTES_EXTENSTION + extension.getKey(), "Modifiable attribute", "Modifiable attribute for " + extension.getKey());
                            }
                        }
                    }
                }
            }
        }
    }

    public static Set<Map.Entry<String, JsonElement>> filterType(JsonObject nodeTemplates, String type) {
        return nodeTemplates.entrySet().stream().filter(e -> e.getValue().getAsJsonObject().get("type").equals(type)).collect(toSet());
    }

    private void processEcps(JsonObject nodeTemplates, StringBuilder envContent, StringBuilder yamlContent) {
        for (Map.Entry<String, JsonElement> node : filterType(nodeTemplates, "tosca.nodes.nfv.ECP")) {
            envContent.append("  " + node.getKey() + NET_ID + ": PUT YOUR NETWORK ID HERE\n");
            addYamlParameter(yamlContent, node.getKey() + NET_ID, "Network id", "Network identifier for " + node.getKey() + " ECP");
        }
    }

    private StringBuilder prepareYamlContent() {
        StringBuilder yamlContent = new StringBuilder();
        yamlContent.append("heat_template_version: 2013-05-23\n");
        yamlContent.append("parameters:\n");
        return yamlContent;
    }

    private void processAspect(Map<String, String> files, JsonArray data, JsonArray policies, String aspectName, long maxScaleLevel) {
        JsonObject aspect = locateAspect(locateHeatPolicy(policies), aspectName);
        StringBuilder envContent = prepareEvnContent();
        StringBuilder yamlContent = prepareYamlContent();
        if (aspect.has("vdus")) {
            processMapping(aspect, envContent, yamlContent);
        }
        if (maxScaleLevel > 1001) {
            throw buildFatalFailure(logger, "Refusing to create more than 1001 scaling levels");
        }
        envContent.append("  etsi.scalingAspectId: "+ aspectName + "\n");
        for (int scaleIndex = 0; scaleIndex < maxScaleLevel; scaleIndex++) {
            String envFileName = "module_" + aspectName + "_" + scaleIndex + ".env";
            files.put(envFileName, envContent.toString());
            String yamlFileName = "module_" + aspectName + "_" + scaleIndex + ".yaml";
            files.put(yamlFileName, yamlContent.toString());
            data.add(buildManifestEntry(envFileName, yamlFileName, false));
        }
    }

    private StringBuilder prepareEvnContent() {
        StringBuilder envContent = new StringBuilder();
        envContent.append("parameters:\n");
        return envContent;
    }

    private JsonObject buildManifestEntry(String envFileName, String yamlFileName, boolean base) {
        JsonObject manifestEntry = new JsonObject();
        manifestEntry.addProperty("file", yamlFileName);
        manifestEntry.addProperty("type", "HEAT");
        manifestEntry.addProperty("isBase", Boolean.toString(base));
        JsonArray envEntries = new JsonArray();
        manifestEntry.add("data", envEntries);
        JsonObject envEntry = new JsonObject();
        envEntries.add(envEntry);
        envEntry.addProperty("file", envFileName);
        envEntry.addProperty("type", "HEAT_ENV");
        return manifestEntry;
    }

    private void processMapping(JsonObject mapping, StringBuilder envContent, StringBuilder yamlContent) {
        for (Map.Entry<String, JsonElement> vdusElement : child(mapping, "vdus").entrySet()) {
            addImageAndFlavor(envContent, yamlContent, vdusElement);
        }
        if (mapping.has("externalConnectionPoints")) {
            for (Map.Entry<String, JsonElement> externalConnectionPoints : child(mapping, "externalConnectionPoints").entrySet()) {
                addParameter(yamlContent, envContent, externalConnectionPoints.getKey() + "_net_id", "Network id", "Network to be used for " + externalConnectionPoints.getKey() + " ECP");
                addParameter(yamlContent, envContent, externalConnectionPoints.getKey() + "_subnet_id", "Subnet id", "Subnet to be used for " + externalConnectionPoints.getKey() + " ECP");
            }
        }
    }

    private void addImageAndFlavor(StringBuilder envContent, StringBuilder yamlContent, Map.Entry<String, JsonElement> vdusElement) {
        String vdu = vdusElement.getKey();
        addParameter(yamlContent, envContent, vdu + IMAGE_NAME, "Image name or identifier", "Image to be used for " + vdu + " VDU");
        addParameter(yamlContent, envContent, vdu + FLAVOR_NAME, "Flavor name or identifier", "Flavor to be used for " + vdu + " VDU");
    }

    private void addParameter(StringBuilder yamlContent, StringBuilder envContent, String key, String label, String description) {
        addYamlParameter(yamlContent, key, label, description);
        envContent.append("  " + key + ": PUT YOUR " + label.toUpperCase() + " HERE\n");
    }

    private void addYamlParameter(StringBuilder yamlContent, String key, String label, String description) {
        yamlContent.append("  " + key + ":\n");
        yamlContent.append("    type: string\n");
        yamlContent.append("    label: " + label + "\n");
        yamlContent.append("    description: " + description + "\n");
    }

    private JsonObject locateHeatPolicy(JsonArray policies) {
        for (int index = 0; index < policies.size(); index++) {
            JsonObject c = policies.get(index).getAsJsonObject();
            JsonObject policy = c.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject();
            if ("tosca.policies.nfv.HeatMapping".equals(childElement(policy, "type").getAsString())) {
                return policy;
            }
        }
        throw buildFatalFailure(logger, "The heat_mapping section is missing from VNFD");
    }

    private JsonObject locateAspect(JsonObject policy, String aspectName) {
        for (Map.Entry<String, JsonElement> aspect : child(child(policy, "properties"), "aspects").entrySet()) {
            if (aspect.getKey().equals(aspectName)) {
                return aspect.getValue().getAsJsonObject();
            }
        }
        throw buildFatalFailure(logger, "Unable to locate " + aspectName + " in heat policy");
    }
}