smart_proxy_omaha 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +14 -0
- data/LICENSE +675 -0
- data/README.md +99 -0
- data/Rakefile +14 -0
- data/bin/smart-proxy-omaha-sync +35 -0
- data/bundler.d/omaha.rb +1 -0
- data/extra/foreman-proxy-omaha-sync.cron +2 -0
- data/lib/smart_proxy_omaha.rb +3 -0
- data/lib/smart_proxy_omaha/configuration_loader.rb +17 -0
- data/lib/smart_proxy_omaha/dependency_injection.rb +8 -0
- data/lib/smart_proxy_omaha/foreman_client.rb +11 -0
- data/lib/smart_proxy_omaha/http_download.rb +65 -0
- data/lib/smart_proxy_omaha/http_request.rb +20 -0
- data/lib/smart_proxy_omaha/http_shared.rb +30 -0
- data/lib/smart_proxy_omaha/metadata.rb +34 -0
- data/lib/smart_proxy_omaha/metadata_provider.rb +23 -0
- data/lib/smart_proxy_omaha/omaha_api.rb +33 -0
- data/lib/smart_proxy_omaha/omaha_http_config.ru +9 -0
- data/lib/smart_proxy_omaha/omaha_plugin.rb +18 -0
- data/lib/smart_proxy_omaha/omaha_protocol.rb +65 -0
- data/lib/smart_proxy_omaha/omaha_protocol/eventacknowledgeresponse.rb +9 -0
- data/lib/smart_proxy_omaha/omaha_protocol/handler.rb +84 -0
- data/lib/smart_proxy_omaha/omaha_protocol/noupdateresponse.rb +9 -0
- data/lib/smart_proxy_omaha/omaha_protocol/request.rb +101 -0
- data/lib/smart_proxy_omaha/omaha_protocol/response.rb +33 -0
- data/lib/smart_proxy_omaha/omaha_protocol/updateresponse.rb +35 -0
- data/lib/smart_proxy_omaha/release.rb +121 -0
- data/lib/smart_proxy_omaha/release_provider.rb +37 -0
- data/lib/smart_proxy_omaha/release_repository.rb +11 -0
- data/lib/smart_proxy_omaha/syncer.rb +48 -0
- data/lib/smart_proxy_omaha/version.rb +5 -0
- data/settings.d/omaha.yml.example +5 -0
- data/smart_proxy_omaha.gemspec +23 -0
- data/test/fixtures/request_update_complete_error.xml +7 -0
- data/test/fixtures/request_update_complete_noupdate.xml +9 -0
- data/test/fixtures/request_update_complete_update.xml +9 -0
- data/test/fixtures/request_update_download_started.xml +7 -0
- data/test/fixtures/response_update_complete_error.xml +5 -0
- data/test/fixtures/response_update_complete_noupdate.xml +7 -0
- data/test/fixtures/response_update_complete_update.xml +19 -0
- data/test/fixtures/stable.html +97 -0
- data/test/omaha/http_download_test.rb +34 -0
- data/test/omaha/http_request_test.rb +12 -0
- data/test/omaha/metadata_provider_test.rb +33 -0
- data/test/omaha/omaha_api_test.rb +75 -0
- data/test/omaha/omaha_protocol/request_test.rb +77 -0
- data/test/omaha/release_provider_test.rb +59 -0
- data/test/omaha/release_test.rb +110 -0
- data/test/omaha/syncer_test.rb +41 -0
- data/test/test_helper.rb +18 -0
- metadata +167 -0
data/README.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# Smart Proxy - Omaha
|
2
|
+
|
3
|
+
This plug-in adds support for the Omaha Procotol to Foreman's Smart Proxy. It is used when updating CoreOS clusters.
|
4
|
+
The Smart Proxy Omaha plugin acts as a mirror for Omaha releases and sends reports to Foreman about the update activity of the managed hosts. It needs the [Foreman Omaha plugin](https://github.com/theforeman/foreman_omaha) installed to work properly.
|
5
|
+
|
6
|
+
## How it works
|
7
|
+
|
8
|
+
The operatingsystem packages install a cronjob, that runs the binary `smart-proxy-omaha-sync` nightly to sync omaha content from the upstream mirror servers.
|
9
|
+
Your CoreOS hosts can then be configured to update against the smart proxy. The proxy then uploads facts and reports to Foreman.
|
10
|
+
Omaha content is served directly from the proxy.
|
11
|
+
|
12
|
+
## Compatibility
|
13
|
+
|
14
|
+
| Foreman Proxy Version | Plugin Version |
|
15
|
+
| --------------------- | -------------- |
|
16
|
+
| >= 1.12 | any |
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
To be able to use Foreman for your Omaha updates, you need to install the [Foreman Omaha plugin](https://github.com/theforeman/foreman_omaha), install this smart-proxy plugin and configure your CoreOS hosts.
|
21
|
+
|
22
|
+
For the Smart Proxy plugin, follow the [smart-proxy plugin installation instructions](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Smart-Proxy_Plugin). You usually just need to install the `rubygem-smart_proxy_omaha` package and restart the `foreman-proxy` service.
|
23
|
+
|
24
|
+
For the initial sync of releases you need to run the binary `smart-proxy-omaha-sync` as `foreman-proxy` user.
|
25
|
+
|
26
|
+
Do not forget to register the smart proxy in Foreman via the user interface.
|
27
|
+
|
28
|
+
## Host Configuration
|
29
|
+
|
30
|
+
You need to configure your CoreOS hosts to connect to the Omaha smart-proxy for updates. You can either configure your servers manually or use cloud-config.
|
31
|
+
|
32
|
+
### Using Config File
|
33
|
+
|
34
|
+
Edit `/etc/coreos/update.conf`
|
35
|
+
|
36
|
+
```
|
37
|
+
GROUP=stable
|
38
|
+
SERVER=https://omahaproxy.example.com:8443/omaha/v1/update
|
39
|
+
```
|
40
|
+
|
41
|
+
Restart update engine
|
42
|
+
|
43
|
+
```bash
|
44
|
+
sudo systemctl restart update-engine
|
45
|
+
```
|
46
|
+
|
47
|
+
### Using Cloud-Config
|
48
|
+
|
49
|
+
```yaml
|
50
|
+
#cloud-config
|
51
|
+
coreos:
|
52
|
+
update:
|
53
|
+
group: "stable"
|
54
|
+
server: "https://omahaproxy.example.com:8443/omaha/v1/update"
|
55
|
+
```
|
56
|
+
|
57
|
+
### Release channels
|
58
|
+
|
59
|
+
All three default release channels (alpha, beta, stable) are supported. You cannot define custom channels right now.
|
60
|
+
|
61
|
+
### Testing
|
62
|
+
|
63
|
+
To test if a client can successfully check for updates, these commands may help:
|
64
|
+
|
65
|
+
```bash
|
66
|
+
$ update_engine_client -check_for_update
|
67
|
+
$ journalctl -u update-engine.service
|
68
|
+
```
|
69
|
+
|
70
|
+
## Proxy Support
|
71
|
+
|
72
|
+
In the settings file you can specify a http proxy that is used to download Omaha content.
|
73
|
+
You need to allow https access to these servers:
|
74
|
+
|
75
|
+
* alpha.release.core-os.net
|
76
|
+
* beta.release.core-os.net
|
77
|
+
* stable.release.core-os.net
|
78
|
+
* update.release.core-os.net
|
79
|
+
|
80
|
+
## Make it High Available
|
81
|
+
|
82
|
+
In order to make the Omaha Smart Proxy high available or add additional capacity, just scale out and put a loadbalancer in front of the proxies.
|
83
|
+
|
84
|
+
## Copyright
|
85
|
+
|
86
|
+
Copyright (c) 2016 The Foreman developers
|
87
|
+
|
88
|
+
This program is free software: you can redistribute it and/or modify
|
89
|
+
it under the terms of the GNU General Public License as published by
|
90
|
+
the Free Software Foundation, either version 3 of the License, or
|
91
|
+
(at your option) any later version.
|
92
|
+
|
93
|
+
This program is distributed in the hope that it will be useful,
|
94
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
95
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
96
|
+
GNU General Public License for more details.
|
97
|
+
|
98
|
+
You should have received a copy of the GNU General Public License
|
99
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
desc 'Default: run unit tests.'
|
5
|
+
task default: :test
|
6
|
+
|
7
|
+
desc 'Test the Foreman Proxy plugin.'
|
8
|
+
Rake::TestTask.new(:test) do |t|
|
9
|
+
t.libs << '.'
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.test_files = FileList['test/**/*_test.rb']
|
13
|
+
t.verbose = true
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift '/usr/share/foreman-proxy/lib'
|
4
|
+
$LOAD_PATH.unshift '/usr/share/foreman-proxy/modules'
|
5
|
+
|
6
|
+
require 'smart_proxy'
|
7
|
+
require 'smart_proxy_main'
|
8
|
+
require 'smart_proxy_omaha'
|
9
|
+
require 'smart_proxy_omaha/syncer'
|
10
|
+
|
11
|
+
module Proxy::LogBuffer
|
12
|
+
class Decorator
|
13
|
+
@@instance = Proxy::LogBuffer::Decorator.new(::Logger.new(STDOUT), 'STDOUT')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
include Proxy::Log
|
17
|
+
|
18
|
+
::Proxy::PluginInitializer.new(::Proxy::Plugins.instance).initialize_plugins
|
19
|
+
|
20
|
+
unless ::Proxy::Plugins.instance.plugin_enabled?(:omaha)
|
21
|
+
logger.info "Omaha plugin not enabled. Exiting."
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
|
25
|
+
if !Proxy::SETTINGS.foreman_url
|
26
|
+
logger.error "Foreman URL not configured"
|
27
|
+
exit false
|
28
|
+
end
|
29
|
+
|
30
|
+
begin
|
31
|
+
Proxy::Omaha::Syncer.new.run
|
32
|
+
rescue StandardError => e
|
33
|
+
logger.error "#{e}"
|
34
|
+
exit false
|
35
|
+
end
|
data/bundler.d/omaha.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
gem 'smart_proxy_omaha'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ::Proxy::Omaha
|
2
|
+
class ConfigurationLoader
|
3
|
+
def load_classes
|
4
|
+
require 'smart_proxy_omaha/dependency_injection'
|
5
|
+
require 'smart_proxy_omaha/foreman_client'
|
6
|
+
require 'smart_proxy_omaha/omaha_api'
|
7
|
+
end
|
8
|
+
|
9
|
+
def load_dependency_injection_wirings(container_instance, settings)
|
10
|
+
container_instance.singleton_dependency :foreman_client_impl, Proxy::Omaha::ForemanClient
|
11
|
+
container_instance.singleton_dependency :release_repository_impl, Proxy::Omaha::ReleaseRepository
|
12
|
+
container_instance.singleton_dependency :metadata_provider_impl, (lambda do
|
13
|
+
Proxy::Omaha::MetadataProvider.new(:contentpath => settings[:contentpath])
|
14
|
+
end)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Proxy::Omaha
|
2
|
+
class ForemanClient < Proxy::HttpRequest::ForemanRequest
|
3
|
+
def post_facts(factsdata)
|
4
|
+
send_request(request_factory.create_post('api/hosts/facts', factsdata))
|
5
|
+
end
|
6
|
+
|
7
|
+
def post_report(report)
|
8
|
+
send_request(request_factory.create_post('api/omaha_reports', report))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'smart_proxy_omaha/http_shared'
|
3
|
+
|
4
|
+
module Proxy::Omaha
|
5
|
+
class HttpDownload
|
6
|
+
include Proxy::Log
|
7
|
+
include HttpShared
|
8
|
+
|
9
|
+
attr_accessor :dst, :src, :result
|
10
|
+
|
11
|
+
def initialize(src, dst)
|
12
|
+
@src = src
|
13
|
+
@dst = dst
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
@task = Thread.new do
|
18
|
+
@result = run
|
19
|
+
end
|
20
|
+
@task.abort_on_exception = true
|
21
|
+
@task
|
22
|
+
end
|
23
|
+
|
24
|
+
def run
|
25
|
+
with_filelock do
|
26
|
+
logger.info "Downloading #{src} to #{dst}."
|
27
|
+
res = download
|
28
|
+
logger.info "Finished downloading #{dst}."
|
29
|
+
res
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def join
|
34
|
+
@task.join
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def download
|
40
|
+
http, request = connection_factory(src)
|
41
|
+
|
42
|
+
http.request(request) do |response|
|
43
|
+
open(dst, 'w') do |io|
|
44
|
+
response.read_body do |chunk|
|
45
|
+
io.write chunk
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def with_filelock
|
53
|
+
lock = Proxy::FileLock.try_locking(dst)
|
54
|
+
if lock.nil?
|
55
|
+
false
|
56
|
+
else
|
57
|
+
begin
|
58
|
+
yield
|
59
|
+
ensure
|
60
|
+
Proxy::FileLock.unlock(lock)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'smart_proxy_omaha/http_shared'
|
2
|
+
|
3
|
+
module Proxy::Omaha
|
4
|
+
class HttpRequest
|
5
|
+
include Proxy::Log
|
6
|
+
include HttpShared
|
7
|
+
|
8
|
+
def get(url)
|
9
|
+
http, request = connection_factory(url)
|
10
|
+
|
11
|
+
Timeout::timeout(10) do
|
12
|
+
response = http.request(request)
|
13
|
+
|
14
|
+
raise "Error retrieving from #{url}: #{response.class}" unless ["200", "201"].include?(response.code)
|
15
|
+
|
16
|
+
response.body
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Proxy::Omaha
|
6
|
+
module HttpShared
|
7
|
+
def connection_factory(url)
|
8
|
+
uri = URI.parse(url)
|
9
|
+
|
10
|
+
if Proxy::Omaha::Plugin.settings.proxy.to_s.empty?
|
11
|
+
proxy_host = nil
|
12
|
+
proxy_port = nil
|
13
|
+
else
|
14
|
+
proxy = URI.parse(Proxy::Omaha::Plugin.settings.proxy)
|
15
|
+
proxy_host = proxy.host
|
16
|
+
proxy_port = proxy.port
|
17
|
+
end
|
18
|
+
|
19
|
+
http = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port)
|
20
|
+
|
21
|
+
if uri.scheme == 'https'
|
22
|
+
http.use_ssl = true
|
23
|
+
end
|
24
|
+
|
25
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
26
|
+
|
27
|
+
[http, request]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Proxy::Omaha
|
2
|
+
class Metadata
|
3
|
+
attr_accessor :release, :sha1_b64, :sha256_b64, :size, :track
|
4
|
+
|
5
|
+
def initialize(params)
|
6
|
+
symbolize_keys_deep!(params)
|
7
|
+
@release = params.fetch(:release)
|
8
|
+
@sha1_b64 = params.fetch(:sha1_b64)
|
9
|
+
@sha256_b64 = params.fetch(:sha256_b64)
|
10
|
+
@size = params.fetch(:size)
|
11
|
+
@track = params.fetch(:track)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_json
|
15
|
+
{
|
16
|
+
:release => release,
|
17
|
+
:sha1_b64 => sha1_b64,
|
18
|
+
:sha256_b64 => sha256_b64,
|
19
|
+
:size => size,
|
20
|
+
:track => track,
|
21
|
+
}.to_json
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def symbolize_keys_deep!(h)
|
27
|
+
h.keys.each do |k|
|
28
|
+
ks = k.to_sym
|
29
|
+
h[ks] = h.delete k
|
30
|
+
symbolize_keys_deep! h[ks] if h[ks].is_a? Hash
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Proxy::Omaha
|
2
|
+
class MetadataProvider
|
3
|
+
attr_accessor :contentpath
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@contentpath = options.fetch(:contentpath)
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(track, release)
|
10
|
+
Metadata.new(JSON.parse(File.read(metadata_file(track, release))))
|
11
|
+
end
|
12
|
+
|
13
|
+
def store(metadata)
|
14
|
+
File.write(metadata_file(metadata.track, metadata.release), metadata.to_json)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def metadata_file(track, release)
|
20
|
+
File.join(contentpath, track, release.to_s, 'metadata.json')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'smart_proxy_omaha/omaha_protocol'
|
3
|
+
|
4
|
+
module Proxy::Omaha
|
5
|
+
|
6
|
+
class Api < ::Sinatra::Base
|
7
|
+
extend Proxy::Omaha::DependencyInjection
|
8
|
+
|
9
|
+
helpers ::Proxy::Helpers
|
10
|
+
|
11
|
+
inject_attr :foreman_client_impl, :foreman_client
|
12
|
+
inject_attr :release_repository_impl, :release_repository
|
13
|
+
inject_attr :metadata_provider_impl, :metadata_provider
|
14
|
+
|
15
|
+
post '/v1/update' do
|
16
|
+
request.body.rewind
|
17
|
+
request_body = request.body.read
|
18
|
+
omaha_request = Proxy::Omaha::OmahaProtocol::Request.new(
|
19
|
+
request_body,
|
20
|
+
:ip => request.ip,
|
21
|
+
:base_url => request.base_url
|
22
|
+
)
|
23
|
+
omaha_handler = Proxy::Omaha::OmahaProtocol::Handler.new(
|
24
|
+
:request => omaha_request,
|
25
|
+
:foreman_client => foreman_client,
|
26
|
+
:repository => release_repository,
|
27
|
+
:metadata_provider => metadata_provider
|
28
|
+
)
|
29
|
+
response = omaha_handler.handle
|
30
|
+
response.to_xml
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Proxy::Omaha
|
2
|
+
class NotFound < RuntimeError; end
|
3
|
+
|
4
|
+
class Plugin < ::Proxy::Plugin
|
5
|
+
plugin 'omaha', Proxy::Omaha::VERSION
|
6
|
+
|
7
|
+
http_rackup_path File.expand_path('omaha_http_config.ru', File.expand_path('../', __FILE__))
|
8
|
+
https_rackup_path File.expand_path('omaha_http_config.ru', File.expand_path('../', __FILE__))
|
9
|
+
|
10
|
+
load_classes ::Proxy::Omaha::ConfigurationLoader
|
11
|
+
load_dependency_injection_wirings ::Proxy::Omaha::ConfigurationLoader
|
12
|
+
|
13
|
+
default_settings :sync_releases => 0,
|
14
|
+
:contentpath => '/var/lib/foreman-proxy/omaha/content'
|
15
|
+
|
16
|
+
validate_readable :contentpath
|
17
|
+
end
|
18
|
+
end
|