smart_proxy_omaha 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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