Minimal support for editing cloud-config

This commit is contained in:
Kris De Volder
2017-08-04 15:48:18 -07:00
parent 66c427f37a
commit 3d1937c9d8
61 changed files with 337 additions and 74 deletions

View File

@@ -0,0 +1,52 @@
/*******************************************************************************
* 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 org.springframework.ide.vscode.bosh.models.BoshModels;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YBeanType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
public class BoshCloudConfigSchema extends SchemaSupport implements YamlSchema {
private YBeanType toplevelType;
private YType t_any;
public BoshCloudConfigSchema(YTypeFactory f, BoshModels models) {
super(f);
this.toplevelType = f.ybean("CloudConfig");
t_any = f.yany("Object");
addProp(toplevelType, "azs", t_any);
addProp(toplevelType, "networks", t_any);
addProp(toplevelType, "vm_types", t_any);
addProp(toplevelType, "vm_extensions", t_any);
addProp(toplevelType, "disk_types", t_any);
addProp(toplevelType, "compilation", t_any);
}
@Override
public YType getTopLevelType() {
return toplevelType;
}
@Override
public YTypeUtil getTypeUtil() {
return f.TYPE_UTIL;
}
@Override
protected String getResourcePathPrefix() {
return "cloud-config";
}
}

View File

@@ -38,7 +38,7 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder<BoshLanguageServ
private final YamlAstCache asts;
private final ASTTypeCache astTypes;
private final BoshDeploymentManifestSchema schema;
private final BoshSchemas schema;
private Map<YType, Handler> handlers = new HashMap<>();
@@ -47,7 +47,7 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder<BoshLanguageServ
Flux<Location> handle(Node refNode, TextDocument doc, YamlFileAST ast);
}
public BoshDefintionFinder(BoshLanguageServer server, BoshDeploymentManifestSchema schema, YamlAstCache asts, ASTTypeCache astTypes) {
public BoshDefintionFinder(BoshLanguageServer server, BoshSchemas schema, YamlAstCache asts, ASTTypeCache astTypes) {
super(server);
this.schema = schema;
this.asts = asts;

View File

@@ -17,6 +17,7 @@ import java.util.UUID;
import java.util.function.Predicate;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.ide.vscode.bosh.models.BoshModels;
import org.springframework.ide.vscode.bosh.models.CachingModelProvider;
import org.springframework.ide.vscode.bosh.models.CloudConfigModel;
import org.springframework.ide.vscode.bosh.models.DynamicModelProvider;
@@ -58,7 +59,7 @@ import com.google.common.collect.ImmutableSet;
/**
* @author Kris De Volder
*/
public class BoshDeploymentManifestSchema implements YamlSchema {
public class BoshDeploymentManifestSchema extends SchemaSupport implements YamlSchema {
private final YBeanType V2_TOPLEVEL_TYPE;
private final YBeanType V1_TOPLEVEL_TYPE;
@@ -70,26 +71,19 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
private ImmutableList<YType> definitionTypes = null;
//Note: 'director_uuid' is also deprecated. But its treated separately since it is deprecated and ignored by V2 client no matter what (i.e. deprecated in both schemas)
public final YTypeFactory f = new YTypeFactory()
.enableTieredProposals(false)
.suggestDeprecatedProperties(false);
public final YType t_string = f.yatomic("String");
public final YType t_ne_string = f.yatomic("String")
.parseWith(ValueParsers.NE_STRING);
public final YType t_string;
public final YType t_ne_string;
public final YType t_strings = f.yseq(t_string);
public final YType t_strings;
public final YAtomicType t_boolean = f.yenum("boolean", "true", "false");
public final YType t_any = f.yany("Object");
public final YType t_params = f.ymap(t_string, t_any);
public final YType t_string_params = f.ymap(t_string, t_string);
public final YType t_pos_integer = f.yatomic("Positive Integer")
.parseWith(ValueParsers.POS_INTEGER);
public final YType t_strictly_pos_integer = f.yatomic("Strictly Positive Integer")
.parseWith(ValueParsers.integerAtLeast(1));
public final YType t_uuid = f.yatomic("UUID").parseWith(UUID::fromString);
public final YType t_integer_or_range = f.yatomic("Integer or Range")
.parseWith(BoshValueParsers.INTEGER_OR_RANGE);
public final YAtomicType t_boolean;
public final YType t_any;
public final YType t_params;
public final YType t_string_params;
public final YType t_pos_integer;
public final YType t_strictly_pos_integer;
public final YType t_uuid;
public final YType t_integer_or_range;
private YType t_stemcell_alias_def;
private YType t_stemcell_alias_ref;
private YType t_release_name_def;
@@ -103,19 +97,31 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
private DynamicModelProvider<ReleasesModel> releasesProvider;
private List<Pair<YType, YType>> defAndRefTypes;
public BoshDeploymentManifestSchema(
YamlAstCache asts, ASTTypeCache astTypes,
DynamicModelProvider<CloudConfigModel> cloudConfigProvider,
DynamicModelProvider<StemcellsModel> stemcellsProvider,
DynamicModelProvider<ReleasesModel> releasesProvider
) {
this.asts = asts;
this.astTypes = astTypes;
this.cloudConfigProvider = new CachingModelProvider<>(cloudConfigProvider, CloudConfigModel.class);
this.stemcellsProvider = new CachingModelProvider<>(stemcellsProvider, StemcellsModel.class);
this.releasesProvider = new CachingModelProvider<>(releasesProvider, ReleasesModel.class);
public BoshDeploymentManifestSchema(YTypeFactory f, BoshModels models) {
super(f);
this.asts = models.asts;
this.astTypes = models.astTypes;
this.cloudConfigProvider = new CachingModelProvider<>(models.cloudConfigProvider, CloudConfigModel.class);
this.stemcellsProvider = new CachingModelProvider<>(models.stemcellsProvider, StemcellsModel.class);
this.releasesProvider = new CachingModelProvider<>(models.releasesProvider, ReleasesModel.class);
TYPE_UTIL = f.TYPE_UTIL;
t_string = f.yatomic("String");
t_boolean = f.yenum("boolean", "true", "false");
t_ne_string = f.yatomic("String")
.parseWith(ValueParsers.NE_STRING);
t_strings = f.yseq(t_string);
t_any = f.yany("Object");
t_params = f.ymap(t_string, t_any);
t_string_params = f.ymap(t_string, t_string);
t_pos_integer = f.yatomic("Positive Integer")
.parseWith(ValueParsers.POS_INTEGER);
t_strictly_pos_integer = f.yatomic("Strictly Positive Integer")
.parseWith(ValueParsers.integerAtLeast(1));
t_uuid = f.yatomic("UUID").parseWith(UUID::fromString);
t_integer_or_range = f.yatomic("Integer or Range")
.parseWith(BoshValueParsers.INTEGER_OR_RANGE);
V2_TOPLEVEL_TYPE = createV2Schema();
V1_TOPLEVEL_TYPE = createV1Schema(V2_TOPLEVEL_TYPE);
@@ -345,25 +351,9 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
return TYPE_UTIL;
}
private YTypedPropertyImpl prop(AbstractType beanType, String name, YType type) {
YTypedPropertyImpl prop = f.yprop(name, type);
prop.setDescriptionProvider(descriptionFor(beanType, name));
return prop;
}
public static Renderable descriptionFor(YType owner, String propName) {
String typeName = owner.toString();
return Renderables.fromClasspath(BoshDeploymentManifestSchema.class, "/desc/"+typeName+"/"+propName);
}
private YTypedPropertyImpl addProp(AbstractType bean, String name, YType type) {
return addProp(bean, bean, name, type);
}
private YTypedPropertyImpl addProp(AbstractType superType, AbstractType bean, String name, YType type) {
YTypedPropertyImpl p = prop(superType, name, type);
bean.addProperty(p);
return p;
@Override
protected String getResourcePathPrefix() {
return "/deployment-manifest/";
}
public Collection<YType> getDefinitionTypes() {

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.bosh;
import org.springframework.ide.vscode.bosh.models.BoshModels;
import org.springframework.ide.vscode.bosh.models.CloudConfigModel;
import org.springframework.ide.vscode.bosh.models.DynamicModelProvider;
import org.springframework.ide.vscode.bosh.models.ReleasesModel;
@@ -41,7 +42,7 @@ import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvid
public class BoshLanguageServer extends SimpleLanguageServer {
private final VscodeCompletionEngineAdapter completionEngine;
private BoshDeploymentManifestSchema schema;
private BoshSchemas schema;
public BoshLanguageServer(BoshCliConfig cliConfig,
DynamicModelProvider<CloudConfigModel> cloudConfigProvider,
@@ -49,11 +50,12 @@ public class BoshLanguageServer extends SimpleLanguageServer {
DynamicModelProvider<ReleasesModel> releasesProvider
) {
super("vscode-bosh");
YamlAstCache asts = new YamlAstCache();
BoshModels models = new BoshModels(cloudConfigProvider, stemcellsProvider, releasesProvider);
SimpleTextDocumentService documents = getTextDocumentService();
ASTTypeCache astTypeCache = new ASTTypeCache();
schema = new BoshDeploymentManifestSchema(asts, astTypeCache, cloudConfigProvider, stemcellsProvider, releasesProvider);
schema = new BoshSchemas(models);
YamlAstCache asts = models.asts;
ASTTypeCache astTypeCache = models.astTypes;
YamlStructureProvider structureProvider = YamlStructureProvider.DEFAULT;
YamlAssistContextProvider contextProvider = new SchemaBasedYamlAssistContextProvider(schema);
@@ -82,11 +84,7 @@ public class BoshLanguageServer extends SimpleLanguageServer {
}
private void validateOnDocumentChange(IReconcileEngine engine, TextDocument doc) {
if (LanguageId.BOSH_DEPLOYMENT.equals(doc.getLanguageId())) {
validateWith(doc.getId(), engine);
} else {
validateWith(doc.getId(), IReconcileEngine.NULL);
}
validateWith(doc.getId(), engine);
}
public void enableSnippets(boolean enable) {

View File

@@ -0,0 +1,67 @@
/*******************************************************************************
* 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 java.util.Collection;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.ide.vscode.bosh.models.BoshModels;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
public class BoshSchemas implements YamlSchema {
public final YTypeFactory f = new YTypeFactory()
.enableTieredProposals(false)
.suggestDeprecatedProperties(false);
public BoshDeploymentManifestSchema getDeploymentSchema() {
return deploymentSchema;
}
private final BoshDeploymentManifestSchema deploymentSchema;
private YTypeUtil typeUtil;
private final YType toplevelType;
private BoshCloudConfigSchema cloudConfigSchema;
public BoshSchemas(BoshModels models) {
this.typeUtil = f.TYPE_UTIL;
this.deploymentSchema = new BoshDeploymentManifestSchema(f, models);
this.cloudConfigSchema = new BoshCloudConfigSchema(f, models);
toplevelType = f.contextAware("BoshSchemas", dc -> {
return LanguageId.BOSH_CLOUD_CONFIG.equals(dc.getDocument().getLanguageId())
? cloudConfigSchema.getTopLevelType()
: deploymentSchema.getTopLevelType();
});
}
@Override
public YType getTopLevelType() {
return toplevelType;
}
@Override
public YTypeUtil getTypeUtil() {
return f.TYPE_UTIL;
}
public Collection<Pair<YType,YType>> getDefAndRefTypes() {
return deploymentSchema.getDefAndRefTypes();
}
public Collection<YType> getDefinitionTypes() {
return deploymentSchema.getDefinitionTypes();
}
}

View File

@@ -0,0 +1,59 @@
/*******************************************************************************
* 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 org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.Renderables;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.AbstractType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YTypedPropertyImpl;
/**
* Some common utility methods useful in implementing Schemas.
*
* @author Kris De Volder
*/
public class SchemaSupport {
protected final YTypeFactory f;
protected SchemaSupport(YTypeFactory f) {
this.f = f;
}
protected String getResourcePathPrefix() {
return "desc";
}
protected YTypedPropertyImpl prop(AbstractType beanType, String name, YType type) {
YTypedPropertyImpl prop = f.yprop(name, type);
prop.setDescriptionProvider(descriptionFor(beanType, name));
return prop;
}
protected Renderable descriptionFor(YType owner, String propName) {
String typeName = owner.toString();
return Renderables.fromClasspath(BoshDeploymentManifestSchema.class, getResourcePathPrefix()+typeName+"/"+propName);
}
protected YTypedPropertyImpl addProp(AbstractType bean, String name, YType type) {
return addProp(bean, bean, name, type);
}
protected YTypedPropertyImpl addProp(AbstractType superType, AbstractType bean, String name, YType type) {
YTypedPropertyImpl p = prop(superType, name, type);
bean.addProperty(p);
return p;
}
}

View File

@@ -0,0 +1,31 @@
/*******************************************************************************
* 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.models;
import org.springframework.ide.vscode.commons.yaml.ast.YamlAstCache;
import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache;
public class BoshModels {
public final YamlAstCache asts = new YamlAstCache();
public final ASTTypeCache astTypes = new ASTTypeCache();
public final DynamicModelProvider<CloudConfigModel> cloudConfigProvider;
public final DynamicModelProvider<StemcellsModel> stemcellsProvider;
public final DynamicModelProvider<ReleasesModel> releasesProvider;
public BoshModels(DynamicModelProvider<CloudConfigModel> cloudConfigProvider,
DynamicModelProvider<StemcellsModel> stemcellsProvider,
DynamicModelProvider<ReleasesModel> releasesProvider) {
this.cloudConfigProvider = cloudConfigProvider;
this.stemcellsProvider = stemcellsProvider;
this.releasesProvider = releasesProvider;
}
}

View File

@@ -15,6 +15,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
import com.google.common.cache.Cache;
@@ -39,6 +40,7 @@ public class CachingModelProvider<T> implements DynamicModelProvider<T> {
private Class<T> modelInterface;
public CachingModelProvider(DynamicModelProvider<T> delegate, Class<T> modelInterface) {
Assert.isNotNull(delegate);
this.delegate = delegate;
this.modelInterface = modelInterface;
}

View File

@@ -148,7 +148,6 @@ public class BoshEditorTest {
editor.assertHoverContains("tags", "Specifies key value pairs to be sent to the CPI for VM tagging");
}
//@Ignore //For now... because not passing yet.
@Test public void reconcileCfManifest() throws Exception {
Editor editor = harness.newEditorFromClasspath("/workspace/cf-deployment-manifest.yml");
cloudConfigProvider.executeCommandWith(() -> {
@@ -254,8 +253,6 @@ public class BoshEditorTest {
editor.assertHoverContains("name", "Full name of a matching stemcell. Either `name` or `os` keys can be specified.");
}
@Test public void releasesBlockCompletions() throws Exception {
harness.getServer().enableSnippets(false);
Editor editor = harness.newEditor(
@@ -1841,4 +1838,61 @@ public class BoshEditorTest {
);
}
@Test public void cloudconfigReconcile() throws Exception {
Editor editor = harness.newEditor(LanguageId.BOSH_CLOUD_CONFIG,
"bogus: bad\n" +
"azs:\n" +
"- name: z1\n" +
" cloud_properties: {availability_zone: us-east-1a}\n" +
"- name: z2\n" +
" cloud_properties: {availability_zone: us-east-1b}\n" +
"\n" +
"vm_types:\n" +
"- name: small\n" +
" cloud_properties:\n" +
" instance_type: t2.micro\n" +
" ephemeral_disk: {size: 3000, type: gp2}\n" +
"- name: medium\n" +
" cloud_properties:\n" +
" instance_type: m3.medium\n" +
" ephemeral_disk: {size: 30000, type: gp2}\n" +
"\n" +
"disk_types:\n" +
"- name: small\n" +
" disk_size: 3000\n" +
" cloud_properties: {type: gp2}\n" +
"- name: large\n" +
" disk_size: 50_000\n" +
" cloud_properties: {type: gp2}\n" +
"\n" +
"networks:\n" +
"- name: private\n" +
" type: manual\n" +
" subnets:\n" +
" - range: 10.10.0.0/24\n" +
" gateway: 10.10.0.1\n" +
" az: z1\n" +
" static: [10.10.0.62]\n" +
" dns: [10.10.0.2]\n" +
" cloud_properties: {subnet: subnet-f2744a86}\n" +
" - range: 10.10.64.0/24\n" +
" gateway: 10.10.64.1\n" +
" az: z2\n" +
" static: [10.10.64.121, 10.10.64.122]\n" +
" dns: [10.10.0.2]\n" +
" cloud_properties: {subnet: subnet-eb8bd3ad}\n" +
"- name: vip\n" +
" type: vip\n" +
"\n" +
"compilation:\n" +
" workers: 5\n" +
" reuse_compilation_vms: true\n" +
" az: z1\n" +
" vm_type: medium\n" +
" network: private\n"
);
editor.assertProblems("bogus|Unknown property");
}
}

View File

@@ -13,19 +13,16 @@ package org.springframework.ide.vscode.bosh;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.springframework.ide.vscode.bosh.models.BoshModels;
import org.springframework.ide.vscode.bosh.snippets.SchemaBasedSnippetGenerator;
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
import org.springframework.ide.vscode.commons.yaml.ast.YamlAstCache;
import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
public class SchemaBasedSnippetGeneratorTest {
private ASTTypeCache astTypes = new ASTTypeCache();
private YamlAstCache asts = new YamlAstCache();
private BoshDeploymentManifestSchema schema = new BoshDeploymentManifestSchema(asts, astTypes, (dc) -> null, (dc) -> null, (dc) -> null);
private BoshDeploymentManifestSchema schema = new BoshSchemas(new BoshModels((dc) -> null, (dc) -> null, (dc) -> null)).getDeploymentSchema();
private YTypeUtil typeUtil = schema.getTypeUtil();
private SchemaBasedSnippetGenerator generator = new SchemaBasedSnippetGenerator(typeUtil, SnippetBuilder::new);
@@ -60,7 +57,6 @@ public class SchemaBasedSnippetGeneratorTest {
,
generator.getSnippets(v2Schema).iterator().next().getSnippet()
);
System.out.println();
}
}

View File

@@ -10,8 +10,6 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.yaml.schema;
import java.util.Collection;
import org.springframework.ide.vscode.commons.util.IntegerRange;
/**

View File

@@ -1,7 +1,8 @@
# Bosh Deployment Manifest Editor for Visual Studio Code
This extension provides validation, content assist and documentation hovers
for editing [Bosh](https://bosh.io/) Deployment Manifest files.
for editing [Bosh](https://bosh.io/) Deployment Manifest files and
Cloud Configs.
## Functionality
@@ -63,9 +64,10 @@ errors.
The Bosh editor automatically activates when the name of the `.yml` file you are editing
follows a certain pattern:
- `**/*deployment*.yml` : activates support for bosh manifest file.
- `**/*deployment*.yml` : activates support for Bosh manifest file.
- `**/*cloud-config*.yml` : activates support for Bosh cloud config.
You can also define your own patterns and map them to the language-id `bosh-deployment-manifest`
You can also define your own patterns and map them to the language-id `bosh-deployment-manifest` or `bosh-cloud-config`
by defining `files.associations` in workspace settings.
See [vscode documentation](https://code.visualstudio.com/Docs/languages/overview#_adding-a-file-extension-to-a-language) for details.

View File

@@ -27,6 +27,15 @@
],
"contributes": {
"languages": [
{
"id": "bosh-cloud-config",
"aliases": [
"Bosh Cloud Config"
],
"filenamePatterns": [
"*cloud-config*.yml"
]
},
{
"id": "bosh-deployment-manifest",
"aliases": [
@@ -43,6 +52,11 @@
"language": "bosh-deployment-manifest",
"scopeName": "source.yaml",
"path": "./yaml-support/yaml.tmLanguage"
},
{
"language": "bosh-cloud-config",
"scopeName": "source.yaml",
"path": "./yaml-support/yaml.tmLanguage"
}
],
"configuration": {