Skip to content

Commit

Permalink
Api implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Binali Rustamov committed Dec 21, 2019
1 parent d05edc5 commit 70f94b7
Show file tree
Hide file tree
Showing 15 changed files with 127 additions and 71 deletions.
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Dockerfile
**/*/
!PortainerClient/bin/Release/netcoreapp3.1/publish/
8 changes: 8 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM mcr.microsoft.com/dotnet/core/runtime:2.2.5-bionic

WORKDIR /app

COPY Rustamov.PortainerClient/bin/Release/netcoreapp2.2/publish/ .

RUN echo '#!/bin/bash\n dotnet /app/Rustamov.PortainerClient.dll "$@"' > /usr/bin/portainerctl && \
chmod +x /usr/bin/portainerctl
14 changes: 14 additions & 0 deletions PortainerClient/Api/Base/BaseApiHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using RestSharp;

namespace PortainerClient.Api
{
public static class BaseApiHelpers
{
public static void AddParameters(this RestRequest request,
IEnumerable<(string paramName, object paramValue)> parameters)
{
foreach (var (paramName, paramValue) in parameters) request.AddParameter(paramName, paramValue);
}
}
}
28 changes: 23 additions & 5 deletions PortainerClient/Api/Base/BaseApiService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using PortainerClient.Api.Model;
using PortainerClient.Helpers;
using RestSharp;
using RestSharp.Authenticators;
Expand All @@ -22,14 +23,31 @@ private RestClient ResolveClient()
protected T Get<T>(string resource, params (string paramName, object paramValue)[] parameters) where T : new()
{
var request = new RestRequest(resource, Method.GET);
foreach (var (paramName, paramValue) in parameters) request.AddParameter(paramName, paramValue);
request.AddParameters(parameters);
var response = ResolveClient().Execute<T>(request);
if (!response.IsSuccessful)
if (response.IsSuccessful) return response.Data;
throw ParseError(resource, response.Content);
}

protected void Delete(string resource, params (string paramName, object paramValue)[] parameters)
{
var request = new RestRequest(resource, Method.DELETE);
request.AddParameters(parameters);
var response = ResolveClient().Execute(request);
if (response.IsSuccessful) return;
throw ParseError(resource, response.Content);
}

private static InvalidOperationException ParseError(string resource, string responseData)
{
ApiError errorInfo = null;
if (responseData != null)
{
throw new InvalidOperationException($"Request {resource} error: {response.Content}");
errorInfo = SimpleJson.DeserializeObject<ApiError>(responseData);
}

return response.Data;
return new InvalidOperationException(
$"Request {resource}: {(errorInfo != null ? $"{errorInfo.message}, details: {errorInfo.details}" : "no information")}");
}
}
}
}
8 changes: 8 additions & 0 deletions PortainerClient/Api/Model/ApiError.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace PortainerClient.Api.Model
{
public class ApiError
{
public string message { get; set; }
public string details { get; set; }
}
}
7 changes: 7 additions & 0 deletions PortainerClient/Api/Model/StackFileInspect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace PortainerClient.Api.Model
{
public class StackFileInspect
{
public string StackFileContent { get; set; }
}
}
11 changes: 0 additions & 11 deletions PortainerClient/Api/StacksApi.cs

This file was deleted.

23 changes: 23 additions & 0 deletions PortainerClient/Api/StacksApiService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.IO;
using PortainerClient.Api;
using PortainerClient.Api.Model;

namespace PortainerClient.Command.Stack
{
public class StacksApiService : BaseApiService
{
public IEnumerable<StackInfo> GetStacks() => Get<List<StackInfo>>("stacks");

public string GetStackFile(int stackId) => Get<StackFileInspect>($"stacks/{stackId}/file").StackFileContent;

public StackInfo GetStackInfo(in int stackId) => Get<StackInfo>($"stacks/{stackId}");

public void RemoveStack(int stackId) => Delete($"stacks/{stackId}");

public object DeployStack(in int endpointId, string name, string swarmID, string stackFilePath, string env)
{
throw new System.NotImplementedException();
}
}
}
12 changes: 5 additions & 7 deletions PortainerClient/Command/Stack/StackCmd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@
namespace PortainerClient.Command
{
[Command(Name = "stack", Description = "Docker Stack management commands")]
[Subcommand(
typeof(StackLsCmd)
// ,
// typeof(StackGetFileCmd),
[Subcommand(typeof(StackLsCmd),
typeof(StackGetFileCmd),
// typeof(StackDeployCmd),
// typeof(StackUpdateCmd),
// typeof(StackRmCmd),
// typeof(StackInspectCmd)
typeof(StackRmCmd),
typeof(StackInspectCmd)
)]
public class StackCmd : ICommand
{
public int OnExecute(CommandLineApplication app, IConsole console) =>
CmdHelpers.SpecifyCommandResult(app, console);
}
}
}
16 changes: 7 additions & 9 deletions PortainerClient/Command/Stack/StackDeployCmd.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.IO;
using IO.Swagger.Api;
using McMaster.Extensions.CommandLineUtils;
using Newtonsoft.Json;
using PortainerClient.Helpers;
using RestSharp;

namespace PortainerClient.Command.Stack
{
[Command("deploy", "Deploy new Swarm stack from file")]
public class StackDeployCmd : BaseApiCommand<StacksApi>
public class StackDeployCmd : BaseApiCommand<StacksApiService>
{
[Option("--file", "Docker Swarm stack definition file path", CommandOptionType.SingleValue, ShortName = "f")]
[Required]
Expand Down Expand Up @@ -42,15 +41,14 @@ public override void Do(CommandLineApplication app, IConsole console)
}

var stackEnvs = CmdHelpers.ParseEnvs(Envs);

var fileStream = File.OpenRead(FilePath);
// 1 - swarm stack
console.WriteLine("Sending deploy request to Portainer...");
var result = ApiClient.StackCreate(type: 1, method: "file", endpointId: EndpointId, body: null,
var result = ApiClient.DeployStack(endpointId: EndpointId,
name: StackName,
endpointID: EndpointId.ToString(), swarmID: SwarmId, file: fileStream,
env: JsonConvert.SerializeObject(stackEnvs));
swarmID: SwarmId,
stackFilePath: FilePath,
env: SimpleJson.SerializeObject(stackEnvs));
console.WriteLine("Stack deployed.");
}
}
}
}
11 changes: 4 additions & 7 deletions PortainerClient/Command/Stack/StackGetFileCmd.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
using System;
using System.ComponentModel.DataAnnotations;
using IO.Swagger.Api;
using McMaster.Extensions.CommandLineUtils;
using PortainerClient.Helpers;

namespace PortainerClient.Command.Stack
{
[Command(Name = "getfile", Description = "Get compose file of stack")]
public class StackGetFileCmd : BaseApiCommand<StacksApi>
public class StackGetFileCmd : BaseApiCommand<StacksApiService>
{
[Argument(0, "stackId", "Stack instance identifier")]
[Required]
public int StackId { get; set; }

public override void Do(CommandLineApplication app, IConsole console)
{
var data = ApiClient.StackFileInspect(StackId);
console.Write(data.StackFileContent);
var data = ApiClient.GetStackFile(StackId);
console.Write(data);
}
}
}
}
7 changes: 3 additions & 4 deletions PortainerClient/Command/Stack/StackInspectCmd.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
using System.ComponentModel.DataAnnotations;
using IO.Swagger.Api;
using McMaster.Extensions.CommandLineUtils;
using YamlDotNet.Serialization;

namespace PortainerClient.Command.Stack
{
[Command("inspect", Description = "Show information about stack")]
public class StackInspectCmd : BaseApiCommand<StacksApi>
public class StackInspectCmd : BaseApiCommand<StacksApiService>
{
[Argument(0, "stackId", "Stack identifier")]
[Required]
public int StackId { get; set; }

public override void Do(CommandLineApplication app, IConsole console)
{
var stackInfo = ApiClient.StackInspect(StackId);
var stackInfo = ApiClient.GetStackInfo(StackId);
console.WriteLine(new Serializer().Serialize(stackInfo));
}
}
}
}
7 changes: 3 additions & 4 deletions PortainerClient/Command/Stack/StackRmCmd.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using System.ComponentModel.DataAnnotations;
using IO.Swagger.Api;
using McMaster.Extensions.CommandLineUtils;

namespace PortainerClient.Command.Stack
{
[Command("rm", Description = "Remove stack from portainer and Docker Swarm")]
public class StackRmCmd : BaseApiCommand<StacksApi>
public class StackRmCmd : BaseApiCommand<StacksApiService>
{
[Argument(0, "stackId", "Stack identifier")]
[Required]
Expand All @@ -21,8 +20,8 @@ public override void Do(CommandLineApplication app, IConsole console)
}

console.Write("Sending remove request to Portainer...");
ApiClient.StackDelete(StackId, null, null);
ApiClient.RemoveStack(StackId);
console.WriteLine("Removed!");
}
}
}
}
39 changes: 19 additions & 20 deletions PortainerClient/Helpers/CmdHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using McMaster.Extensions.CommandLineUtils;
using PortainerClient.Api.Model;

namespace PortainerClient.Helpers
{
Expand All @@ -20,24 +21,22 @@ public static int WriteError(this IConsole console, Exception exception)
return 1;
}

// public static List<StackEnv> ParseEnvs(string[] envs)
// {
// var stackEnvs = new List<StackEnv>();
// if (envs != null)
// {
// foreach (var env in envs)
// {
// if (!env.Contains("="))
// {
// throw new Exception($"Incorrect env var format: {env}");
// }
//
// var splited = env.Split("=", 2);
// stackEnvs.Add(new StackEnv {Name = splited[0], Value = splited[1]});
// }
// }
//
// return stackEnvs;
// }
public static List<StackEnv> ParseEnvs(string[] envs)
{
var stackEnvs = new List<StackEnv>();
if (envs == null) return stackEnvs;
foreach (var env in envs)
{
if (!env.Contains("="))
{
throw new Exception($"Incorrect env var format: {env}");
}

var splited = env.Split("=", 2);
stackEnvs.Add(new StackEnv {Name = splited[0], Value = splited[1]});
}

return stackEnvs;
}
}
}
}
4 changes: 0 additions & 4 deletions PortainerClient/PortainerClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@
</ItemGroup>

<ItemGroup>
<Compile Remove="Command\Stack\StackDeployCmd.cs" />
<Compile Remove="Command\Stack\StackGetFileCmd.cs" />
<Compile Remove="Command\Stack\StackInspectCmd.cs" />
<Compile Remove="Command\Stack\StackRmCmd.cs" />
<Compile Remove="Command\Stack\StackUpdateCmd.cs" />
</ItemGroup>

Expand Down

0 comments on commit 70f94b7

Please sign in to comment.