Create CloudConfigProvider and wire it up...

... in preparation for implementing various stories that depend on this
infrastructure.
This commit is contained in:
Kris De Volder
2017-07-18 15:52:34 -07:00
parent eb440634b4
commit cecd98f7a5
19 changed files with 279 additions and 31 deletions

View File

@@ -14,6 +14,7 @@ import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import org.springframework.ide.vscode.bosh.cloudconfig.CloudConfigProvider;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.Renderables;
@@ -77,9 +78,11 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
private YType t_release_name_ref;
private YType t_var_name_def;
private final ASTTypeCache astTypes;
private CloudConfigProvider cloudConfigProvider;
public BoshDeploymentManifestSchema(ASTTypeCache astTypes) {
public BoshDeploymentManifestSchema(ASTTypeCache astTypes, CloudConfigProvider cloudConfigProvider) {
this.astTypes = astTypes;
this.cloudConfigProvider = cloudConfigProvider;
TYPE_UTIL = f.TYPE_UTIL;
V2_TOPLEVEL_TYPE = createV2Schema();

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.bosh;
import org.springframework.ide.vscode.bosh.cloudconfig.CloudConfigProvider;
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter.LazyCompletionResolver;
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider;
@@ -40,12 +41,12 @@ public class BoshLanguageServer extends SimpleLanguageServer {
private final LazyCompletionResolver completionResolver = new LazyCompletionResolver(); //Set to null to disable lazy resolving
private final VscodeCompletionEngineAdapter completionEngine;
public BoshLanguageServer() {
public BoshLanguageServer(CloudConfigProvider cloudConfigProvider) {
super("vscode-bosh");
YamlASTProvider parser = new YamlParser(yaml);
SimpleTextDocumentService documents = getTextDocumentService();
ASTTypeCache astTypeCache = new ASTTypeCache();
BoshDeploymentManifestSchema schema = new BoshDeploymentManifestSchema(astTypeCache);
BoshDeploymentManifestSchema schema = new BoshDeploymentManifestSchema(astTypeCache, cloudConfigProvider);
YamlStructureProvider structureProvider = YamlStructureProvider.DEFAULT;
YamlAssistContextProvider contextProvider = new SchemaBasedYamlAssistContextProvider(schema);

View File

@@ -8,16 +8,15 @@
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.bosh;
import java.io.IOException;
import org.springframework.ide.vscode.bosh.cloudconfig.BoshCommandCloudConfigProvider;
import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
LaunguageServerApp.start(() -> new BoshLanguageServer());
LaunguageServerApp.start(() -> new BoshLanguageServer(new BoshCommandCloudConfigProvider()));
}
}

View File

@@ -0,0 +1,110 @@
/*******************************************************************************
* Copyright (c) 2017 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.bosh.cloudconfig;
import java.io.File;
import java.time.Duration;
import java.util.Collection;
import java.util.stream.Stream;
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.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.NodeUtil;
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.YamlPath;
import org.springframework.ide.vscode.commons.yaml.path.YamlTraversal;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.representer.Representer;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Concrete implementation of {@link CloudConfigProvider} that runs `bosh cloud-config` command
* with bosh cli and parses the output.
*
* @author Kris De Volder
*/
public class BoshCommandCloudConfigProvider implements CloudConfigProvider {
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final YamlParser yamlParser;
public BoshCommandCloudConfigProvider() {
Representer representer = new Representer();
representer.getPropertyUtils().setSkipMissingProperties(true);
yamlParser = new YamlParser(new Yaml());
}
/**
* For deserializing the output from bosh cloud-config command.
*/
public static class CloudConfigResponse {
private String[] blocks;
@JsonProperty("Blocks")
public String[] getBlocks() {
return blocks;
}
public void setBlocks(String[] blocks) {
this.blocks = blocks;
}
}
YamlTraversal VM_TYPE_NAMES = YamlPath.EMPTY
.thenAnyChild()
.thenValAt("vm_types")
.thenAnyChild()
.thenValAt("name");
@Override
public CloudConfigModel getCloudConfig(DynamicSchemaContext dc) throws Exception {
String out = executeBoshCloudConfigCommand();
CloudConfigResponse response = mapper.readValue(out, CloudConfigResponse.class);
String[] blocks = response.getBlocks();
Assert.isLegal(blocks!=null);
Assert.isLegal(blocks.length==1);
TextDocument doc = new TextDocument(null, LanguageId.BOSH_CLOUD_CONFIG);
doc.setText(blocks[0]);
YamlFileAST ast = yamlParser.getAST(doc);
return new CloudConfigModel() {
@Override
public Collection<String> getVMTypes() {
return VM_TYPE_NAMES.traverseAmbiguously(ast)
.flatMap(nameNode -> {
String name = NodeUtil.asScalar(nameNode);
return StringUtil.hasText(name)
? Stream.of(name)
: Stream.empty();
})
.collect(CollectorUtil.toMultiset());
}
};
}
protected String executeBoshCloudConfigCommand() throws Exception {
ExternalCommand command = new ExternalCommand("bosh", "cloud-config", "--json");
ExternalProcess process = new ExternalProcess(new File(".").getAbsoluteFile(), command, true, Duration.ofSeconds(30));
System.out.println("executeBoshCloudConfigCommand: "+process);
String out = process.getOut();
return out;
}
}

View File

@@ -0,0 +1,20 @@
/*******************************************************************************
* Copyright (c) 2017 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.bosh.cloudconfig;
import java.util.Collection;
/**
* Represents CloudConfig information as might be retrieved from bosh director.
*/
public interface CloudConfigModel {
Collection<String> getVMTypes();
}

View File

@@ -0,0 +1,12 @@
package org.springframework.ide.vscode.bosh.cloudconfig;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
/**
* Responsible for somehow obtaining {@link CloudConfigModel} relative to a {@link DynamicSchemaContext}
*/
public interface CloudConfigProvider {
CloudConfigModel getCloudConfig(DynamicSchemaContext dc) throws Exception;
}

View File

@@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright (c) 2017 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.bosh;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.ide.vscode.bosh.cloudconfig.BoshCommandCloudConfigProvider;
import org.springframework.ide.vscode.bosh.cloudconfig.CloudConfigModel;
import org.springframework.ide.vscode.commons.util.IOUtil;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
import com.google.common.collect.ImmutableMultiset;
public class BoshCommandCloudConfigProviderTest {
private static final String MOCK_DATA_RSRC = "/cmd-out/cloud-config.json";
public static final BoshCommandCloudConfigProvider mockProvider = new BoshCommandCloudConfigProvider() {
/**
* Override with a 'fake' which just returns some mock data. That way we can unit-test
* without requiring a real bosh setup.
*/
@Override
protected String executeBoshCloudConfigCommand() throws Exception {
return IOUtil.toString(BoshCommandCloudConfigProviderTest.class.getResourceAsStream(MOCK_DATA_RSRC));
};
};
// For local testing only... in CI builds we don't have the means to use a real bosh director and cli.
// private BoshCommandCloudConfigProvider realProvider = new BoshCommandCloudConfigProvider();
@Test public void getVMTypes() throws Exception {
BoshCommandCloudConfigProvider provider = mockProvider;
DynamicSchemaContext dc = Mockito.mock(DynamicSchemaContext.class);
CloudConfigModel cloudConfig = provider.getCloudConfig(dc);
assertEquals(ImmutableMultiset.of("default", "large"), cloudConfig.getVMTypes());
}
}

View File

@@ -8,7 +8,7 @@
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.concourse;
package org.springframework.ide.vscode.bosh;
import static org.springframework.ide.vscode.languageserver.testharness.Editor.PLAIN_COMPLETION;
@@ -26,7 +26,7 @@ public class BoshEditorTest {
@Before public void setup() throws Exception {
harness = new LanguageServerHarness(() -> {
return new BoshLanguageServer()
return new BoshLanguageServer(BoshCommandCloudConfigProviderTest.mockProvider)
.setMaxCompletions(100);
},
LanguageId.BOSH_DEPLOYMENT

View File

@@ -9,7 +9,7 @@
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.concourse;
package org.springframework.ide.vscode.bosh;
import static org.assertj.core.api.Assertions.assertThat;
@@ -31,7 +31,9 @@ public class BoshLanguageServerTest {
@Test
public void createAndInitializeServerWithWorkspace() throws Exception {
LanguageServerHarness harness = new LanguageServerHarness(() -> new BoshLanguageServer());
LanguageServerHarness harness = new LanguageServerHarness(() ->
new BoshLanguageServer(BoshCommandCloudConfigProviderTest.mockProvider)
);
File workspaceRoot = getTestResource("/workspace/");
assertExpectedInitResult(harness.intialize(workspaceRoot));
}
@@ -39,7 +41,9 @@ public class BoshLanguageServerTest {
@Test
public void createAndInitializeServerWithoutWorkspace() throws Exception {
File workspaceRoot = null;
LanguageServerHarness harness = new LanguageServerHarness(() -> new BoshLanguageServer());
LanguageServerHarness harness = new LanguageServerHarness(() ->
new BoshLanguageServer(BoshCommandCloudConfigProviderTest.mockProvider)
);
assertExpectedInitResult(harness.intialize(workspaceRoot));
}

View File

@@ -8,7 +8,7 @@
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.concourse;
package org.springframework.ide.vscode.bosh;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

View File

@@ -0,0 +1,10 @@
{
"Tables": null,
"Blocks": [
"azs:\n- cloud_properties:\n datacenters:\n - clusters:\n - AppFabric: {}\n name: z1\n- cloud_properties:\n datacenters:\n - clusters:\n - AppFabric: {}\n name: z2\n- cloud_properties:\n datacenters:\n - clusters:\n - AppFabric: {}\n name: z3\ncompilation:\n az: z1\n network: default\n reuse_compilation_vms: true\n vm_type: default\n workers: 5\ndisk_types:\n- disk_size: 3000\n name: default\n- disk_size: 50000\n name: large\nnetworks:\n- name: default\n subnets:\n - azs:\n - z1\n - z2\n - z3\n cloud_properties:\n name: VLAN 40 - AF\n dns:\n - 10.192.2.10\n - 8.8.8.8\n gateway: 10.194.4.1\n range: 10.194.4.0/23\n reserved:\n - 10.194.4.1-10.194.4.34\n - 10.194.4.40-10.194.5.255\n type: manual\nvm_types:\n- cloud_properties:\n cpu: 2\n disk: 3240\n ram: 1024\n name: default\n- cloud_properties:\n cpu: 2\n disk: 30240\n ram: 4096\n name: large\n"
],
"Lines": [
"Using environment '10.194.4.35' as client 'admin'",
"Succeeded"
]
}