Skip to content

Commit

Permalink
Merge pull request #345 from nblumhardt/update-commands
Browse files Browse the repository at this point in the history
Implement `update` commands for commonly-used entities
  • Loading branch information
nblumhardt authored May 3, 2024
2 parents 2678561 + b5b77cb commit 3f16c7d
Show file tree
Hide file tree
Showing 22 changed files with 405 additions and 31 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,5 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs

.DS_Store
25 changes: 25 additions & 0 deletions src/SeqCli/Cli/Commands/ApiKey/UpdateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © Datalust Pty Ltd and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Seq.Api;
using SeqCli.Connection;

namespace SeqCli.Cli.Commands.ApiKey;

[Command("apikey", "update",
"Update an existing API key",
Example="seqcli apikey update --json '{...}'")]
class UpdateCommand(SeqConnectionFactory connectionFactory):
Shared.UpdateCommand(connectionFactory, "apikey", nameof(SeqConnection.ApiKeys), "API key");

25 changes: 25 additions & 0 deletions src/SeqCli/Cli/Commands/AppInstance/UpdateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © Datalust Pty Ltd and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Seq.Api;
using SeqCli.Connection;

namespace SeqCli.Cli.Commands.AppInstance;

[Command("appinstance", "update",
"Update an existing app instance",
Example="seqcli appinstance update --json '{...}'")]
class UpdateCommand(SeqConnectionFactory connectionFactory):
Shared.UpdateCommand(connectionFactory, "appinstance", nameof(SeqConnection.AppInstances), "app instance");

25 changes: 25 additions & 0 deletions src/SeqCli/Cli/Commands/Feed/UpdateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © Datalust Pty Ltd and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Seq.Api;
using SeqCli.Connection;

namespace SeqCli.Cli.Commands.Feed;

[Command("feed", "update",
"Update an existing NuGet feed",
Example="seqcli feed update --json '{...}'")]
class UpdateCommand(SeqConnectionFactory connectionFactory):
Shared.UpdateCommand(connectionFactory, "feed", nameof(SeqConnection.Feeds), "NuGet feed");

25 changes: 25 additions & 0 deletions src/SeqCli/Cli/Commands/RetentionPolicy/UpdateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © Datalust Pty Ltd and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Seq.Api;
using SeqCli.Connection;

namespace SeqCli.Cli.Commands.RetentionPolicy;

[Command("retention", "update",
"Update an existing retention policy",
Example="seqcli retention update --json '{...}'")]
class UpdateCommand(SeqConnectionFactory connectionFactory):
Shared.UpdateCommand(connectionFactory, "retention", nameof(SeqConnection.RetentionPolicies), "retention policy");

92 changes: 92 additions & 0 deletions src/SeqCli/Cli/Commands/Shared/UpdateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright © Datalust Pty Ltd and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SeqCli.Cli.Features;
using SeqCli.Connection;
using SeqCli.Templates.Ast;
using SeqCli.Templates.Import;
using SeqCli.Templates.Parser;
using SeqCli.Util;
using Serilog;

namespace SeqCli.Cli.Commands.Shared;

abstract class UpdateCommand: Command
{
readonly SeqConnectionFactory _connectionFactory;

readonly ConnectionFeature _connection;
readonly string _resourceGroupName;
readonly string _entityName;

string? _json;
bool _jsonStdin;

protected UpdateCommand(SeqConnectionFactory connectionFactory, string commandGroupName, string resourceGroupName, string? entityName = null)
{
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
_resourceGroupName = resourceGroupName;
_entityName = entityName ?? commandGroupName;

Options.Add(
"json=",
$"The updated {_entityName} in JSON format; this can be produced using `seqcli {commandGroupName} list --json`",
p => _json = ArgumentString.Normalize(p));

Options.Add(
"json-stdin",
$"Read the updated {_entityName} as JSON from `STDIN`",
_ => _jsonStdin = true);

_connection = Enable<ConnectionFeature>();
}

protected override async Task<int> Run()
{
var connection = _connectionFactory.Connect(_connection);

if (_json == null && !_jsonStdin)
{
Log.Error("One of either `--json` or `--json-stdin` must be specified");
return 1;
}

var json = _json ?? await Console.In.ReadToEndAsync();

if (!JsonTemplateParser.TryParse(json, out var template, out var error, out _))
{
Log.Error("The {EntityName} JSON could not be parsed: {Error}", _entityName, error);
return 1;
}

if (template is not JsonTemplateObject obj ||
!obj.Members.TryGetValue("Id", out var idValue) ||
idValue is not JsonTemplateString id)
{
Log.Error("The {EntityName} JSON must be an object literal with a valid string `Id` property", _entityName);
return 1;
}

var templateName = "JSON";
var entityTemplate = new EntityTemplate(_resourceGroupName, templateName, template);
var state = new TemplateImportState();
state.AddOrUpdateCreatedEntityId(templateName, id.Value);
await TemplateSetImporter.ImportAsync([entityTemplate], connection, new Dictionary<string, JsonTemplate>(), state, merge: false);

return 0;
}
}
25 changes: 25 additions & 0 deletions src/SeqCli/Cli/Commands/Signal/UpdateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © Datalust Pty Ltd and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Seq.Api;
using SeqCli.Connection;

namespace SeqCli.Cli.Commands.Signal;

[Command("signal", "update",
"Update an existing signal",
Example="seqcli signal update --json '{...}'")]
class UpdateCommand(SeqConnectionFactory connectionFactory):
Shared.UpdateCommand(connectionFactory, "signal", nameof(SeqConnection.Signals));

25 changes: 25 additions & 0 deletions src/SeqCli/Cli/Commands/User/UpdateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © Datalust Pty Ltd and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Seq.Api;
using SeqCli.Connection;

namespace SeqCli.Cli.Commands.User;

[Command("user", "update",
"Update an existing user",
Example="seqcli user update --json '{...}'")]
class UpdateCommand(SeqConnectionFactory connectionFactory):
Shared.UpdateCommand(connectionFactory, "user", nameof(SeqConnection.Users));

25 changes: 25 additions & 0 deletions src/SeqCli/Cli/Commands/Workspace/UpdateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © Datalust Pty Ltd and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Seq.Api;
using SeqCli.Connection;

namespace SeqCli.Cli.Commands.Workspace;

[Command("workspace", "update",
"Update an existing workspace",
Example="seqcli workspace update --json '{...}'")]
class UpdateCommand(SeqConnectionFactory connectionFactory):
Shared.UpdateCommand(connectionFactory, "workspace", nameof(SeqConnection.Workspaces));

2 changes: 1 addition & 1 deletion src/SeqCli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ static async Task<int> Main(string[] args)
}
finally
{
Log.CloseAndFlush();
await Log.CloseAndFlushAsync();
}
}
}
9 changes: 9 additions & 0 deletions src/SeqCli/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"SeqCli": {
"commandName": "Project",
"commandLineArgs": "signal update --json-stdin"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public static bool Load(string path, [MaybeNullWhen(false)] out EntityTemplate t
if (root is not JsonTemplateObject rootDictionary ||
!rootDictionary.Members.TryGetValue("$entity", out var resourceToken) ||
resourceToken is not JsonTemplateString resource ||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
resource.Value is null)
{
template = null;
Expand Down
6 changes: 3 additions & 3 deletions src/SeqCli/Templates/Import/TemplateSetImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ static class TemplateSetImporter
TemplateImportState state,
bool merge)
{
var ordering = new[] {"users", "signals", "apps", "appinstances",
var ordering = new List<string> {"users", "signals", "apps", "appinstances",
"dashboards", "sqlqueries", "workspaces", "retentionpolicies",
"alerts", "expressionindexes"}.ToList();
"alerts", "expressionindexes"};

var sorted = templates.OrderBy(t => ordering.IndexOf(t.ResourceGroup));

Expand Down Expand Up @@ -77,7 +77,7 @@ static class TemplateSetImporter
var resourceGroup = await connection.Client.GetAsync<ResourceGroup>(apiRoot, link.Key);

// ExpressionIndexes with mapped ids or identical expressions are assumed to be equivalent.
var immutableTarget = template.ResourceGroup != "ExpressionIndexes";
var immutableTarget = template.ResourceGroup.Equals("ExpressionIndexes", StringComparison.OrdinalIgnoreCase);

if (state.TryGetCreatedEntityId(template.Name, out var existingId) &&
await CheckEntityExistenceAsync(connection, resourceGroup, existingId))
Expand Down
Loading

0 comments on commit 3f16c7d

Please sign in to comment.