Skip to content

Commit

Permalink
Redis auth support + Redis as optional cache (#15)
Browse files Browse the repository at this point in the history
* Update README

* Add redis user & password

* Generalize cache + make redis cache optional

* Update README
  • Loading branch information
encX authored May 31, 2022
1 parent f8f4bb1 commit 695545b
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 32 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ GitLabKit Runner Admin can help improve experience of managing runners.
### How?
#### Main page
Put your group ID in text box and hit enter to go to group page. Simple enough.

![main-page](/doc/images/main-page.png)

#### Group page
Expand All @@ -43,6 +44,7 @@ Displays all runners in the group
- Use the toggle in front of runner name to individually enable/disable it
- Click on job name on the right to navigate back to job page on GitLab
- Click on runner name for runner history page

![group-page](/doc/images/group-page.png)

##### Filters!
Expand Down Expand Up @@ -118,8 +120,10 @@ Settings could be passed to Runner Admin's container using these environment var
| variable | example | required | description |
|---|---|---|---|
| `CONNECTIONS__GITLABSERVER` | `https://gitlab.yourcompany.com` | yes | GitLab server URL |
| `CONNECTIONS__REDISSERVER` | `redis-server:16379` | yes | Redis host |
| `SECRETS__GITLABTOKEN` | `rG2f93ddaz` | yes | GitLab token. Could be a personal token or group token that has sufficient permission to view CI/CD settings in the group |
| `CONNECTIONS__REDISSERVER` | `redis-server:16379` | no | Redis host. If set, it will be used as cache. |
| `SECRETS__REDISUSER` | `username` | no | Redis ACL user. Leave empty if Redis has no ACL user set. |
| `SECRETS__REDISPASSWORD` | `password` | no | Redis password. Could be used alone if Redis has set `requirepass`. Or could be used together with `SECRETS__REDISUSER` for ACL authentication. |
| `LOGTARGETS__SEQ` | `http://seq-server:5341` | no | Runner Admin supports [Seq](https://datalust.co/seq) logger. Use this to set log ingestion URL. |
| `APPLICATIONINSIGHTS__CONNECTIONSTRING` | - | no | Runner Admin supports [Application Insights](https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview) to see application diagnostics. Use this to set connection string from Azure dashboard. |

Expand Down
2 changes: 2 additions & 0 deletions src/GitLabKit.Runner.Core/Configs/Secrets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
public class Secrets
{
public string GitLabToken { get; set; }
public string RedisUser { get; set; }
public string RedisPassword { get; set; }
}
20 changes: 9 additions & 11 deletions src/GitLabKit.Runner.Core/Repositories/GitLabRepository.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
Expand All @@ -13,7 +12,6 @@
using Microsoft.Extensions.Options;
using Nelibur.ObjectMapper;
using Newtonsoft.Json;
using Serilog;

namespace GitLabKit.Runner.Core.Repositories;

Expand All @@ -31,17 +29,17 @@ public interface IGitLabRepository

public class GitLabRepository : IGitLabRepository
{
private readonly IRedisCache _redis;
private readonly ICache _cache;
private readonly IGitLabClient _gitLabClient;
private readonly HttpClient _gitLabHttpClient = new();

private static string GroupRunnerListCacheKey(int id) => $"group_{id}_runnerlist";
private static string GroupInfoCacheKey(int id) => $"group_{id}_info";
private static string RunnerCacheKey(int id) => $"runner_{id}";

public GitLabRepository(IOptions<Secrets> secretsOptions, IOptions<Connections> connectionOptions, IRedisCache redis)
public GitLabRepository(IOptions<Secrets> secretsOptions, IOptions<Connections> connectionOptions, ICache cache)
{
_redis = redis;
_cache = cache;
_gitLabHttpClient.BaseAddress = new Uri($"{connectionOptions.Value.GitLabServer}/api/v4/");
_gitLabHttpClient.DefaultRequestHeaders.Add("PRIVATE-TOKEN", secretsOptions.Value.GitLabToken);
_gitLabClient = new GitLabClient(connectionOptions.Value.GitLabServer, secretsOptions.Value.GitLabToken);
Expand All @@ -51,7 +49,7 @@ public async Task<Group> GetGroup(int groupId)
{
var dataFunc = () => _gitLabClient.Groups.GetAsync(groupId);

var groupInfo = await _redis.GetCached(GroupInfoCacheKey(groupId), dataFunc, TimeSpan.FromDays(1));
var groupInfo = await _cache.GetCached(GroupInfoCacheKey(groupId), dataFunc, TimeSpan.FromDays(1));

return TinyMapper.Map<Group>(groupInfo);
}
Expand All @@ -62,15 +60,15 @@ public async Task<Group> GetGroup(int groupId)
$"groups/{groupId}/runners?type=group_type",
new Dictionary<string, string>());

var runners = await _redis.GetCached(GroupRunnerListCacheKey(groupId), dataFunc, TimeSpan.FromMinutes(1));
var runners = await _cache.GetCached(GroupRunnerListCacheKey(groupId), dataFunc, TimeSpan.FromMinutes(1));

return runners;
}

public async Task<Models.Runner> GetSingleRunner(int runnerId)
{
var dataFunc = () => _gitLabClient.Runners.GetAsync(runnerId);
var runner = await _redis.GetCached(RunnerCacheKey(runnerId), dataFunc, TimeSpan.FromMinutes(1));
var runner = await _cache.GetCached(RunnerCacheKey(runnerId), dataFunc, TimeSpan.FromMinutes(1));
return TinyMapper.Map<Models.Runner>(runner);
}

Expand All @@ -80,7 +78,7 @@ public async Task<IEnumerable<Job>> GetRunnerCurrentJobs(int runnerId)
$"runners/{runnerId}/jobs",
new Dictionary<string, string> {{"status", "running"}});

var jobs = await _redis.GetCached($"runner_{runnerId}_currentjob", dataFunc, TimeSpan.FromMinutes(1));
var jobs = await _cache.GetCached($"runner_{runnerId}_currentjob", dataFunc, TimeSpan.FromMinutes(1));

return jobs;
}
Expand All @@ -91,14 +89,14 @@ public async Task<IEnumerable<Job>> GetRunnerJobs(int runnerId)
$"runners/{runnerId}/jobs",
new Dictionary<string, string>());

var jobs = await _redis.GetCached($"runner_{runnerId}_alljob", dataFunc, TimeSpan.FromMinutes(1));
var jobs = await _cache.GetCached($"runner_{runnerId}_alljob", dataFunc, TimeSpan.FromMinutes(1));

return jobs;
}

public async Task InvalidateRunnerCache(int runnerId)
{
await _redis.Delete(RunnerCacheKey(runnerId));
await _cache.Delete(RunnerCacheKey(runnerId));
}

public async Task<bool> SetRunnerActiveStatus(int runnerId, bool isActive)
Expand Down
10 changes: 10 additions & 0 deletions src/GitLabKit.Runner.Core/Repositories/ICache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Threading.Tasks;

namespace GitLabKit.Runner.Core.Repositories;

public interface ICache
{
Task<T> GetCached<T>(string key, Func<Task<T>> dataFunc, TimeSpan ttl);
Task Delete(string key);
}
17 changes: 17 additions & 0 deletions src/GitLabKit.Runner.Core/Repositories/NoCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Threading.Tasks;

namespace GitLabKit.Runner.Core.Repositories;

public class NoCache : ICache
{
public async Task<T> GetCached<T>(string key, Func<Task<T>> dataFunc, TimeSpan ttl)
{
return await dataFunc.Invoke();
}

public Task Delete(string key)
{
return Task.CompletedTask;
}
}
8 changes: 1 addition & 7 deletions src/GitLabKit.Runner.Core/Repositories/RedisCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@

namespace GitLabKit.Runner.Core.Repositories;

public interface IRedisCache
{
Task<T> GetCached<T>(string key, Func<Task<T>> dataFunc, TimeSpan ttl);
Task Delete(string key);
}

public class RedisCache : IRedisCache
public class RedisCache : ICache
{
private readonly IConnectionMultiplexer _redis;

Expand Down
16 changes: 5 additions & 11 deletions src/GitLabKit.Runner.Web/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Serilog;
using StackExchange.Redis;
using Serilog;
using Swashbuckle.Extensions;

var builder = WebApplication.CreateBuilder(args);
Expand Down Expand Up @@ -45,20 +44,15 @@
var connectionsConfig = configuration.GetSection(nameof(Connections));
builder.Services.Configure<Connections>(connectionsConfig);
builder.Services.Configure<ApplicationInsights>(configuration.GetSection(nameof(ApplicationInsights)));
builder.Services.Configure<Secrets>(configuration.GetSection(nameof(Secrets)));

var secretsConfig = configuration.GetSection(nameof(Secrets));
builder.Services.Configure<Secrets>(secretsConfig);

builder.Services.AddHttpContextAccessor();

builder.Services.AddApplicationInsightsTelemetry().EnrichAppInsightsData();
builder.Services.AddSingleton<ITelemetryInitializer, ApplicationInsightsRoleNameInitializer>();
builder.Services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(connectionsConfig.GetSection("RedisServer").Value,
options =>
{
options.AbortOnConnectFail = false;
options.ConnectTimeout = 1000;
}));

builder.Services.AddSingleton<IRedisCache, RedisCache>();
builder.Services.AddCache(connectionsConfig, secretsConfig);
builder.Services.AddSingleton<IGitLabRepository, GitLabRepository>();
builder.Services.AddSingleton<IGitLabGroupService, GitLabGroupService>();
builder.Services.AddSingleton<IGitLabRunnerService, GitLabRunnerService>();
Expand Down
37 changes: 37 additions & 0 deletions src/GitLabKit.Runner.Web/Startup/CacheConfigurator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using GitLabKit.Runner.Core.Repositories;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;

namespace GitLabKit.Runner.Web.Startup;

public static class CacheConfigurator
{
public static void AddCache(this IServiceCollection service, IConfiguration connectionsConfig, IConfiguration secretsConfig)
{
var redisServerUrl = connectionsConfig.GetValue<string>("RedisServer");

if (!string.IsNullOrEmpty(redisServerUrl))
{
service.AddSingleton<IConnectionMultiplexer>(
ConnectionMultiplexer.Connect(redisServerUrl,
options =>
{
options.AbortOnConnectFail = false;
options.ConnectTimeout = 1000;

var user = secretsConfig.GetValue<string>("RedisUser");
var password = secretsConfig.GetValue<string>("RedisPassword");

if (!string.IsNullOrEmpty(user)) options.User = user;
if (!string.IsNullOrEmpty(password)) options.Password = password;
}));

service.AddSingleton<ICache, RedisCache>();
}
else
{
service.AddSingleton<ICache, NoCache>();
}
}
}
2 changes: 1 addition & 1 deletion src/GitLabKit.Runner.Web/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
},
"Connections": {
"GitLabServer": "",
"RedisServer": "localhost:16379"
"RedisServer": ""
},
"ApplicationInsights": {
"ConnectionString": "InstrumentationKey=163976b1-0110-4102-bb20-28088f8c8fa3;IngestionEndpoint=http://localhost:9999/;"
Expand Down
4 changes: 3 additions & 1 deletion src/GitLabKit.Runner.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"Seq": ""
},
"Secrets": {
"GitLabToken": ""
"GitLabToken": "",
"RedisUser": "",
"RedisPassword": ""
},
"Connections": {
"GitLabServer": "",
Expand Down

0 comments on commit 695545b

Please sign in to comment.