-
Notifications
You must be signed in to change notification settings - Fork 203
/
BoshCommandBasedModelProvider.java
157 lines (138 loc) · 5.47 KB
/
BoshCommandBasedModelProvider.java
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
/*******************************************************************************
* Copyright (c) 2017, 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.bosh.models;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;
import org.springframework.ide.vscode.bosh.BoshCliConfig;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.util.CollectorUtil;
import org.springframework.ide.vscode.commons.util.ExternalCommand;
import org.springframework.ide.vscode.commons.util.ExternalProcess;
import org.springframework.ide.vscode.commons.util.GsonUtil;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
import org.springframework.ide.vscode.commons.yaml.ast.YamlParser;
import org.springframework.ide.vscode.commons.yaml.path.YamlTraversal;
import org.springframework.ide.vscode.commons.yaml.util.JSONCursor;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.representer.Representer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.annotations.SerializedName;
/**
* Abstract base class to aid in implementing a Dynamic model provider that executes a bosh
* command (with `--json`) swtich and then extracts information from its json output.
*/
public abstract class BoshCommandBasedModelProvider<T> implements DynamicModelProvider<T> {
private final YamlParser yamlParser;
// NOTE: By default, Gson skips unknown fields, so this hopefully is equivalent to the Jackson mapper configuration that was replaced:
// protected final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
protected final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
private final BoshCliConfig config;
protected BoshCommandBasedModelProvider(BoshCliConfig config) {
this.config = config;
Representer representer = new Representer();
representer.getPropertyUtils().setSkipMissingProperties(true);
yamlParser = new YamlParser();
}
/**
* For deserializing the output from bosh cloud-config command.
*/
public static class BoshCommandResponse {
@SerializedName("Blocks")
private String[] blocks;
public String[] getBlocks() {
return blocks;
}
public void setBlocks(String[] blocks) {
this.blocks = blocks;
}
}
protected String getBlock() throws Exception {
String out = executeCommand(getCommand());
BoshCommandResponse response = gson.fromJson(out, BoshCommandResponse.class);
String[] blocks = response.getBlocks();
Assert.isLegal(blocks!=null);
Assert.isLegal(blocks.length==1);
return blocks[0];
}
protected final ExternalCommand getCommand() {
List<String> commandAndArgs = new ArrayList<>();
String command = config.getCommand();
if (command==null) {
return null;
}
commandAndArgs.add(command);
String target = config.getTarget();
if (target==null && !StringUtil.hasText(System.getenv("BOSH_ENVIRONMENT"))) {
//See https://www.pivotaltracker.com/story/show/150309966
return null;
}
if (target!=null) {
commandAndArgs.add("-e");
commandAndArgs.add(target);
}
for (String s : getBoshCommand()) {
commandAndArgs.add(s);
}
return new ExternalCommand(commandAndArgs.toArray(new String[commandAndArgs.size()]));
}
protected JsonElement getJsonTree() throws Exception {
String out = executeCommand(getCommand());
JsonElement element = gson.fromJson(out, JsonElement.class);
return element;
}
protected String executeCommand(ExternalCommand command) throws Exception {
if (command==null) {
Log.log("bosh cli based editor features are disabled");
throw new IOException("bosh cli based editor features are disabled. "
+ "Consult the atom/vscode extension's readme for detailed "
+ "instructions on how to target a director and enable them.");
}
try {
ExternalProcess process = new ExternalProcess(getWorkingDir(), command, true, config.getTimeout());
return process.getOut();
} catch (Exception e) {
Log.log("executing cmd FAILED", e);
throw e;
}
}
protected File getWorkingDir() {
return new File(".").getAbsoluteFile();
}
protected abstract String[] getBoshCommand();
protected YamlFileAST parseYaml(String block) throws Exception {
TextDocument doc = new TextDocument(null, LanguageId.BOSH_CLOUD_CONFIG);
doc.setText(block);
YamlFileAST ast = yamlParser.getAST(doc);
return ast;
}
protected Collection<String> getNames(JSONCursor _cursor, YamlTraversal path) {
return path.traverseAmbiguously(_cursor)
.flatMap((cursor) -> {
String text = GsonUtil.getAsString(cursor.target);
if (StringUtil.hasText(text)) {
return Stream.of(text);
} else {
return Stream.empty();
}
})
.collect(CollectorUtil.toImmutableSet());
}
}