use curl for detection until I find a better method
[opensuse:obs-autotest.git] / bin / obs-autotest
1 #!/usr/bin/ruby
2 #
3 # Copyright (c) 2010 Novell, Inc.
4 # All Rights Reserved.
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of either version 2 or version 3 of the
8 # GNU General Public License as published by the Free Software Foundation.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of both the GNU General Public License
16 # version 2 and the GNU General Public License version 3 along with this 
17 # program;
18 # if not, contact Novell, Inc.
19 #
20 # To contact Novell about this file by physical or electronic mail,
21 # you may find current contact information at www.novell.com
22 #  
23 # == Synopsis
24 #
25 # obs-autotest: starts last built image
26 #
27 # == Usage
28 #
29 # obs-autotest [OPTION] ...
30 #
31 # -h, --help:
32 #    show help
33 #
34 # --api x, -A x:
35 #    use build service api url (default: http://api.suse.de)
36 #
37 # --project x:
38 #    use the given project
39 #
40 # --package x:
41 #    use image from this package
42 #
43 # --arch a:
44 #    use the following arch, default i586
45 #
46 require 'getoptlong'
47 require 'rdoc/usage'
48 require 'fileutils'
49 require 'logger'
50 require 'tmpdir'
51 require 'timeout'
52
53 log = Logger.new(STDOUT)
54 log.level = Logger::INFO
55
56 opts = GetoptLong.new(
57   [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
58   [ '--api', '-A', GetoptLong::REQUIRED_ARGUMENT ],
59   [ '--project', GetoptLong::REQUIRED_ARGUMENT ],
60   [ '--package', GetoptLong::REQUIRED_ARGUMENT ],
61   [ '--arch', GetoptLong::REQUIRED_ARGUMENT ],
62   [ '--guest-port', GetoptLong::REQUIRED_ARGUMENT ],
63   [ '--image-port', GetoptLong::REQUIRED_ARGUMENT ]
64 )
65
66 project = nil
67 package = nil
68 arch = "i586"
69 api = "http://api.opensuse.org"
70 project = nil
71 guest_port = 9999
72 image_port = 80
73
74 opts.each do |opt, arg|
75   case opt
76   when '--help'
77     RDoc::usage
78   when '--project'
79     project = arg
80   when '--package'
81     package = arg
82   when '--arch'
83     arch = arg
84   when '--api'
85     api = arg
86   when '--guest-port'
87     guest_port = arg.to_i
88   when '--image-port'
89     image_port = arg.to_i
90   end
91 end
92
93 log.error("No project specified") and exit(1) if project.nil?
94 log.error("No package specified") and exit(1) if package.nil?
95
96 cache_dir = File.join(Dir.tmpdir, 'obs-autotest')
97 FileUtils.mkdir_p(cache_dir)
98
99 log.info "Cleaning unpacked images directory..."
100 unpack_dir = File.join(Dir.tmpdir, 'obs-autotest-vm')
101 FileUtils.rm_rf(unpack_dir)
102 FileUtils.mkdir_p(unpack_dir)
103
104 log.info "Retrieving images..."
105 `osc -A '#{api}' getbinaries -d '#{cache_dir}' '#{project}' '#{package}' images '#{arch}'`
106
107 sorted_images = Dir.glob("#{cache_dir}/*.tar.bz2").to_a.sort { |a,b| File.mtime(a) <=> File.mtime(b) }
108
109 if sorted_images.empty?
110   log.error "No images to test..."
111   exit(1)
112 end
113
114 log.info "Newer image: #{sorted_images.last}"
115
116 Dir.chdir(unpack_dir) do
117   log.info "Unpacking image..."
118   `tar -jxpvf '#{sorted_images.last}'`
119   disk = Dir.glob("*.vmdk").first
120   if disk
121     log.info "Booting qemu with disk #{disk}..."
122     readme, writeme = IO.pipe
123     cmd = ['qemu-kvm', '-redir', "tcp:#{guest_port}::#{image_port}", disk]
124     log.info "Running #{cmd.join(' ')}"
125     pid = fork {
126       # child
127       $stdout.reopen writeme
128       readme.close
129       exec(*cmd)
130     }
131     #parent
132     writeme.close
133     # loop until webyast is booted
134     log.info "Waiting for WebYaST to boot..."
135
136     begin
137       status = Timeout::timeout(120) do
138         while true
139           # ruby ping does not work here. No idea
140           # `ping -c 3 -W 3 localhost #{guest_port}`
141           `curl --connect-timeout 2 --insecure https://localhost:#{guest_port}`
142           break if $? == 0
143           log.info "waiting..."
144         end
145         log.info "booted!!"
146       end      
147     rescue Timeout::Error
148       log.error "WebYaST did not came up!!"
149       Process.kill("HUP", pid)
150       exit(1)
151     end
152     log.info "Image port #{image_port} available on localhost port #{guest_port}"
153     Process.waitpid(pid)
154     
155   else
156     log.error "No disk found in image"
157     exit(1)
158   end
159 end