Rewrite in Zig
This commit is contained in:
164
src/main.zig
Normal file
164
src/main.zig
Normal file
@@ -0,0 +1,164 @@
|
||||
const std = @import("std");
|
||||
const allocator = std.heap.page_allocator;
|
||||
var client: std.http.Client = .{ .allocator = allocator };
|
||||
const Command = enum { list, logs, create, delete, start };
|
||||
|
||||
const ForwardedUser = "X-Forwarded-User";
|
||||
|
||||
const PluginError = error{
|
||||
InvalidUser,
|
||||
InvalidCommand,
|
||||
NoContainerName,
|
||||
InvalidImage,
|
||||
};
|
||||
|
||||
const CodefirstAuth = struct {
|
||||
proxyScheme: []const u8,
|
||||
proxyHost: []const u8,
|
||||
user: []const u8,
|
||||
};
|
||||
|
||||
const CodefirstContainer = struct {
|
||||
Id: []const u8,
|
||||
Image: []const u8,
|
||||
Admins: []const u8,
|
||||
Env: [][]const u8,
|
||||
Private: bool,
|
||||
};
|
||||
|
||||
fn sendRequest(method: std.http.Method, auth: CodefirstAuth, path: []const u8, body: []const u8) !std.http.Status {
|
||||
const uri = std.Uri.parse(path) catch unreachable;
|
||||
var headers = std.http.Headers{ .allocator = allocator };
|
||||
defer headers.deinit();
|
||||
try headers.append(ForwardedUser, auth.user);
|
||||
if (body.len > 0) {
|
||||
try headers.append("Content-Type", "application/json");
|
||||
}
|
||||
var req = try client.request(method, uri, headers, .{});
|
||||
defer req.deinit();
|
||||
req.transfer_encoding = std.http.Client.RequestTransfer{ .content_length = body.len };
|
||||
try req.start();
|
||||
try req.writeAll(body);
|
||||
try req.finish();
|
||||
try req.wait();
|
||||
const responseBody = req.reader().readAllAlloc(allocator, 8192) catch unreachable;
|
||||
defer allocator.free(responseBody);
|
||||
std.log.info("{s}", .{responseBody});
|
||||
return req.response.status;
|
||||
}
|
||||
|
||||
fn exists(auth: CodefirstAuth, containerName: []const u8) !bool {
|
||||
const path = try std.fmt.allocPrint(allocator, "{s}://{s}/containers/{s}/json", .{ auth.proxyScheme, auth.proxyHost, containerName });
|
||||
defer allocator.free(path);
|
||||
var status = try sendRequest(.GET, auth, path, "");
|
||||
return status == .ok;
|
||||
}
|
||||
|
||||
fn createImage(auth: CodefirstAuth, imageName: []const u8) !void {
|
||||
const path = try std.fmt.allocPrint(allocator, "{s}://{s}/images/create?fromImage={s}", .{ auth.proxyScheme, auth.proxyHost, imageName });
|
||||
defer allocator.free(path);
|
||||
_ = try sendRequest(.POST, auth, path, "");
|
||||
}
|
||||
|
||||
fn create(auth: CodefirstAuth, container: CodefirstContainer, containerName: []const u8) !void {
|
||||
const path = try std.fmt.allocPrint(allocator, "{s}://{s}/containers/create/{s}", .{ auth.proxyScheme, auth.proxyHost, containerName });
|
||||
defer allocator.free(path);
|
||||
var json = std.ArrayList(u8).init(allocator);
|
||||
defer json.deinit();
|
||||
try std.json.stringify(container, .{}, json.writer());
|
||||
_ = try sendRequest(.POST, auth, path, json.items);
|
||||
}
|
||||
|
||||
fn start(auth: CodefirstAuth, imageName: []const u8, containerName: []const u8, env: [][]const u8, private: bool) !void {
|
||||
const ContainerStart = struct {
|
||||
Id: []const u8,
|
||||
Image: []const u8,
|
||||
Env: [][]const u8,
|
||||
Private: bool,
|
||||
};
|
||||
const command = ContainerStart{
|
||||
.Id = "",
|
||||
.Image = imageName,
|
||||
.Env = env,
|
||||
.Private = private,
|
||||
};
|
||||
const path = try std.fmt.allocPrint(allocator, "{s}://{s}/containers/{s}/start", .{ auth.proxyScheme, auth.proxyHost, containerName });
|
||||
defer allocator.free(path);
|
||||
var json = std.ArrayList(u8).init(allocator);
|
||||
defer json.deinit();
|
||||
try std.json.stringify(command, .{}, json.writer());
|
||||
_ = try sendRequest(.POST, auth, path, json.items);
|
||||
}
|
||||
|
||||
fn delete(auth: CodefirstAuth, containerName: []const u8) !void {
|
||||
const path = try std.fmt.allocPrint(allocator, "{s}://{s}/containers/{s}", .{ auth.proxyScheme, auth.proxyHost, containerName });
|
||||
defer allocator.free(path);
|
||||
_ = try sendRequest(.DELETE, auth, path, "");
|
||||
}
|
||||
|
||||
pub fn run() !void {
|
||||
const command_name = std.os.getenv("PLUGIN_COMMAND") orelse return PluginError.InvalidCommand;
|
||||
const command = std.meta.stringToEnum(Command, command_name) orelse return PluginError.InvalidCommand;
|
||||
const auth = CodefirstAuth{
|
||||
.proxyScheme = std.os.getenv("PROXYSCHEME") orelse "http",
|
||||
.proxyHost = std.os.getenv("PROXYHOST") orelse "dockerproxy:8080",
|
||||
.user = std.os.getenv("DRONE_REPO_OWNER") orelse return PluginError.InvalidUser,
|
||||
};
|
||||
const containerName = std.os.getenv("PLUGIN_CONTAINER") orelse return PluginError.NoContainerName;
|
||||
|
||||
var envs = std.ArrayList([]const u8).init(allocator);
|
||||
defer envs.deinit();
|
||||
for (std.os.environ) |env| {
|
||||
if (std.mem.startsWith(u8, std.mem.span(env), "CODEFIRST_CLIENTDRONE_ENV_")) {
|
||||
try envs.append(std.mem.span(env)["CODEFIRST_CLIENTDRONE_ENV_".len..]);
|
||||
}
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
.create => {
|
||||
const imageName = std.os.getenv("PLUGIN_IMAGE") orelse return PluginError.InvalidImage;
|
||||
const private = std.mem.eql(u8, std.os.getenv("PLUGIN_PRIVATE") orelse "false", "true");
|
||||
const overwrite = std.mem.eql(u8, std.os.getenv("PLUGIN_OVERWRITE") orelse "false", "true");
|
||||
const admins = std.os.getenv("PLUGIN_ADMINS") orelse auth.user;
|
||||
|
||||
const container = CodefirstContainer{
|
||||
.Id = "",
|
||||
.Image = imageName,
|
||||
.Admins = admins,
|
||||
.Env = envs.items,
|
||||
.Private = private,
|
||||
};
|
||||
|
||||
if (overwrite) {
|
||||
try delete(auth, containerName);
|
||||
}
|
||||
if (!try exists(auth, containerName)) {
|
||||
try createImage(auth, imageName);
|
||||
try create(auth, container, containerName);
|
||||
try start(auth, imageName, containerName, envs.items, private);
|
||||
}
|
||||
},
|
||||
.start => {
|
||||
const imageName = std.os.getenv("PLUGIN_IMAGE") orelse return PluginError.InvalidImage;
|
||||
const private = std.mem.eql(u8, std.os.getenv("PLUGIN_PRIVATE") orelse "false", "true");
|
||||
try start(auth, imageName, containerName, envs.items, private);
|
||||
},
|
||||
.delete => {
|
||||
try delete(auth, containerName);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
run() catch |err| {
|
||||
switch (err) {
|
||||
PluginError.InvalidCommand => std.log.err("Invalid command (possible values: list|logs|create|delete|start)", .{}),
|
||||
PluginError.InvalidUser => std.log.err("Invalid user", .{}),
|
||||
PluginError.NoContainerName => std.log.err("No container name", .{}),
|
||||
PluginError.InvalidImage => std.log.err("Invalid image", .{}),
|
||||
else => std.log.err("{}", .{err}),
|
||||
}
|
||||
std.os.exit(1);
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user