Define (first-level) nested properties for instance_groups

This commit is contained in:
Kris De Volder
2017-07-11 16:53:47 -07:00
parent ac0230689b
commit 53fcb79a0c
18 changed files with 249 additions and 24 deletions

View File

@@ -14,6 +14,7 @@ import java.util.UUID;
import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.Renderables;
import org.springframework.ide.vscode.commons.util.ValueParser;
import org.springframework.ide.vscode.commons.util.ValueParsers;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory;
@@ -55,8 +56,35 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
TOPLEVEL_TYPE = f.ybean("BoshDeploymentManifest");
addProp(TOPLEVEL_TYPE, "name", t_ne_string).isPrimary(true);
addProp(TOPLEVEL_TYPE, "director_uuid", t_uuid)
.isRequired(true);
addProp(TOPLEVEL_TYPE, "director_uuid", t_uuid).isDeprecated(
"bosh v2 CLI no longer checks or requires director_uuid in the deployment manifest. " +
"To achieve similar safety make sure to give unique deployment names across environments."
);
YAtomicType t_network_name = f.yatomic("NetworkName"); //TODO: resolve from 'cloud config' https://www.pivotaltracker.com/story/show/148712155
t_network_name.parseWith(ValueParsers.NE_STRING);
YAtomicType t_disk_type = f.yatomic("DiskType"); //TODO: resolve from 'cloud config' https://www.pivotaltracker.com/story/show/148704001
t_disk_type.parseWith(ValueParsers.NE_STRING);
YAtomicType t_stemcell_alias = f.yatomic("StemcellAlias"); //TODO: resolve from 'stemcells block' https://www.pivotaltracker.com/story/show/148706041
t_stemcell_alias.parseWith(ValueParsers.NE_STRING);
YAtomicType t_vm_extension = f.yatomic("VMExtension"); //TODO: resolve dynamically from 'cloud config' ? https://www.pivotaltracker.com/story/show/148703877
t_vm_extension.parseWith(ValueParsers.NE_STRING);
YAtomicType t_vm_type = f.yatomic("VMType"); //TODO: resolve dynamically from 'cloud config' ? https://www.pivotaltracker.com/story/show/148686169
t_vm_type.parseWith(ValueParsers.NE_STRING);
YAtomicType t_az = f.yatomic("AvailabilityZone"); //TODO: resolve dynamically from 'cloud config': https://www.pivotaltracker.com/story/show/148704481
t_az.parseWith(ValueParsers.NE_STRING);
YBeanType t_network = f.ybean("Network");
addProp(t_network, "name", t_network_name).isRequired(true);
YBeanType t_instance_group_env = f.ybean("InstanceGroupEnv");
addProp(t_instance_group_env, "npsh", t_params);
addProp(t_instance_group_env, "password", t_ne_string);
YAtomicType t_version = f.yatomic("Version");
t_version.addHints("latest");
@@ -77,8 +105,31 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
YType t_update = t_params; //TODO: https://www.pivotaltracker.com/story/show/148627121
addProp(TOPLEVEL_TYPE, "update", t_update).isRequired(true);
YType t_instance_group = t_params; //TODO: https://www.pivotaltracker.com/story/show/148627211
YBeanType t_job = f.ybean("Job");
addProp(t_job, "name", t_ne_string).isPrimary(true);
addProp(t_job, "release", t_ne_string).isRequired(true);
addProp(t_job, "consumes", t_params);
addProp(t_job, "provides", t_params);
addProp(t_job, "properties", t_params).isRequired(true);
YBeanType t_instance_group = f.ybean("InstanceGroup");
addProp(t_instance_group, "name", t_ne_string).isPrimary(true);
addProp(t_instance_group, "azs", f.yseq(t_az)).isRequired(true);
addProp(t_instance_group, "instances", t_pos_integer).isRequired(true); //Strictly positive? Or zero is okay?
addProp(t_instance_group, "jobs", f.yseq(t_job)).isRequired(true);
addProp(t_instance_group, "vm_type", t_vm_type).isRequired(true);
addProp(t_instance_group, "vm_extensions", f.yseq(t_vm_extension));
addProp(t_instance_group, "stemcell", t_stemcell_alias).isRequired(true);
addProp(t_instance_group, "persistent_disk_type", t_disk_type);
addProp(t_instance_group, "networks", f.yseq(t_network));
addProp(t_instance_group, "update", t_update);
YType t_migration = t_params; //TODO: https://www.pivotaltracker.com/story/show/148712595
addProp(t_instance_group, "migrated_from", f.yseq(t_migration));
addProp(t_instance_group, "lifecycle", f.yenum("WorkloadType", "service", "errand"));
addProp(t_instance_group, "properties", t_params).isDeprecated("Deprecated in favor of job level properties and links");
addProp(t_instance_group, "env", t_instance_group_env);
addProp(TOPLEVEL_TYPE, "instance_groups", f.yseq(t_instance_group)).isRequired(true);
addProp(TOPLEVEL_TYPE, "properties", t_params).isDeprecated("Deprecated in favor of job level properties and links");

View File

@@ -0,0 +1 @@
*Required*. List of AZs associated with this instance group (should only be used when using [first class AZs](https://bosh.io/docs/azs.html) ). Example: `[z1, z2]`.

View File

@@ -0,0 +1 @@
*Optional*. Specifies advanced BOSH Agent configuration for each instance in the group.

View File

@@ -0,0 +1 @@
*Required*. The number of instances in this group. Each instance is a VM.

View File

@@ -0,0 +1 @@
*Required*. Specifies the name and release of jobs that will be installed on each instance.

View File

@@ -0,0 +1 @@
Specifies the kind of workload the instance group represents. Valid values are `service` and `errand`; defaults to `service`. A `service` runs indefinitely and restarts if it fails. An `errand` starts with a manual trigger and does not restart if it fails.

View File

@@ -0,0 +1 @@
*Optional*. Specific migration settings for this instance group. Use this to [rename and/or migrate instance groups](https://bosh.io/docs/migrated-from.html).

View File

@@ -0,0 +1 @@
*Required*. A unique name used to identify and reference the instance group.

View File

@@ -0,0 +1 @@
*Required*. Specifies the networks this instance requires.

View File

@@ -0,0 +1 @@
*Optional*. A valid disk type name from the cloud config. [Read more about persistent disks](https://bosh.io/docs/persistent-disks.html)

View File

@@ -0,0 +1 @@
*Optional*. Specifies instance group properties. Deprecated in favor of job level properties and links.

View File

@@ -0,0 +1 @@
*Required*. A valid stemcell alias from the Stemcells Block.

View File

@@ -0,0 +1 @@
*Optional*. Specific update settings for this instance group. Use this to override [global job update settings](https://bosh.io/docs/manifest-v2.html#update) on a per-instance-group basis.

View File

@@ -0,0 +1 @@
*Optional*. A valid list of VM extension names from the cloud config.

View File

@@ -0,0 +1 @@
*Required*. A valid VM type name from the cloud config.

View File

@@ -11,6 +11,7 @@
package org.springframework.ide.vscode.concourse;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.ide.vscode.bosh.BoshLanguageServer;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
@@ -98,6 +99,7 @@ public class BoshEditorTest {
"blah: hoooo\n"
);
editor.assertProblems(
"director_uuid|bosh v2 CLI no longer checks or requires",
"properties|Deprecated in favor of job level properties and links",
"blah|Unknown property"
);
@@ -128,13 +130,12 @@ public class BoshEditorTest {
editor.assertCompletions(
"name: blah\n" +
"director_uuid: <*>"
"instance_groups:\n" +
"- name: <*>"
, // ============
"name: blah\n" +
"instance_groups:\n- <*>"
, // ============
"name: blah\n" +
"releases:\n- <*>"
"releases:\n" +
"- name: <*>"
, // ============
"name: blah\n" +
"stemcells:\n- <*>"
@@ -149,6 +150,9 @@ public class BoshEditorTest {
"variables:\n- <*>"
, // ============
"name: blah\n" +
"director_uuid: <*>"
, // ============
"name: blah\n" +
"properties:\n <*>"
);
}
@@ -186,7 +190,7 @@ public class BoshEditorTest {
editor.assertProblems(
"-|One of [name, os] is required",
"-|[alias, version] are required",
"}|[director_uuid, instance_groups, name, releases, update] are required"
"}|[instance_groups, name, releases, update] are required"
);
}
@@ -236,12 +240,164 @@ public class BoshEditorTest {
editor.assertCompletionLabels("latest");
}
@Test public void temp_instanceGroupsCompletions() throws Exception {
Editor editor = harness.newEditor(
"instance_groups:\n" +
"- name: foo-group\n" +
" job<*>"
);
editor.assertCompletions(
"instance_groups:\n" +
"- name: foo-group\n" +
" jobs:\n" +
" - name: <*>"
);
}
@Test public void instanceGroupsCompletions() throws Exception {
Editor editor = harness.newEditor(
"instance_groups:\n" +
"- <*>"
);
editor.assertCompletions(
"instance_groups:\n" +
"- name: <*>"
);
editor = harness.newEditor(
"instance_groups:\n" +
"- name: foo-group\n" +
" <*>"
);
editor.assertCompletions(PLAIN_COMPLETION,
"instance_groups:\n" +
"- name: foo-group\n" +
" azs:\n" +
" - <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" env:\n" +
" <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" instances: <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" jobs:\n" +
" - name: <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" lifecycle: <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" migrated_from:\n" +
" - <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" networks:\n" +
" - name: <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" persistent_disk_type: <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" stemcell: <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" update:\n" +
" <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" vm_extensions:\n" +
" - <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" vm_type: <*>"
, // =============
"instance_groups:\n" +
"- name: foo-group\n" +
" properties:\n" +
" <*>"
);
}
@Test public void instanceGroupsHovers() throws Exception {
Editor editor = harness.newEditor(
"instance_groups:\n" +
"- name: redis-master\n" +
" properties: {}\n" +
" instances: 1\n" +
" azs: [z1, z2]\n" +
" jobs:\n" +
" - name: redis-server\n" +
" release: redis\n" +
" properties:\n" +
" port: 3606\n" +
" vm_type: medium\n" +
" vm_extensions: [public-lbs]\n" +
" stemcell: default\n" +
" persistent_disk_type: medium\n" +
" networks:\n" +
" - name: default\n" +
"\n" +
"- name: redis-slave\n" +
" instances: 2\n" +
" azs: [z1, z2]\n" +
" jobs:\n" +
" - name: redis-server\n" +
" release: redis\n" +
" properties: {}\n" +
" update:\n" +
" canaries: 2\n" +
" lifecycle: errand\n" +
" migrated_from: []\n" +
" env: {}\n" +
" vm_type: medium\n" +
" stemcell: default\n" +
" persistent_disk_type: medium\n" +
" networks:\n" +
" - name: default\n"
);
editor.assertHoverContains("name", "A unique name used to identify and reference the instance group.");
editor.assertHoverContains("azs", "List of AZs associated with this instance group");
editor.assertHoverContains("instances", "The number of instances in this group");
editor.assertHoverContains("jobs", "Specifies the name and release of jobs that will be installed on each instance.");
editor.assertHoverContains("vm_type", "A valid VM type name from the cloud config");
editor.assertHoverContains("vm_extensions", "A valid list of VM extension names from the cloud config");
editor.assertHoverContains("stemcell", "A valid stemcell alias from the Stemcells Block");
editor.assertHoverContains("persistent_disk_type", "A valid disk type name from the cloud config.");
editor.assertHoverContains("networks", "Specifies the networks this instance requires");
editor.assertHoverContains("update", "Specific update settings for this instance group");
editor.assertHoverContains("migrated_from", "Specific migration settings for this instance group.");
editor.assertHoverContains("lifecycle", "Specifies the kind of workload");
editor.assertHoverContains("properties", "Specifies instance group properties");
editor.assertHoverContains("env", "Specifies advanced BOSH Agent configuration");
}
@Ignore @Test public void instanceGroups_job_hovers() throws Exception {
//For the nested properties of instance_groups.jobs
throw new IllegalStateException("Implement a test please!");
}
@Ignore @Test public void instanceGroups_network_hovers() throws Exception {
//For the nested properties of instance_groups.networks
throw new IllegalStateException("Implement a test please!");
}
@Ignore @Test public void instanceGroups_env_hovers() throws Exception {
throw new IllegalStateException("Implement a test please!");
}
}

View File

@@ -54,7 +54,7 @@ public class AppendTextBuilder {
//ready to enter sequence element on next line
newline(text, indent);
text.append("- ");
singleRequiredProperty(typeUtil.getDomainType(type), indent+2, text);
singleMostImportantProperty(typeUtil.getDomainType(type), indent+2, text);
//Yes using 2 here instead of YamlIndentUtil.INDENT_BY is deliberate. It's the same value (now),
// but the 2 used here is the width of the "- " which should determine nested indent level for things to
// line up properly.
@@ -66,14 +66,18 @@ public class AppendTextBuilder {
}
}
private void singleRequiredProperty(YType type, int indent, StringBuilder text) {
private void singleMostImportantProperty(YType type, int indent, StringBuilder text) {
if (type!=null) {
YTypedProperty requireProp = Streams.getSingle(typeUtil.getProperties(type).stream()
.filter(p -> p.isRequired()));
if (requireProp!=null) {
text.append(requireProp.getName());
YTypedProperty singleProp = Streams.getSingle(typeUtil.getProperties(type).stream()
.filter(p -> p.isPrimary()));
if (singleProp==null) {
singleProp = Streams.getSingle(typeUtil.getProperties(type).stream()
.filter(p -> p.isRequired()));
}
if (singleProp!=null) {
text.append(singleProp.getName());
text.append(':');
build(requireProp.getType(), indent+YamlIndentUtil.INDENT_BY, text);
build(singleProp.getType(), indent+YamlIndentUtil.INDENT_BY, text);
}
}
}

View File

@@ -473,7 +473,7 @@ public class ConcourseEditorTest {
editor = harness.newEditor("jo<*>");
editor.assertCompletions(
"jobs:\n"+
"- <*>"
"- name: <*>"
);
}
@@ -486,19 +486,19 @@ public class ConcourseEditorTest {
"- name: <*>"
, // --------------
"jobs:\n" +
"- <*>"
"- name: <*>"
, // ---------------
"resource_types:\n" +
"- <*>"
"- name: <*>"
, // ---------------
"resources:\n"+
"- <*>"
"- name: <*>"
);
editor = harness.newEditor("rety<*>");
editor.assertCompletions(
"resource_types:\n" +
"- <*>"
"- name: <*>"
);
}