From 42bea2a14458b56a5a12e4ff7ee22026214c3b00 Mon Sep 17 00:00:00 2001 From: Zachary Wasserman Date: Tue, 7 Apr 2020 15:12:32 -0700 Subject: [PATCH] Implement manual labels "Manual" labels can be specified by hostname, allowing users to specify the membership of a label without having to use a dynamic query. See the included documentation. --- docs/cli/file-format.md | 16 ++ .../components/forms/LabelForm/LabelForm.jsx | 25 ++- .../components/forms/LabelForm/validate.js | 4 +- .../hosts/ManageHostsPage/ManageHostsPage.jsx | 10 +- server/datastore/datastore_labels_test.go | 36 ++++- server/datastore/mysql/hosts.go | 2 +- server/datastore/mysql/labels.go | 148 ++++++++++++++++-- .../20200407120000_AddLabelMembershipType.go | 35 +++++ server/datastore/mysql/mysql.go | 2 +- server/kolide/labels.go | 86 ++++++++-- server/service/service_labels.go | 10 ++ server/test/new_objects.go | 7 +- 12 files changed, 332 insertions(+), 49 deletions(-) create mode 100644 server/datastore/mysql/migrations/tables/20200407120000_AddLabelMembershipType.go diff --git a/docs/cli/file-format.md b/docs/cli/file-format.md index cdb55d9b7d..e4f3192581 100644 --- a/docs/cli/file-format.md +++ b/docs/cli/file-format.md @@ -155,6 +155,22 @@ spec: ); ``` +Labels can also be "manually managed". When defining the label, reference hosts +by hostname: + +```yaml +apiVersion: v1 +kind: label +spec: + name: Manually Managed Example + label_membership_type: manual + hosts: + - hostname1 + - hostname2 + - hostname3 +``` + + ## Osquery Configuration Options The following file describes options returned to osqueryd when it checks for configuration. See the [osquery documentation](https://osquery.readthedocs.io/en/stable/deployment/configuration/#options) for the available options. Existing options will be over-written by the application of this file. diff --git a/frontend/components/forms/LabelForm/LabelForm.jsx b/frontend/components/forms/LabelForm/LabelForm.jsx index 647a34991c..fc5d1f84ef 100644 --- a/frontend/components/forms/LabelForm/LabelForm.jsx +++ b/frontend/components/forms/LabelForm/LabelForm.jsx @@ -22,6 +22,9 @@ class LabelForm extends Component { platform: formFieldInterface.isRequired, query: formFieldInterface.isRequired, }).isRequired, + formData: PropTypes.shape({ + label_membership_type: PropTypes.string, + }), handleSubmit: PropTypes.func.isRequired, isEdit: PropTypes.bool, onCancel: PropTypes.func.isRequired, @@ -50,24 +53,35 @@ class LabelForm extends Component { } render () { - const { baseError, fields, handleSubmit, isEdit, onCancel } = this.props; + const { baseError, fields, handleSubmit, isEdit, onCancel, formData } = this.props; const { onLoad } = this; + const isBuiltin = formData && (formData.label_type === 'builtin' || formData.type === 'status'); + const isManual = formData && formData.label_membership_type === 'manual'; const headerText = isEdit ? 'Edit Label' : 'New Label'; const saveBtnText = isEdit ? 'Update Label' : 'Save Label'; const aceHintText = isEdit ? 'Label queries are immutable. To change the query, delete this label and create a new one.' : ''; + if (isBuiltin) { + return ( +
+

Built in labels cannot be edited

+
+ ); + } + return (

{headerText}

- {aceHintText}} + hint={aceHintText} handleSubmit={noop} /> + )} {baseError &&
{baseError}
} -
+ {!isManual && + (
-
+
)}