-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
68a63c5
commit a183e26
Showing
24 changed files
with
931 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
require_relative "google/api" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
require "google/cloud/container" | ||
|
||
module Google | ||
def cluster_manager | ||
@cluster_manager ||= Google::Cloud::Container.new | ||
end | ||
|
||
def google_cluster | ||
@google_cluster ||= begin | ||
cluster_manager.get_cluster("walrus-network", "us-central1-a", "walrus-production") | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
require_relative "../kubernetes" | ||
|
||
module Google | ||
module Container | ||
module V1 | ||
class NodePool | ||
# Get the kubernetes nodes that make up this cluster | ||
def kube_nodes(all) | ||
all.select {|node| node.labels[:'cloud.google.com/gke-nodepool'] == id} | ||
end | ||
|
||
# Get the pods running on this cluster | ||
def pods(all) | ||
res = [] | ||
kube_nodes(all).each do |node| | ||
res << node.pods | ||
end | ||
res.flatten | ||
end | ||
|
||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
require "lru_redux" | ||
require "active_support/time" | ||
|
||
# Represents an object that has an unique ID and a cachable document. | ||
module Document | ||
|
||
# Get the ID of this document. | ||
# Must be set by the implementer using @id = "value". | ||
def id | ||
@id | ||
end | ||
|
||
# Gets a new version of the document and updates the cache. | ||
def document | ||
cache_internal[:document] = fetch! | ||
end | ||
|
||
# Get a cached version of the document or call #{fetch!} | ||
# if the cache has expired beyond the #{cache_duration}. | ||
def cache | ||
cache_internal.getset(:document){fetch!} | ||
end | ||
|
||
# Fetch the newest version of the document. | ||
# This does not update the cache, use #{document} instead. | ||
def fetch! | ||
raise NotImplementedError, "Unable to fetch document" | ||
end | ||
|
||
# Clear the document cache and fetch the newest document. | ||
def refresh! | ||
cache_internal.clear | ||
cache | ||
end | ||
|
||
protected | ||
|
||
# Duration that document caches should be stored before expiring. | ||
def cache_duration | ||
5.minutes | ||
end | ||
|
||
# Cache provider that allows thread-safe ttl operations. | ||
def cache_internal | ||
@cache ||= LruRedux::TTL::ThreadSafeCache.new(1, cache_duration.to_i) | ||
end | ||
|
||
# Any missing methods are assumed to be directed at the document. | ||
# If the method ends with "_cache", then the method is forwarded | ||
# to the cache, if not it forwards to a newly requested document. | ||
def method_missing(m, *args, &block) | ||
if m.to_s.end_with?("_cache") | ||
m = m.to_s.gsub("_cache", "") | ||
else | ||
refresh! | ||
end | ||
cache.send(m, *args, &block) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
class GraphQuery | ||
def initialize(name) | ||
@path = "resources/queries/#{name}.json" | ||
raise "Query \"#{@path}\" not found!" unless File.file?(@path) | ||
end | ||
|
||
def create(env) | ||
raw = File.read(@path) | ||
# Replace placeholders | ||
raw.gsub!(/\$\{([ a-zA-Z0-9_-]{1,})\b\}|\$([a-zA-Z0-9_-]{1,})\b/) do |var| | ||
clean = var.gsub(/[\{\}\$]/, "") | ||
match = env[:"#{clean}"] | ||
raise "Unable to find #{clean} in environment!" if match.nil? | ||
match | ||
end | ||
raw | ||
.gsub(/(^.*.#.+)/, '') # Remove comments not at first index | ||
.gsub(/(^#.+)/, '') # Remove comments at first index | ||
.gsub("\n", "") # Remove newlines | ||
.gsub(/\s+/, "") # Remove all spaces | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
class String | ||
def to_bool | ||
return true if self =~ (/^(true|t|yes|y|1)$/i) | ||
return false if self.empty? || self =~ (/^(false|f|no|n|0)$/i) | ||
|
||
raise ArgumentError.new "invalid value: #{self}" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
require_relative "walrus/api" | ||
require_relative "walrus/server_templates" | ||
require_relative "walrus/servers" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
require 'net/http' | ||
require 'uri' | ||
require 'json' | ||
|
||
module Walrus | ||
def request(data) | ||
uri = URI.parse($config.get("api", "url")) | ||
|
||
params = {query: data} | ||
params = Hash[URI.decode_www_form(uri.query || '')].merge(params) | ||
uri.query = URI.encode_www_form(params) | ||
|
||
header = {'Content-Type': 'text/json'} | ||
http = Net::HTTP.new(uri.host, uri.port) | ||
request = Net::HTTP::Post.new(uri.request_uri, header) | ||
|
||
# Send the request | ||
response = http.request(request) | ||
res = JSON.parse(response.body, symbolize_names: true) | ||
puts res | ||
unless res[:errors].nil? | ||
errors = res[:errors] | ||
message = "#{errors.size} error(s) while executing query: " | ||
errors.each do |error| | ||
message += "\"#{error[:message]}\", " | ||
end | ||
message = message.delete_suffix(", ") | ||
raise message | ||
end | ||
return res[:data] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
require_relative "api" | ||
require_relative "../graph_query" | ||
require 'json' | ||
|
||
module Walrus | ||
module ServerTemplates | ||
include ::Walrus | ||
|
||
TEMPLATES_QUERY = GraphQuery.new("templates/all").create({}) | ||
TEMPLATE_ID_QUERY = GraphQuery.new("templates/by_id") | ||
|
||
def template_idents | ||
request(TEMPLATES_QUERY)[:serverTemplates].map { |t| t[:identifier] } | ||
end | ||
|
||
def all_templates | ||
request(TEMPLATES_QUERY)[:serverTemplates] | ||
end | ||
|
||
def template_by_id(id) | ||
request(TEMPLATE_ID_QUERY.create({id: id}))[:serverTemplates] | ||
end | ||
|
||
def get_template(identifier) | ||
all_templates.each do |temp| | ||
if temp[:identifier].downcase == identifier.downcase | ||
return fix_template(temp) | ||
end | ||
end | ||
nil | ||
end | ||
|
||
private | ||
|
||
def fix_template(temp) | ||
temp[:plugins].map! { |pl| JSON.parse(pl.gsub('=>', ':'), symbolize_names: true) } if temp[:plugins] | ||
temp[:components].map! { |comp| JSON.parse(comp.gsub('=>', ':'), symbolize_names: true) } if temp[:components] | ||
temp[:remote_files].map! { |file| JSON.parse(file.gsub('=>', ':'), symbolize_names: true) } if temp[:remote_files] | ||
return temp | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require_relative "api" | ||
require_relative "../graph_query" | ||
require 'json' | ||
|
||
module Walrus | ||
module Servers | ||
include ::Walrus | ||
include ServerTemplates | ||
|
||
TEMPLATE_QUERY = GraphQuery.new("servers/template") | ||
ADD_MUTATION = GraphQuery.new("servers/add") | ||
CREATE_MUTATION = GraphQuery.new("servers/create") | ||
|
||
def template(server_id) | ||
template_by_id(request(TEMPLATE_QUERY.create({id: server_id}))[:findServer][:template_id]) | ||
end | ||
|
||
def add_server(server_id, pod_name) | ||
request(ADD_MUTATION.create({id: server_id, pod_name: pod_name})) | ||
end | ||
|
||
def create_server(template_id) | ||
request(CREATE_MUTATION.create({template_id: template_id}))[:serverCreate][:serverId] | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
require_relative "../lib/worker" | ||
|
||
class BoostNotifer < Worker | ||
|
||
def initialize(discord) | ||
super("BoostNotifer", 5.minutes) | ||
@guild = discord.guild(:main_guild)[:object] | ||
@where = discord.guild(:staff_guild)[:object].channels.detect { |chan| chan.id == $config.get("discord", "boost_channel").to_i } | ||
@boosters = [] | ||
end | ||
|
||
def execute(itteration) | ||
role = @guild.roles.detect{|r| r.name == "Nitro Booster"} | ||
return if role.nil? | ||
actual = [] | ||
@guild.members.each do |m| | ||
actual << {name: m.display_name, id: m.id} if m.role?(role) | ||
end | ||
no_longer = @boosters.select{|entry| !actual.include?(entry)} | ||
new = actual - @boosters | ||
@boosters = @boosters - no_longer + new | ||
new.each do |e| | ||
@where.send_embed do |embed| | ||
embed.title = "New Boost" | ||
embed.description = e[:name] | ||
embed.color = '22d100' | ||
end | ||
end | ||
no_longer.each do |e| | ||
@where.send_embed do |embed| | ||
embed.title = "Boost Revoked" | ||
embed.description = e[:name] | ||
embed.color = 'b50900' | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
require_relative "../lib/worker" | ||
require_relative "../lib/kubernetes" | ||
require_relative "../lib/cloudflare" | ||
|
||
class DnsUpdater < Worker | ||
include Kubernetes | ||
include Cloudflare | ||
|
||
@sizes = [] | ||
|
||
def initialize() | ||
super("DNSUpater", 1.minute) | ||
@mapping = [ | ||
{ | ||
domain: "uhc", | ||
matchers: %w(uhc) | ||
}, | ||
{ | ||
domain: "pre", | ||
matchers: %w(dev) | ||
}, | ||
{ | ||
domain: "dev", | ||
matchers: %w(mapdev) | ||
} | ||
] | ||
end | ||
|
||
def domain_for(pool) | ||
@mapping.select {|map| map[:matchers].include?(pool)}.map {|map| map[:domain]}[0] | ||
end | ||
|
||
def is_mapped?(domain) | ||
@mapping.any? {|map| map[:domain].to_s.downcase == domain.to_s.downcase} | ||
end | ||
|
||
def execute(itteration) | ||
expected = {} | ||
actual = {} | ||
nodes.each do |node| | ||
begin | ||
external = node.status.addresses.detect {|add| add.type == "ExternalIP"}.address | ||
pool = node.labels[:'doks.digitalocean.com/node-pool'] | ||
domain = domain_for(pool) | ||
if domain.present? | ||
expected[domain] = [] unless expected[domain].present? | ||
expected[domain] << external | ||
end | ||
rescue Exception => e | ||
log("Failed to get DNS information for #{node.name}! #{e}", :critical) | ||
puts e.backtrace | ||
end | ||
end | ||
|
||
perform_on_zone do |zone| | ||
begin | ||
zone.dns_records.each do |r| | ||
prefix = r.name.split(".")[0] | ||
if is_mapped?(prefix) | ||
actual[prefix] = [] unless actual[prefix].present? | ||
actual[prefix] << r.content | ||
end | ||
end | ||
|
||
to_add = {} | ||
to_remove = {} | ||
expected.each do |domain, ips| | ||
if actual[domain].nil? || actual[domain].empty? | ||
to_add[domain] = ips | ||
else | ||
to_add[domain] = expected[domain] - actual[domain] | ||
to_remove[domain] = actual[domain] - expected[domain] | ||
end | ||
end | ||
|
||
if expected.empty? | ||
to_remove = actual | ||
end | ||
|
||
to_add.each do |domain, ips| | ||
ips.each do |ip| | ||
zone.dns_records.create("A", domain, ip) | ||
log "Adding DNS entry for #{domain}.walrus.network => #{ip}" | ||
end | ||
end | ||
to_remove.each do |domain, ips| | ||
zone.dns_records.select {|r| r.name.split(".")[0] == domain && r.type == "A" && ips.include?(r.content)}.each do |r| | ||
r.delete | ||
log "Removing DNS entry for #{r.name} (#{r.content})" | ||
end | ||
end | ||
rescue Exception => e | ||
log("Failed to update DNS information! #{e}", :critical) | ||
puts e.backtrace | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.