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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +14 -0
  3. data/LICENSE +675 -0
  4. data/README.md +99 -0
  5. data/Rakefile +14 -0
  6. data/bin/smart-proxy-omaha-sync +35 -0
  7. data/bundler.d/omaha.rb +1 -0
  8. data/extra/foreman-proxy-omaha-sync.cron +2 -0
  9. data/lib/smart_proxy_omaha.rb +3 -0
  10. data/lib/smart_proxy_omaha/configuration_loader.rb +17 -0
  11. data/lib/smart_proxy_omaha/dependency_injection.rb +8 -0
  12. data/lib/smart_proxy_omaha/foreman_client.rb +11 -0
  13. data/lib/smart_proxy_omaha/http_download.rb +65 -0
  14. data/lib/smart_proxy_omaha/http_request.rb +20 -0
  15. data/lib/smart_proxy_omaha/http_shared.rb +30 -0
  16. data/lib/smart_proxy_omaha/metadata.rb +34 -0
  17. data/lib/smart_proxy_omaha/metadata_provider.rb +23 -0
  18. data/lib/smart_proxy_omaha/omaha_api.rb +33 -0
  19. data/lib/smart_proxy_omaha/omaha_http_config.ru +9 -0
  20. data/lib/smart_proxy_omaha/omaha_plugin.rb +18 -0
  21. data/lib/smart_proxy_omaha/omaha_protocol.rb +65 -0
  22. data/lib/smart_proxy_omaha/omaha_protocol/eventacknowledgeresponse.rb +9 -0
  23. data/lib/smart_proxy_omaha/omaha_protocol/handler.rb +84 -0
  24. data/lib/smart_proxy_omaha/omaha_protocol/noupdateresponse.rb +9 -0
  25. data/lib/smart_proxy_omaha/omaha_protocol/request.rb +101 -0
  26. data/lib/smart_proxy_omaha/omaha_protocol/response.rb +33 -0
  27. data/lib/smart_proxy_omaha/omaha_protocol/updateresponse.rb +35 -0
  28. data/lib/smart_proxy_omaha/release.rb +121 -0
  29. data/lib/smart_proxy_omaha/release_provider.rb +37 -0
  30. data/lib/smart_proxy_omaha/release_repository.rb +11 -0
  31. data/lib/smart_proxy_omaha/syncer.rb +48 -0
  32. data/lib/smart_proxy_omaha/version.rb +5 -0
  33. data/settings.d/omaha.yml.example +5 -0
  34. data/smart_proxy_omaha.gemspec +23 -0
  35. data/test/fixtures/request_update_complete_error.xml +7 -0
  36. data/test/fixtures/request_update_complete_noupdate.xml +9 -0
  37. data/test/fixtures/request_update_complete_update.xml +9 -0
  38. data/test/fixtures/request_update_download_started.xml +7 -0
  39. data/test/fixtures/response_update_complete_error.xml +5 -0
  40. data/test/fixtures/response_update_complete_noupdate.xml +7 -0
  41. data/test/fixtures/response_update_complete_update.xml +19 -0
  42. data/test/fixtures/stable.html +97 -0
  43. data/test/omaha/http_download_test.rb +34 -0
  44. data/test/omaha/http_request_test.rb +12 -0
  45. data/test/omaha/metadata_provider_test.rb +33 -0
  46. data/test/omaha/omaha_api_test.rb +75 -0
  47. data/test/omaha/omaha_protocol/request_test.rb +77 -0
  48. data/test/omaha/release_provider_test.rb +59 -0
  49. data/test/omaha/release_test.rb +110 -0
  50. data/test/omaha/syncer_test.rb +41 -0
  51. data/test/test_helper.rb +18 -0
  52. metadata +167 -0
@@ -0,0 +1,37 @@
1
+ require 'nokogiri'
2
+ require 'fileutils'
3
+ require 'smart_proxy_omaha/http_request'
4
+ require 'smart_proxy_omaha/release'
5
+
6
+ module Proxy::Omaha
7
+ class ReleaseProvider
8
+ include ::Proxy::Log
9
+ include HttpShared
10
+
11
+ attr_accessor :track
12
+
13
+ def initialize(options)
14
+ @track = options.fetch(:track)
15
+ end
16
+
17
+ def releases
18
+ @releases ||= fetch_releases
19
+ end
20
+
21
+ def fetch_releases
22
+ releases = http_request.get("https://#{track}.release.core-os.net/amd64-usr/")
23
+ xml = Nokogiri::HTML(releases)
24
+ parsed = (xml.xpath('//a/text()').map(&:to_s) - ['current']).map do |v|
25
+ Proxy::Omaha::Release.new(:version => v, :track => track)
26
+ end.sort
27
+ logger.debug "Fetched releases for #{track}: #{parsed.map(&:to_s).join(', ')}"
28
+ parsed
29
+ end
30
+
31
+ private
32
+
33
+ def http_request
34
+ @http_request ||= ::Proxy::Omaha::HttpRequest.new
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ module Proxy::Omaha
2
+ class ReleaseRepository
3
+ def releases(track)
4
+ Dir.glob(File.join(Proxy::Omaha::Plugin.settings.contentpath, track, '*')).select {|f| File.directory? f }.map { |f| Gem::Version.new(File.basename(f)) }
5
+ end
6
+
7
+ def latest_os(track)
8
+ releases(track).max
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ require 'smart_proxy_omaha/release'
2
+ require 'smart_proxy_omaha/release_provider'
3
+
4
+ module Proxy::Omaha
5
+ class Syncer
6
+ include ::Proxy::Log
7
+
8
+ def run
9
+ if sync_count == 0
10
+ logger.info "Syncing is disabled."
11
+ return
12
+ end
13
+
14
+ ['alpha', 'beta', 'stable'].each do |track|
15
+ logger.debug "Syncing track: #{track}..."
16
+ sync_track(track)
17
+ end
18
+ end
19
+
20
+ def sync_track(track)
21
+ release_provider(track).releases.last(sync_count).each do |release|
22
+ if release.exists?
23
+ if release.valid?
24
+ logger.info "#{track} release #{release} already exists and is valid."
25
+ next
26
+ else
27
+ logger.info "#{track} release #{release} is invalid. Purging."
28
+ release.purge
29
+ end
30
+ end
31
+ release.create
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def sync_count
38
+ Proxy::Omaha::Plugin.settings.sync_releases.to_i
39
+ end
40
+
41
+ def release_provider(track)
42
+ @release_provider ||= {}
43
+ @release_provider[track] ||= ReleaseProvider.new(
44
+ :track => track
45
+ )
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ module Proxy
2
+ module Omaha
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ ---
2
+ :enabled: true
3
+ :contentpath: '/var/lib/foreman-proxy/omaha/content'
4
+ :sync_releases: 2
5
+ #:proxy: 'http://127.0.0.1:3128'
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../lib/smart_proxy_omaha/version', __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'smart_proxy_omaha'
5
+ s.version = Proxy::Omaha::VERSION
6
+
7
+ s.summary = 'Omaha protocol support for smart-proxy'
8
+ s.description = 'This plug-in adds support for the Omaha Procotol to Foreman\'s Smart Proxy.'
9
+ s.authors = ['Timo Goebel']
10
+ s.email = 'mail@timogoebel.name'
11
+ s.extra_rdoc_files = ['README.md', 'LICENSE']
12
+ s.files = `git ls-files`.split("\n") - ['.gitignore']
13
+ s.executables = ['smart-proxy-omaha-sync']
14
+ s.homepage = 'http://github.com/theforeman/smart_proxy_omaha'
15
+ s.license = 'GPLv3'
16
+
17
+ s.add_dependency('nokogiri')
18
+ s.add_dependency('json')
19
+
20
+ s.add_development_dependency('rake')
21
+ s.add_development_dependency('mocha')
22
+ s.add_development_dependency('test-unit')
23
+ end
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <request protocol="3.0" version="CoreOSUpdateEngine-0.1.0.0" updaterversion="CoreOSUpdateEngine-0.1.0.0" installsource="ondemandupdate" ismachine="1">
3
+ <os version="Chateau" platform="CoreOS" sp="1068.9.0_x86_64"></os>
4
+ <app appid="{e96281a6-d1af-4bde-9a0a-97b76e56dc57}" version="1068.9.0" track="stable" bootid="{5c43ee37-70da-48b7-9328-636618c2807c}" oem="" oemversion="" alephversion="1010.5.0" machineid="8e9450f47a4c47adbfe48b946e201c84" lang="en-US" board="amd64-usr" hardware_class="" delta_okay="false" >
5
+ <event eventtype="3" eventresult="0" errorcode="268435465"></event>
6
+ </app>
7
+ </request>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <request protocol="3.0" version="CoreOSUpdateEngine-0.1.0.0" updaterversion="CoreOSUpdateEngine-0.1.0.0" installsource="ondemandupdate" ismachine="1">
3
+ <os version="Chateau" platform="CoreOS" sp="1122.2.0_x86_64"></os>
4
+ <app appid="{e96281a6-d1af-4bde-9a0a-97b76e56dc57}" version="1122.2.0" track="stable" bootid="{5c43ee37-70da-48b7-9328-636618c2807c}" oem="" oemversion="" alephversion="1010.5.0" machineid="8e9450f47a4c47adbfe48b946e201c84" lang="en-US" board="amd64-usr" hardware_class="" delta_okay="false" >
5
+ <ping active="1"></ping>
6
+ <updatecheck></updatecheck>
7
+ <event eventtype="3" eventresult="2" previousversion=""></event>
8
+ </app>
9
+ </request>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <request protocol="3.0" version="CoreOSUpdateEngine-0.1.0.0" updaterversion="CoreOSUpdateEngine-0.1.0.0" installsource="ondemandupdate" ismachine="1">
3
+ <os version="Chateau" platform="CoreOS" sp="1068.9.0_x86_64"></os>
4
+ <app appid="{e96281a6-d1af-4bde-9a0a-97b76e56dc57}" version="1068.9.0" track="stable" bootid="{5c43ee37-70da-48b7-9328-636618c2807c}" oem="" oemversion="" alephversion="1010.5.0" machineid="8e9450f47a4c47adbfe48b946e201c84" lang="en-US" board="amd64-usr" hardware_class="" delta_okay="false" >
5
+ <ping active="1"></ping>
6
+ <updatecheck></updatecheck>
7
+ <event eventtype="3" eventresult="2" previousversion=""></event>
8
+ </app>
9
+ </request>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <request protocol="3.0" version="CoreOSUpdateEngine-0.1.0.0" updaterversion="CoreOSUpdateEngine-0.1.0.0" installsource="ondemandupdate" ismachine="1">
3
+ <os version="Chateau" platform="CoreOS" sp="1068.9.0_x86_64"></os>
4
+ <app appid="{e96281a6-d1af-4bde-9a0a-97b76e56dc57}" version="1068.9.0" track="stable" bootid="{5c43ee37-70da-48b7-9328-636618c2807c}" oem="" oemversion="" alephversion="1010.5.0" machineid="8e9450f47a4c47adbfe48b946e201c84" lang="en-US" board="amd64-usr" hardware_class="" delta_okay="false" >
5
+ <event eventtype="13" eventresult="1"></event>
6
+ </app>
7
+ </request>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <response protocol="3.0" server="example.org">
3
+ <daystart elapsed_seconds="0"/>
4
+ <app app_id="e96281a6-d1af-4bde-9a0a-97b76e56dc57" status="ok"/>
5
+ </response>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <response protocol="3.0" server="example.org">
3
+ <daystart elapsed_seconds="0"/>
4
+ <app app_id="e96281a6-d1af-4bde-9a0a-97b76e56dc57" status="ok">
5
+ <updatecheck status="noupdate"/>
6
+ </app>
7
+ </response>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <response protocol="3.0" server="example.org">
3
+ <daystart elapsed_seconds="0"/>
4
+ <app app_id="e96281a6-d1af-4bde-9a0a-97b76e56dc57" status="ok">
5
+ <updatecheck status="ok">
6
+ <urls>
7
+ <url codebase="http://example.org/omahareleases/stable/1122.2.0/"/>
8
+ </urls>
9
+ <manifest version="1122.2.0">
10
+ <packages>
11
+ <package hash="+ZFmPWzv1OdfmKHaGSojbK5Xj3k=" name="update.gz" size="212555113" required="false"/>
12
+ </packages>
13
+ <actions>
14
+ <action event="postinstall" sha256="cSBzKN0c6vKinrH0SdqUZSHlQtCa90vmeKC7p/xk19M=" needsadmin="false" IsDelta="false" DisablePayloadBackoff="true" ChromeOSVersion=""/>
15
+ </actions>
16
+ </manifest>
17
+ </updatecheck>
18
+ </app>
19
+ </response>
@@ -0,0 +1,97 @@
1
+ <html>
2
+ <head>
3
+ <title>stable.release.core-os.net/amd64-usr/</title>
4
+ <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" />
5
+ </head>
6
+ <body>
7
+ <h1>stable.release.core-os.net/amd64-usr/</h1>
8
+
9
+ [dir] <a href="367.1.0/">367.1.0</a> <br/>
10
+
11
+ [dir] <a href="410.0.0/">410.0.0</a> <br/>
12
+
13
+ [dir] <a href="410.1.0/">410.1.0</a> <br/>
14
+
15
+ [dir] <a href="410.2.0/">410.2.0</a> <br/>
16
+
17
+ [dir] <a href="444.4.0/">444.4.0</a> <br/>
18
+
19
+ [dir] <a href="444.5.0/">444.5.0</a> <br/>
20
+
21
+ [dir] <a href="494.3.0/">494.3.0</a> <br/>
22
+
23
+ [dir] <a href="494.4.0/">494.4.0</a> <br/>
24
+
25
+ [dir] <a href="494.5.0/">494.5.0</a> <br/>
26
+
27
+ [dir] <a href="522.4.0/">522.4.0</a> <br/>
28
+
29
+ [dir] <a href="522.5.0/">522.5.0</a> <br/>
30
+
31
+ [dir] <a href="522.6.0/">522.6.0</a> <br/>
32
+
33
+ [dir] <a href="557.2.0/">557.2.0</a> <br/>
34
+
35
+ [dir] <a href="607.0.0/">607.0.0</a> <br/>
36
+
37
+ [dir] <a href="633.1.0/">633.1.0</a> <br/>
38
+
39
+ [dir] <a href="647.0.0/">647.0.0</a> <br/>
40
+
41
+ [dir] <a href="647.2.0/">647.2.0</a> <br/>
42
+
43
+ [dir] <a href="681.0.0/">681.0.0</a> <br/>
44
+
45
+ [dir] <a href="681.1.0/">681.1.0</a> <br/>
46
+
47
+ [dir] <a href="681.2.0/">681.2.0</a> <br/>
48
+
49
+ [dir] <a href="717.1.0/">717.1.0</a> <br/>
50
+
51
+ [dir] <a href="717.3.0/">717.3.0</a> <br/>
52
+
53
+ [dir] <a href="723.3.0/">723.3.0</a> <br/>
54
+
55
+ [dir] <a href="766.3.0/">766.3.0</a> <br/>
56
+
57
+ [dir] <a href="766.4.0/">766.4.0</a> <br/>
58
+
59
+ [dir] <a href="766.5.0/">766.5.0</a> <br/>
60
+
61
+ [dir] <a href="835.8.0/">835.8.0</a> <br/>
62
+
63
+ [dir] <a href="835.9.0/">835.9.0</a> <br/>
64
+
65
+ [dir] <a href="835.10.0/">835.10.0</a> <br/>
66
+
67
+ [dir] <a href="835.11.0/">835.11.0</a> <br/>
68
+
69
+ [dir] <a href="835.12.0/">835.12.0</a> <br/>
70
+
71
+ [dir] <a href="835.13.0/">835.13.0</a> <br/>
72
+
73
+ [dir] <a href="899.13.0/">899.13.0</a> <br/>
74
+
75
+ [dir] <a href="899.15.0/">899.15.0</a> <br/>
76
+
77
+ [dir] <a href="899.17.0/">899.17.0</a> <br/>
78
+
79
+ [dir] <a href="1010.5.0/">1010.5.0</a> <br/>
80
+
81
+ [dir] <a href="1010.6.0/">1010.6.0</a> <br/>
82
+
83
+ [dir] <a href="1068.6.0/">1068.6.0</a> <br/>
84
+
85
+ [dir] <a href="1068.8.0/">1068.8.0</a> <br/>
86
+
87
+ [dir] <a href="1068.9.0/">1068.9.0</a> <br/>
88
+
89
+ [dir] <a href="1068.10.0/">1068.10.0</a> <br/>
90
+
91
+ [dir] <a href="1122.2.0/">1122.2.0</a> <br/>
92
+
93
+ [dir] <a href="current/">current</a> <br/>
94
+
95
+
96
+ </body>
97
+ </html>
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+ require 'fileutils'
3
+ require 'tmpdir'
4
+ require 'smart_proxy_omaha/http_download'
5
+
6
+ class HttpDownloadTest < Test::Unit::TestCase
7
+
8
+ def setup
9
+ @source_url = 'http://example.com/omaha_downlod'
10
+ @destination_dir = Dir.mktmpdir
11
+ @destination_path = File.join(@destination_dir, 'test_file')
12
+ end
13
+
14
+ def teardown
15
+ FileUtils.rm_rf(@destination_dir)
16
+ end
17
+
18
+ def test_downloads_file
19
+ stub_request(:get, @source_url).to_return(:status => [200, 'OK'], :body => "body")
20
+
21
+ http_download = ::Proxy::Omaha::HttpDownload.new(@source_url, @destination_path)
22
+ task = http_download.start
23
+ task.join
24
+ assert_equal 'body', File.read(@destination_path)
25
+ assert_equal true, http_download.result
26
+ end
27
+
28
+ def test_should_skip_download_if_one_is_in_progress
29
+ locked = Proxy::FileLock.try_locking(@destination_path)
30
+ http_download = ::Proxy::Omaha::HttpDownload.new(@source_url, locked.path)
31
+ http_download.start.join
32
+ assert_equal false, http_download.result
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+ require 'smart_proxy_omaha/http_request'
3
+
4
+ class HttpDownloadTest < Test::Unit::TestCase
5
+ def test_get
6
+ request_url = 'http://www.example.com/file'
7
+ stub_request(:get, request_url).to_return(:status => [200, 'OK'], :body => "body")
8
+
9
+ result = ::Proxy::Omaha::HttpRequest.new.get(request_url)
10
+ assert_equal 'body', result
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+ require 'json'
3
+ require 'smart_proxy_omaha/metadata_provider'
4
+
5
+ class MetadataProviderTest < Test::Unit::TestCase
6
+ def setup
7
+ @provider = Proxy::Omaha::MetadataProvider.new(:contentpath => '/tmp')
8
+ end
9
+
10
+ def test_get
11
+ File.expects(:read).with('/tmp/stable/1068.9.0/metadata.json').returns(stub_metadata.to_json)
12
+ metadata = @provider.get('stable', '1068.9.0')
13
+ assert_kind_of Proxy::Omaha::Metadata, metadata
14
+ end
15
+
16
+ def test_store
17
+ File.expects(:write).with('/tmp/stable/1068.9.0/metadata.json', stub_metadata.to_json).returns(true)
18
+ metadata = Proxy::Omaha::Metadata.new(stub_metadata)
19
+ assert @provider.store(metadata)
20
+ end
21
+
22
+ private
23
+
24
+ def stub_metadata
25
+ {
26
+ :release => '1068.9.0',
27
+ :sha1_b64 => 'foo',
28
+ :sha256_b64 => 'bar',
29
+ :size => '123',
30
+ :track => 'stable'
31
+ }
32
+ end
33
+ end
@@ -0,0 +1,75 @@
1
+ require 'test_helper'
2
+ require 'smart_proxy_omaha/configuration_loader'
3
+ require 'smart_proxy_omaha/omaha_plugin'
4
+
5
+ ENV['RACK_ENV'] = 'test'
6
+
7
+ class TestForemanClient
8
+ def post_facts(factsdata); end
9
+ def post_report(report); end
10
+ end
11
+
12
+ class TestReleaseRepository
13
+ def releases(track)
14
+ ['1068.9.0', '1122.2.0'].map { |release| Gem::Version.new(release) }
15
+ end
16
+
17
+ def latest_os(track)
18
+ releases(track).max
19
+ end
20
+ end
21
+
22
+ class TestMetadataProvider
23
+ def get(track, release)
24
+ Proxy::Omaha::Metadata.new(
25
+ :track => track,
26
+ :release => release,
27
+ :sha1_b64 => '+ZFmPWzv1OdfmKHaGSojbK5Xj3k=',
28
+ :sha256_b64 => 'cSBzKN0c6vKinrH0SdqUZSHlQtCa90vmeKC7p/xk19M=',
29
+ :size => '212555113'
30
+ )
31
+ end
32
+
33
+ def store(metadata); end
34
+ end
35
+
36
+ module Proxy::Omaha
37
+ module DependencyInjection
38
+ include Proxy::DependencyInjection::Accessors
39
+ def container_instance
40
+ Proxy::DependencyInjection::Container.new do |c|
41
+ c.singleton_dependency :foreman_client_impl, TestForemanClient
42
+ c.singleton_dependency :release_repository_impl, TestReleaseRepository
43
+ c.singleton_dependency :metadata_provider_impl, TestMetadataProvider
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ require 'smart_proxy_omaha/omaha_api'
50
+
51
+ class OmahaApiTest < Test::Unit::TestCase
52
+ include Rack::Test::Methods
53
+
54
+ def app
55
+ Proxy::Omaha::Api.new
56
+ end
57
+
58
+ def test_processes_update_complete_noupdate
59
+ post "/v1/update", xml_fixture('request_update_complete_noupdate')
60
+ assert last_response.ok?, "Last response was not ok: #{last_response.status} #{last_response.body}"
61
+ assert_equal xml_fixture('response_update_complete_noupdate'), last_response.body
62
+ end
63
+
64
+ def test_processes_update_complete_update
65
+ post "/v1/update", xml_fixture('request_update_complete_update')
66
+ assert last_response.ok?, "Last response was not ok: #{last_response.status} #{last_response.body}"
67
+ assert_equal xml_fixture('response_update_complete_update'), last_response.body
68
+ end
69
+
70
+ def test_processes_update_complete_error
71
+ post "/v1/update", xml_fixture('request_update_complete_error')
72
+ assert last_response.ok?, "Last response was not ok: #{last_response.status} #{last_response.body}"
73
+ assert_equal xml_fixture('response_update_complete_error'), last_response.body
74
+ end
75
+ end