Skip to content

Commit

Permalink
Merge pull request #3 from susestudio/workshop_2012
Browse files Browse the repository at this point in the history
[Review] Request from 'vlewin' @ 'susestudio/ssc/workshop_2012'
  • Loading branch information
ytsarev committed Jun 22, 2012
2 parents 5148bf1 + f60aec8 commit 542f707
Show file tree
Hide file tree
Showing 15 changed files with 267 additions and 143 deletions.
8 changes: 5 additions & 3 deletions Gemfile
Expand Up @@ -2,13 +2,15 @@ source "http://rubygems.org"

gem "studio_api", ">= 3.1.2"
gem "thor", ">=0.14.6"
gem "json"

gem 'simplecov', :require => false, :group => :test

# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
group :development do
gem "shoulda", ">= 0"
gem "mocha", ">= 0"
gem "bundler", "~> 1.0.0"
gem "jeweler", "~> 1.6.0"
gem "rcov", ">= 0"
gem "bundler"
gem "jeweler"
end
60 changes: 38 additions & 22 deletions Gemfile.lock
@@ -1,39 +1,55 @@
GEM
remote: http://rubygems.org/
specs:
activemodel (3.0.0)
activesupport (= 3.0.0)
builder (~> 2.1.2)
i18n (~> 0.4.1)
activeresource (3.0.0)
activemodel (= 3.0.0)
activesupport (= 3.0.0)
activesupport (3.0.0)
builder (2.1.2)
activemodel (3.2.5)
activesupport (= 3.2.5)
builder (~> 3.0.0)
activeresource (3.2.5)
activemodel (= 3.2.5)
activesupport (= 3.2.5)
activesupport (3.2.5)
i18n (~> 0.6)
multi_json (~> 1.0)
builder (3.0.0)
git (1.2.5)
i18n (0.4.1)
jeweler (1.6.0)
bundler (~> 1.0.0)
i18n (0.6.0)
jeweler (1.8.3)
bundler (~> 1.0)
git (>= 1.2.5)
rake
mocha (0.9.12)
rake (0.8.7)
rcov (0.9.9)
shoulda (2.11.3)
studio_api (3.1.2)
rdoc
json (1.7.3)
metaclass (0.0.1)
mocha (0.11.4)
metaclass (~> 0.0.1)
multi_json (1.3.6)
rake (0.9.2.2)
rdoc (3.12)
json (~> 1.4)
shoulda (3.0.1)
shoulda-context (~> 1.0.0)
shoulda-matchers (~> 1.0.0)
shoulda-context (1.0.0)
shoulda-matchers (1.0.0)
simplecov (0.6.4)
multi_json (~> 1.0)
simplecov-html (~> 0.5.3)
simplecov-html (0.5.3)
studio_api (3.2.0)
activeresource (>= 2.3.8)
xml-simple (>= 1.0.0)
thor (0.14.6)
xml-simple (1.0.15)
thor (0.15.2)
xml-simple (1.1.1)

PLATFORMS
ruby

DEPENDENCIES
bundler (~> 1.0.0)
jeweler (~> 1.6.0)
bundler
jeweler
json
mocha
rcov
shoulda
simplecov
studio_api (>= 3.1.2)
thor (>= 0.14.6)
86 changes: 40 additions & 46 deletions README.rdoc
Expand Up @@ -15,82 +15,76 @@ This is the new version of the the Suse Studio command line client. Built as a p

=== Command Listing

ssc checkout --appliance-id=N --password=PASSWORD --username=USERNAME # checkout the latest changes to an appliance
ssc commit --appliance-id=N --password=PASSWORD --username=USERNAME # commit changes to studio
ssc status --appliance-id=N --password=PASSWORD --username=USERNAME # show status of the appliance
ssc checkout --appliance-id=N --password=PASSWORD --username=USERNAME --server=SUSE_STUDIO_SERVER # checkout the latest changes to an appliance
ssc commit # commit changes to studio
ssc status # show status of the appliance

ssc appliance # manage appliances

ssc appliance create APPLIANCE_NAME --password=PASSWORD --source-id=N --username=USERNAME # Create an appliance
ssc appliance destroy --appliance-id=N --password=PASSWORD --username=USERNAME # destroy the current appliance
ssc appliance info --appliance-id=N --password=PASSWORD --username=USERNAME # show details of a specific appliance
ssc appliance list --password=PASSWORD --username=USERNAME # list all appliances
ssc appliance status --appliance-id=N --password=PASSWORD --username=USERNAME # gives status of the appliance
ssc appliance create APPLIANCE_NAME --password=PASSWORD --source-id=N --username=USERNAME --server=SUSE_STUDIO_SERVER # Create an appliance
ssc appliance destroy # destroy the current appliance
ssc appliance info # show details of a specific appliance
ssc appliance list # list all appliances
ssc appliance status # gives status of the appliance
ssc appliance diff # get difference between RPMs installed on current machine and SUSE Studio software configuration

ssc package # manage packages

ssc package add NAME --appliance-id=N --password=PASSWORD --username=USERNAME
# add a package to the appliance
ssc package ban NAME --appliance-id=N --password=PASSWORD --username=USERNAME
# ban a package from the appliance
ssc package list [selected|installed] --appliance-id=N --password=PASSWORD --username=USERNAME
# list all selected or installed packages
ssc package remove NAME --appliance-id=N --password=PASSWORD --username=USERNAME
# remove a package from the appliance
ssc package search SEARCH_STRING --appliance-id=N --password=PASSWORD --username=USERNAME
# search available packages and patterns
ssc package unban NAME --appliance-id=N --password=PASSWORD --username=USERNAME
# unban a package for the appliance
ssc package add NAME # add a package to the appliance
ssc package ban NAM # ban a package from the appliance
ssc package list [selected|installed] # list all selected or installed packages
ssc package remove NAME # remove a package from the appliance
ssc package search SEARCH_STRING # search available packages and patterns
ssc package unban NAME # unban a package for the appliance

ssc repository # manage repositories
ssc repository add REPO_IDS --appliance-id=N --password=PASSWORD --username=USERNAME
# add existing repositories to the appliance
ssc repository import URL NAME --password=PASSWORD --username=USERNAME
# import a 3rd party repository into appliance
ssc repository list --appliance-id=N --password=PASSWORD --username=USERNAME
# list all repositories in a given appliance
ssc repository remove REPO_IDS --appliance-id=N --password=PASSWORD --username=USERNAME
# remove existing repositories from appliance
ssc repository search SEARCH_STRING --password=PASSWORD --username=USERNAME
# search all available repositories

ssc repository add REPO_IDS # add existing repositories to the appliance
ssc repository import URL NAME # import a 3rd party repository into appliance
ssc repository list # list all repositories in a given appliance
ssc repository remove REPO_IDS # remove existing repositories from appliance
ssc repository search SEARCH_STRING # search all available repositories


ssc file # manage files
ssc file add PATH --appliance-id=N --password=PASSWORD --username=USERNAME # create a new overlay file
ssc file diff FILE_NAME --appliance-id=N --password=PASSWORD --username=USERNAME
# show the diff of the remote file and the local one
ssc file list --appliance-id=N --password=PASSWORD --username=USERNAME # show all overlay files
ssc file remove FILE_NAME --appliance-id=N --password=PASSWORD --username=USERNAME # removes existing overlay file
ssc file show FILE_NAME --appliance-id=N --password=PASSWORD --username=USERNAME # show the contents of the file
ssc file add PATH # create a new overlay file
ssc file diff FILE_NAME # show the diff of the remote file and the local one
ssc file list # show all overlay files
ssc file remove FILE_NAME # removes existing overlay file
ssc file show FILE_NAME # show the contents of the file


ssc build # manage builds
ssc build --appliance-id=N --password=PASSWORD --username=USERNAME # build an appliance
ssc list --appliance-id=N --password=PASSWORD --username=USERNAME # list builds (running or completed)
ssc status --build-id=N --password=PASSWORD --username=USERNAME # find the build status of an appliance
ssc build # manage builds
ssc build # build an appliance
ssc list # list builds (running or completed)
ssc status --build-id=N # find the build status of an appliance

ssc template # manage templates
ssc template list SET_NAME --password=PASSWORD --username=USERNAME # show details of a particular template set
ssc template list_sets --password=PASSWORD --username=USERNAME # list all available template sets
ssc template list SET_NAME # show details of a particular template set
ssc template list_sets # list all available template sets

ssc help [TASK] # Describe available tasks or one specific task

=== Examples

* Creating and modifying a new appliance:
$ ssc appliance create web_server --source-id=SOURCE_APPLIANCE_ID --username=USERNAME --password=PASSWORD
$ ssc appliance create web_server --source-id=SOURCE_APPLIANCE_ID --username=USERNAME --password=PASSWORD --server=SUSE_STUDIO_SERVER
$ cd web_server
$ ssc package list
$ ssc package add apache
$ ssc file add /etc/apache2/apache2.conf
$ ssc commit

* Checking out an existing appliance and starting a build
$ ssc checkout --appliance-id 59836 --username=USERNAME --password=PASSWORD
$ ssc checkout --appliance-id APPLIANCE_ID --username=USERNAME --password=PASSWORD --server=SUSE_STUDIO_SERVER
$ cd APPLIANCE_NAME
$ ssc build
$ ssc build status

* Performing appliance diff between deployed image and configuration in Studio; example assumes that ssc is running within a deployed appliance
$ ssc checkout --appliance-id=APPLIANCE_ID --username=USERNAME --password=PASSWORD --server=SUSE_STUDIO_SERVER
$ zypper in PACKAGES # install or remove arbitrary package list
$ ssc appliance diff # Show configuration difference between running appliance and configuration is Studio
$ ssc commit # Commit changes back to Studio

== Contributing to ssc

* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
Expand Down
8 changes: 0 additions & 8 deletions Rakefile
Expand Up @@ -32,14 +32,6 @@ Rake::TestTask.new(:test) do |test|
test.verbose = true
end

require 'rcov/rcovtask'
Rcov::RcovTask.new do |test|
test.libs << 'test'
test.pattern = 'test/**/test_*.rb'
test.verbose = true
test.rcov_opts << '--exclude "gems/*"'
end

task :default => :test

require 'rake/rdoctask'
Expand Down
15 changes: 10 additions & 5 deletions lib/directory_manager.rb
Expand Up @@ -33,8 +33,9 @@ def pop(section)
nil
end
end

def push(section, item)
clean
read
if @parsed_file[section].is_a?(Array)
@parsed_file[section] |= [ item ]
Expand All @@ -56,6 +57,10 @@ def empty_list?
read
(!@parsed_file['list']) || (@parsed_file['list'] == []) || (@parsed_file['list'] == {})
end

def clean
File.open(@location, 'w') {} if File.exist?(@location)
end
end

class PackageFile < LocalStorageFile
Expand Down Expand Up @@ -117,11 +122,11 @@ class ApplianceDirectory

def initialize(name= '', options = {})
@name= name
@path= File.join(Dir.pwd, name)
@path= File.join(Dir.pwd, name)
@files = if Dir.exist?(@path)
{:package => PackageFile.new(@path),
:repository => RepositoryFile.new(@path),
:file_list => FileListFile.new(@path)}
:repository => RepositoryFile.new(@path),
:file_list => FileListFile.new(@path)}
else
{}
end
Expand All @@ -141,7 +146,7 @@ def create
end

def valid?
Dir.exists?(@path) && File.exists?(File.join(@path, '.sscrc'))
Dir.exists?(@path) && File.exists?(File.join(@path, '.sscrc'))
end

class << self
Expand Down
4 changes: 2 additions & 2 deletions lib/handlers/all.rb
Expand Up @@ -9,7 +9,7 @@ module SSC::Handler; end
module SSC
module Handler
class Base < Thor

include Helper

API_URL= 'https://susestudio.com/api/v2/user'
Expand All @@ -18,7 +18,7 @@ def initialize(*args)
super

optional_connection_options= filter_options(options, [:timeout, :proxy])
connect(options.username, options.password, optional_connection_options)
connect(options.username, options.password, options.server, optional_connection_options)
@not_local= true if options.remote?
end

Expand Down
75 changes: 75 additions & 0 deletions lib/handlers/appliance.rb
Expand Up @@ -65,6 +65,66 @@ def status
end
end

desc "appliance diff", "difference between RPMs installed on current machine and SUSE Studio configuration"
require_appliance_id
def diff
appliance_state = self.status
raise appliance_state if appliance_state != "Appliance Ok"
# get list of installed packages
rpm_output = `rpm -qa --qf '%{NAME}#%{VERSION}-%{RELEASE}$'`.split('$').sort # TODO: bug check exit code
rpm_output.delete_if {|x| x["gpg-pubkey"] } # remove SUSE gpg-pubkey package

raise "\n*** Command 'rpm 'not found: ensure RPM is installed #{$?.exitstatus}" unless $?.success?

local_packages = Hash[rpm_output.map {|e| e.split('#')}]

# read software yaml and convert to RPM hash format
studio_packages = {}
package_file= PackageFile.new

package_file.read["list"].map{|hash| hash.map{|k,v| studio_packages[k] = v["version"] }}
studio_packages = Hash[studio_packages.sort]

number = studio_packages.compare(local_packages).count + local_packages.compare(studio_packages).count

if number > 0
say "You have #{number} packages that differ from SUSE Studio application configuration:\n"

# compare studio packages with locally installed packages
# if studio package list differ from local package list, add package to remove section
# returns Hash of hashes with package name as a key and versions [studio, local]

say "\n\033[31mremove:\033[0m"
studio_packages.compare(local_packages).map do |name, version|
package = { :name => name, :options => Hash[:version,version.first]}
package_file.push('remove', package) # downgrade if version.last
say "#{name}-#{version.first}"
end

# compare locally installed packages with studio packages
# if local package list differ from studio, add package to add section
# returns Hash of hashes with package name as a key and versions [local, studio]

say "\n\033[32madd:\033[0m"
local_packages.compare(studio_packages).map do |name, version|
package = { :name => name, :options => Hash[:version,version.first]} # commit local package version if differ from studio
package_file.push('add', package)
say "#{name}-#{version.first}"
end


#say "You have #{studio_packages.compare(local_packages).count} packages that differ from SUSE Studio application configuration:\n"
#ap studio_packages.compare(local_packages)

if package_file.save # write to software file
say "#{number} packages changed in the software configuration file", :green
end

else
say "You SUSE Studio software configuration is up-to-date", :green
end
end

private

def download_url(appliance)
Expand All @@ -74,6 +134,21 @@ def download_url(appliance)
appliance.builds.last.download_url
end
end

end
end
end


class Hash
def compare(other)
self.keys.inject({}) do |memo, key|
unless self[key] == other[key]
memo[key] = [self[key], other[key]]
end
memo
end
end
end


2 changes: 1 addition & 1 deletion lib/handlers/build.rb
Expand Up @@ -6,7 +6,7 @@ class Build < Base

desc "build", "Builds an appliance.\n\nAccepted image types: oem, iso, xen, vmx"
require_appliance_id
method_option :image_type, :type => :string, :default => "iso"
method_option :image_type, :type => :string, :default => "iso", :required => true
def build
require_appliance_directory do |appliance, files|
if appliance.status.state != "ok"
Expand Down

0 comments on commit 542f707

Please sign in to comment.