consul_kv_backup 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 13b187d68d4ff6d1592949f06a38ff5cbb996005799ffb522759f66a4539d26e
4
+ data.tar.gz: aa9d14e725256b181d6d70c59718c4dda0c578f3e15faf1b17322ae395b7a89d
5
+ SHA512:
6
+ metadata.gz: 239168aeaf537e277db14aa982bc4caf18fb07b95014c0001fd0fdec6ba725fc4951f3a48e1945fea3bffc9cba4e176f10160dafa50b2b9a208a1153aed3411c
7
+ data.tar.gz: 64d05b93d3d0fc99eb52f0c87f0d6b2c11179fe900f40bf4a995bf2b1d1c0e5fd1c479c32787d7376e91ae521ca8ef0aca5479ca7df1a5f410662eb2d7bb990d
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .vscode
data/Dockerfile ADDED
@@ -0,0 +1,13 @@
1
+ FROM consul:1.4.0
2
+
3
+ ARG gem_file
4
+
5
+ RUN apk add --no-cache jq build-base libc-dev linux-headers postgresql-dev libxml2-dev libxslt-dev ruby ruby-dev ruby-rdoc ruby-irb git openssh-client
6
+
7
+ COPY ./docker-entrypoint.sh /
8
+ COPY pkg/$gem_file /consul_kv_backup/
9
+
10
+ RUN cd /consul_kv_backup ; \
11
+ gem install $gem_file
12
+
13
+ ENTRYPOINT ["/docker-entrypoint.sh"]
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ repo_name = '/fortman/consul_kv_backup'
4
+
5
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in consul_kv_backup.gemspec
8
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Ryan Fortman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # consul_kv_backup
2
+ Backup changes in consul kv storge to a git repository. Relies on the https://github.com/fortman/consul_watcher project.
data/Rakefile ADDED
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'open3'
5
+ require 'flazm_ruby_helpers/os'
6
+ require 'flazm_ruby_helpers/http'
7
+ require 'flazm_ruby_helpers/project'
8
+
9
+ spec_file = Gem::Specification.load('consul_kv_backup.gemspec')
10
+
11
+ task default: :docker_build
12
+
13
+ task :docker_tag, [:version, :docker_image_id] do |_task, args|
14
+ puts "Docker id #{args['docker_image_id']} => tag rfortman/consul_kv_backup:#{args['version']}"
15
+ tag_cmd = "docker tag #{args['docker_image_id']} rfortman/consul_kv_backup:#{args['version']}"
16
+ Open3.popen3(tag_cmd) do |_stdin, _stdout, stderr, wait_thr|
17
+ error = stderr.read
18
+ puts error unless wait_thr.value.success?
19
+ end
20
+ end
21
+
22
+ task docker_build: [:build] do
23
+ docker_image_id = nil
24
+ build_cmd = "docker build --build-arg gem_file=consul_kv_backup-#{spec_file.version}.gem ."
25
+ threads = []
26
+ Open3.popen3(build_cmd) do |_stdin, stdout, stderr, wait_thr|
27
+ { out: stdout, err: stderr }.each do |key, stream|
28
+ threads << Thread.new do
29
+ until (raw_line = stream.gets).nil?
30
+ match = raw_line.match(/Successfully built (.*)$/i)
31
+ docker_image_id = match.captures[0] if match
32
+ puts raw_line.to_s
33
+ end
34
+ end
35
+ end
36
+ threads.each(&:join)
37
+ if wait_thr.value.success?
38
+ Rake::Task['docker_tag'].invoke(spec_file.version, docker_image_id)
39
+ Rake::Task['docker_tag'].reenable
40
+ Rake::Task['docker_tag'].invoke('latest', docker_image_id)
41
+ end
42
+ end
43
+ end
44
+
45
+ task :start_deps do
46
+ cmd = 'docker-compose --file test/docker-compose.yml up -d consul rabbitmq'
47
+ FlazmRubyHelpers::Os.exec(cmd)
48
+ urls = [
49
+ 'http://localhost:8500/v1/status/leader',
50
+ 'http://localhost:15672'
51
+ ]
52
+ FlazmRubyHelpers::Http.wait_for_urls(urls)
53
+ cmd = 'docker-compose --file test/docker-compose.yml up -d consul-kv-watcher'
54
+ FlazmRubyHelpers::Os.exec(cmd)
55
+ end
56
+
57
+ task up: [:start_deps] do
58
+ cmd = 'docker-compose --file test/docker-compose.yml up consul-kv-backup'
59
+ _output, _status = FlazmRubyHelpers::Os.exec(cmd)
60
+ end
61
+
62
+ task :down do
63
+ cmd = 'docker-compose --file test/docker-compose.yml down'
64
+ _output, _status = FlazmRubyHelpers::Os.exec(cmd)
65
+ end
66
+
67
+ task publish: [:build, :docker_build] do
68
+ #FlazmRubyHelpers::Project::Git.publish(spec_file.version.to_s, 'origin', 'master')
69
+ FlazmRubyHelpers::Project::Docker.publish(spec_file.metadata['docker_image_name'], spec_file.version.to_s)
70
+ FlazmRubyHelpers::Project::Docker.publish(spec_file.metadata['docker_image_name'], 'latest')
71
+ FlazmRubyHelpers::Project::Gem.publish(spec_file.name.to_s, spec_file.version.to_s)
72
+ end
73
+
74
+ task :unpublish do
75
+ _output, _success = FlazmRubyHelpers::Os.exec("git tag --delete #{spec_file.version.to_s}")
76
+ _output, _success = FlazmRubyHelpers::Os.exec("gem yank #{spec_file.name.to_s} -v #{spec_file.version.to_s}")
77
+ puts "Please delete the tag from dockerhub at https://cloud.docker.com/repository/registry-1.docker.io/#{spec_file.metadata['docker_image_name']}/tags"
78
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', '..')
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'consul_kv_backup'
8
+ spec.version = IO.read('VERSION').chomp
9
+ spec.authors = ['Ryan Fortman']
10
+ spec.email = ['r.fortman.dev@gmail.com']
11
+
12
+ spec.summary = 'Send consul watch events to an amqp.'
13
+ spec.homepage = 'https://github.com/fortman/consul_kv_backup'
14
+ spec.metadata = {
15
+ 'docker_image_name' => 'rfortman/consul_kv_backup'
16
+ }
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_development_dependency 'bundler', '~> 2.0'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ # spec.add_runtime_dependency 'bundler', '~> 2.0'
28
+ spec.add_runtime_dependency 'diplomat', '~> 2.2.4'
29
+ spec.add_dependency 'bunny', '~> 1.7.0'
30
+ spec.add_dependency 'slop', '~> 4.6'
31
+ spec.add_dependency 'flazm_ruby_helpers', '~> 0.0.3'
32
+ end
@@ -0,0 +1,10 @@
1
+ #!/bin/sh
2
+
3
+ echo
4
+ echo "CLI_ARGS: \"${@}\""
5
+ if [[ ${#} != 0 ]]; then
6
+ exec $@
7
+ else
8
+ mkdir -p /repo ; cd /repo ; /usr/bin/consul_kv_backup --config-file /etc/consul_kv_backup/config.json
9
+ echo
10
+ fi
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'slop'
6
+ require 'logger'
7
+ require 'json'
8
+ require 'consul_kv_backup'
9
+
10
+ logger = Logger.new(STDOUT)
11
+
12
+ opts = Slop.parse do |o|
13
+ o.string '--config-file', required: true
14
+ o.on '-h', '--help', 'print help' do
15
+ logger.warn("\n#{o}")
16
+ exit(false)
17
+ end
18
+ end
19
+
20
+ config = JSON.parse(File.read(opts['config-file']))
21
+
22
+ ConsulKvBackup.start(config)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'consul_kv_backup/consul'
4
+ require 'consul_kv_backup/amqp'
5
+ require 'consul_kv_backup/git'
6
+
7
+ module ConsulKvBackup
8
+ def self.start(config)
9
+ assemble(config)
10
+ @amqp.consul = @consul
11
+ @amqp.git = @git
12
+ @amqp.consume
13
+ end
14
+
15
+ def self.assemble(config)
16
+ @consul = ConsulKvBackup::Consul.new(config['consul'])
17
+ @amqp = ConsulKvBackup::Amqp.new(config['amqp'])
18
+ @git = ConsulKvBackup::Git.new(config['git'])
19
+ end
20
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bunny'
4
+ require 'flazm_ruby_helpers/class'
5
+ require 'json'
6
+
7
+ module ConsulKvBackup
8
+ # Send diff output to jq command line
9
+ class Amqp
10
+ include FlazmRubyHelpers::Class
11
+
12
+ attr_accessor :consul, :git
13
+ def initialize(amqp_config)
14
+ initialize_variables(amqp_config)
15
+ setup_connection
16
+ end
17
+
18
+ def setup_connection
19
+ @conn = Bunny.new(amqp_opts)
20
+ @conn.start
21
+ @ch = @conn.create_channel
22
+ @ex = Bunny::Exchange.new(@ch,
23
+ :topic,
24
+ @amqp_exchange,
25
+ durable: true)
26
+ @queue = @ch.queue(@amqp_queue, durable: true).bind(@ex, routing_key: @amqp_routing_key)
27
+ end
28
+
29
+ def consume
30
+ @consumer ||= @queue.subscribe(block: true, &itself.method(:process_message))
31
+ nil
32
+ end
33
+
34
+ private
35
+
36
+ def process_message(delivery_info, properties, body)
37
+ data = JSON.parse(body)
38
+ data['value'] = @consul.consul_key(data['key_path']) if data['new_value']
39
+
40
+ @git.process_data(data)
41
+ end
42
+
43
+ def amqp_opts
44
+ opts = {}
45
+ opts[:vhost] = @amqp_vhost
46
+ opts[:username] = @amqp_username
47
+ opts[:password] = @amqp_password
48
+ if @amqp_addresses
49
+ opts[:addresses] = @amqp_addresses
50
+ elsif @amqp_hosts
51
+ opts[:hosts] = @amqp_hosts
52
+ opts[:port] = @amqp_port if @rabbitmq_port
53
+ elsif @amqp_host
54
+ opts[:host] = @amqp_host
55
+ opts[:port] = @amqp_port if @rabbitmq_port
56
+ end
57
+ opts
58
+ end
59
+
60
+ def defaults
61
+ logger = Logger.new(STDOUT)
62
+ logger.level = Logger::DEBUG
63
+ {
64
+ logger: logger,
65
+ amqp_host: 'localhost',
66
+ amqp_hosts: nil,
67
+ amqp_addresses: nil,
68
+ amqp_port: nil,
69
+ amqp_vhost: '/',
70
+ amqp_username: 'guest',
71
+ amqp_password: 'guest',
72
+ amqp_queue: nil,
73
+ amqp_exchange: "amq.topic",
74
+ amqp_routing_key: 'consul_watcher.key.#'
75
+ }
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'flazm_ruby_helpers/class'
4
+ require 'diplomat'
5
+
6
+ module ConsulKvBackup
7
+ # Consul storage for previous watch data
8
+ class Consul
9
+ include FlazmRubyHelpers::Class
10
+
11
+ def initialize(consul_config)
12
+ initialize_variables(consul_config)
13
+ setup_connection
14
+ end
15
+
16
+ def consul_key(key_path)
17
+ Diplomat::Kv.get(key_path)
18
+ end
19
+
20
+ private
21
+
22
+ def setup_connection
23
+ Diplomat.configure do |config|
24
+ # Set up a custom Consul URL
25
+ config.url = @consul_http_addr
26
+ # Set extra Faraday configuration options and custom access token (ACL)
27
+ config.options = {headers: {"X-Consul-Token" => @consul_token}}
28
+ end
29
+ end
30
+
31
+ def defaults
32
+ logger = Logger.new(STDOUT)
33
+ logger.level = Logger::WARN
34
+ {
35
+ logger: logger,
36
+ consul_http_addr: 'http://localhost:8500',
37
+ consul_token: nil,
38
+ }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'flazm_ruby_helpers/class'
4
+ require 'flazm_ruby_helpers/os'
5
+ require 'fileutils'
6
+
7
+ module ConsulKvBackup
8
+ # Consul storage for previous watch data
9
+ class Git
10
+ include FlazmRubyHelpers::Class
11
+
12
+ def initialize(git_config)
13
+ initialize_variables(git_config)
14
+ git_setup
15
+ end
16
+
17
+ def process_data(data)
18
+ path = data['key_path']
19
+ value = data['value']
20
+ dc = data['consul_dc']
21
+
22
+ git_set_branch(dc)
23
+
24
+ if data['old_value'] and !data['new_value']
25
+ git_rm(path)
26
+ else
27
+ git_add(path, value)
28
+ end
29
+
30
+ # git_push if @git['push']
31
+ end
32
+
33
+ private
34
+
35
+ def git_setup
36
+ FileUtils.mkdir_p(@git_root_dir) unless File.directory?(@git_root_dir)
37
+ FlazmRubyHelpers::Os.exec("git config --global core.sshCommand '#{@git_config['core.sshCommand']}'")
38
+ unless File.directory?("#{@git_root_dir}/.git")
39
+ FlazmRubyHelpers::Os.exec("git clone #{@git_config['remote.origin.url']} .")
40
+ end
41
+ @git_config.each_pair do |key, value|
42
+ FlazmRubyHelpers::Os.exec("git config --local #{key} '#{value}'")
43
+ end
44
+ if FlazmRubyHelpers::Os.exec("git count-objects")[0][0].match(/0 objects, 0 kilobytes/)
45
+ FlazmRubyHelpers::Os.exec("git commit --allow-empty -m 'Initial commit'")
46
+ end
47
+ end
48
+
49
+ def git_set_branch(branch = 'master')
50
+ exist = git_branch_exists?(branch)
51
+ if exist
52
+ FlazmRubyHelpers::Os.exec("git reset --hard HEAD")
53
+ FlazmRubyHelpers::Os.exec("git checkout #{branch}")
54
+ else
55
+ FlazmRubyHelpers::Os.exec("git fetch")
56
+ FlazmRubyHelpers::Os.exec("git branch #{branch} master")
57
+ FlazmRubyHelpers::Os.exec("git checkout #{branch}")
58
+ end
59
+ end
60
+
61
+ def git_branch_exists?(branch)
62
+ FlazmRubyHelpers::Os.exec("git branch --list")[0].each do |line|
63
+ return true if line.match(/#{branch}/)
64
+ end
65
+ false
66
+ end
67
+
68
+ def git_add(path, value)
69
+ file = File.open(path, 'w')
70
+ file.write(value)
71
+ file.close
72
+ FlazmRubyHelpers::Os.exec('git add --all')
73
+ FlazmRubyHelpers::Os.exec('git commit -m "automated backup: updating"')
74
+ end
75
+
76
+ def git_rm(path)
77
+ FlazmRubyHelpers::Os.exec("git rm #{path}")
78
+ FlazmRubyHelpers::Os.exec('git commit -m "automated backup: deleting"')
79
+ end
80
+
81
+ def git_rebase
82
+ FlazmRubyHelpers::Os.exec('git fetch')
83
+ FlazmRubyHelpers::Os.exec('git reset origin/master')
84
+ end
85
+
86
+ def git_push
87
+ FlazmRubyHelpers::Os.exec('git push')
88
+ end
89
+
90
+ def defaults
91
+ {
92
+ git_root_dir: '/tmp/consul_backup',
93
+ git_config: {}
94
+ }
95
+ end
96
+ end
97
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: consul_kv_backup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Fortman
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-06-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: diplomat
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.2.4
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.2.4
55
+ - !ruby/object:Gem::Dependency
56
+ name: bunny
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.7.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.7.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: slop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.6'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: flazm_ruby_helpers
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.0.3
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.0.3
97
+ description:
98
+ email:
99
+ - r.fortman.dev@gmail.com
100
+ executables:
101
+ - consul_kv_backup
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - Dockerfile
107
+ - Gemfile
108
+ - LICENSE
109
+ - README.md
110
+ - Rakefile
111
+ - VERSION
112
+ - consul_kv_backup.gemspec
113
+ - docker-entrypoint.sh
114
+ - exe/consul_kv_backup
115
+ - lib/consul_kv_backup.rb
116
+ - lib/consul_kv_backup/amqp.rb
117
+ - lib/consul_kv_backup/consul.rb
118
+ - lib/consul_kv_backup/git.rb
119
+ homepage: https://github.com/fortman/consul_kv_backup
120
+ licenses: []
121
+ metadata:
122
+ docker_image_name: rfortman/consul_kv_backup
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.7.8
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Send consul watch events to an amqp.
143
+ test_files: []