Merge pull request #743 from mnemonikk/develop

added modules and state modules for rubygem and rvm support; see #667
This commit is contained in:
Thomas S Hatch 2012-02-23 06:41:24 -08:00
commit cd031782cd
4 changed files with 657 additions and 0 deletions

131
salt/modules/gem.py Normal file
View File

@ -0,0 +1,131 @@
"""
Manage ruby gems.
"""
__opts__ = {
"rvm.runas": None,
}
import re
def _gem(command, ruby = None, runas = None):
cmdline = "gem {command}".format(command = command)
if __salt__["rvm.is_installed"]:
return __salt__["rvm.do"](ruby, cmdline, runas = runas)
ret = __salt__["cmd.run_all"](cmdline, runas = runas or __opts__["rvm.runas"])
if ret["retcode"] == 0:
return ret["stdout"]
else:
return False
def install(gems, ruby = None, runas = None):
"""
Installs one or several gems.
gems
The gems to install.
ruby : None
If RVM is installed, the ruby version and gemset to use.
runas : None
The user to run gem as.
"""
return _gem("install {gems}".format(gems = gems), ruby, runas = runas)
def uninstall(gems, ruby = None, runas = None):
"""
Uninstall one or several gems.
gems
The gems to uninstall.
ruby : None
If RVM is installed, the ruby version and gemset to use.
runas : None
The user to run gem as.
"""
return _gem("uninstall {gems}".format(gems = gems), ruby, runas = runas)
def update(gems, ruby = None, runas = None):
"""
Update one or several gems.
gems
The gems to update.
ruby : None
If RVM is installed, the ruby version and gemset to use.
runas : None
The user to run gem as.
"""
return _gem("update {gems}".format(gems = gems), ruby, runas = runas)
def update_system(version = "", ruby = None, runas = None):
"""
Update rubygems.
version : (newest)
The version of rubygems to install.
ruby : None
If RVM is installed, the ruby version and gemset to use.
runas : None
The user to run gem as.
"""
return _gem("update --system {version}".format(version = version), ruby, runas = runas)
def list(prefix = "", ruby = None, runas = None):
"""
List locally installed gems.
prefix :
Only list gems when the name matches this prefix.
ruby : None
If RVM is installed, the ruby version and gemset to use.
runas : None
The user to run gem as.
"""
gems = {}
for line in _gem("list {prefix}".format(prefix = prefix), ruby, runas = runas).splitlines():
m = re.match("^([^ ]+) \((.+)\)", line)
if m:
gem = m.group(1)
versions = m.group(2).split(", ")
gems[gem] = versions
return gems
def sources_add(source_uri, ruby = None, runas = None):
"""
Add a gem source.
source_uri
The source URI to add.
ruby : None
If RVM is installed, the ruby version and gemset to use.
runas : None
The user to run gem as.
"""
return _gem("sources --add {source_uri}".format(source_uri = source_uri), ruby, runas = runas)
def sources_remove(source_uri, ruby = None, runas = None):
"""
Remove a gem source.
source_uri
The source URI to remove.
ruby : None
If RVM is installed, the ruby version and gemset to use.
runas : None
The user to run gem as.
"""
return _gem("sources --remove {source_uri}".format(source_uri = source_uri), ruby, runas = runas)
def sources_list(ruby = None, runas = None):
"""
List the configured gem sources.
ruby : None
If RVM is installed, the ruby version and gemset to use.
runas : None
The user to run gem as.
"""
return _gem("sources", ruby, runas = runas).splitlines()[2:]

235
salt/modules/rvm.py Normal file
View File

@ -0,0 +1,235 @@
"""
Manage ruby installations and gemsets with RVM, the Ruby Version Manager.
"""
__opts__ = {
"rvm.runas": None,
}
import re
def _rvm(command, arguments = "", runas = None):
if not is_installed():
return False
ret = __salt__["cmd.run_all"]("/usr/local/rvm/bin/rvm {command} {arguments}".format(command = command, arguments = arguments), runas = runas or __opts__["rvm.runas"])
if ret["retcode"] == 0:
return ret["stdout"]
else:
return False
def _rvm_do(ruby, command, runas = None):
return _rvm("{ruby} do {command}".format(ruby = ruby or "default", command = command), runas = runas)
def is_installed():
"""
Check if RVM is installed.
"""
return __salt__["cmd.has_exec"]("/usr/local/rvm/bin/rvm")
# RVM dependencies on Ubuntu 10.04:
# bash coreutils gzip bzip2 gawk sed curl git-core subversion sudo
def install():
"""
Install RVM system wide.
"""
return 0 == __salt__["cmd.retcode"](
# the RVM installer only does a multi-user install when it is invoked under sudo
"curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer | sudo bash -s stable")
# MRI/RBX/REE dependencies for Ubuntu 10.04:
# build-essential openssl libreadline6 libreadline6-dev curl
# git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0
# libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev autoconf libc6-dev
# libncurses5-dev automake libtool bison subversion ruby
def install_ruby(ruby, runas = None):
"""
Install a ruby implementation.
ruby
The version of ruby to install.
runas : None
The user to run rvm as.
"""
return _rvm("install", ruby, runas = runas)
def reinstall_ruby(ruby, runas = None):
"""
Reinstall a ruby implementation.
ruby
The version of ruby to reinstall.
runas : None
The user to run rvm as.
"""
return _rvm("reinstall", ruby, runas = runas)
def list(runas = None):
"""
List all rvm installed rubies.
runas : None
The user to run rvm as.
"""
rubies = []
for line in _rvm("list", "", runas = runas).splitlines():
m = re.match("^[= ]([*> ]) ([^- ]+)-([^ ]+) \[ (.*) \]", line)
if m:
rubies.append([m.group(2), m.group(3), m.group(1) == "*"])
return rubies
def set_default(ruby, runas = None):
"""
Set the default ruby.
ruby
The version of ruby to make the default.
runas : None
The user to run rvm as.
"""
return _rvm("alias", "create default {ruby}".format(ruby = ruby), runas = runas)
def get(version = "stable", runas = None):
"""
Update RVM.
version : stable
Which version of RVM to install, e.g. stable or head.
ruby
The version of ruby to reinstall.
"""
return _rvm("get", version, runas = runas)
def wrapper(ruby_string, wrapper_prefix, runas = None, *binaries):
"""
Install RVM wrapper scripts.
ruby_string
Ruby/gemset to install wrappers for.
wrapper_prefix
What to prepend to the name of the generated wrapper binaries.
runas : None
The user to run rvm as.
binaries : None
The names of the binaries to create wrappers for. When nothing is given, wrappers for ruby, gem, rake, irb, rdoc, ri and testrb are generated.
"""
return _rvm("wrapper", "{ruby_string} {wrapper_prefix} {binaries}".
format(ruby_string = ruby_string,
wrapper_prefix = wrapper_prefix,
binaries = " ".join(binaries)), runas = runas)
def rubygems(ruby, version, runas = None):
"""
Installs a specific rubygems version in the given ruby.
ruby
The ruby to install rubygems for.
version
The version of rubygems to install or 'remove' to use the version that ships with 1.9
runas : None
The user to run rvm as.
"""
return _rvm_do(ruby, "rubygems", version, runas = runas)
def gemset_create(ruby, gemset, runas = None):
"""
Creates a gemset.
ruby
The ruby version to create the gemset for.
gemset
The name of the gemset to create.
runas : None
The user to run rvm as.
"""
return _rvm_do(ruby, "rvm gemset create {gemset}".format(gemset = gemset), runas = runas)
def gemset_list(ruby = "default", runas = None):
"""
List all gemsets for the given ruby.
ruby : default
The ruby version to list the gemsets for
runas : None
The user to run rvm as.
"""
gemsets = []
for line in _rvm_do(ruby, "rvm gemset list", runas = runas).splitlines():
m = re.match("^ ([^ ]+)", line)
if m:
gemsets.append(m.group(1))
return gemsets
def gemset_delete(ruby, gemset, runas = None):
"""
Deletes a gemset.
ruby
The ruby version the gemset belongs to.
gemset
The gemset to delete.
runas : None
The user to run rvm as.
"""
return _rvm_do(ruby, "rvm --force gemset delete {gemset}".format(gemset = gemset), runas = runas)
def gemset_empty(ruby, gemset, runas = None):
"""
Remove all gems from a gemset.
ruby
The ruby version the gemset belongs to.
gemset
The gemset to empty.
runas : None
The user to run rvm as.
"""
return _rvm_do(ruby, "rvm --force gemset empty", gemset, runas = runas)
def gemset_copy(source, destination, runas = None):
"""
Copy all gems from one gemset to another.
source
The name of the gemset to copy, complete with ruby version.
destination
The destination gemset.
runas : None
The user to run rvm as.
"""
return _rvm("gemset copy", source, destination, runas = runas)
def gemset_list_all(runas = None):
"""
List all gemsets for all installed rubies.
Note that you must have set a default ruby before this can work.
runas : None
The user to run rvm as.
"""
gemsets = {}
current_ruby = None
for line in _rvm_do("default", "rvm gemset list_all", runas = runas).splitlines():
m = re.match("^gemsets for ([^ ]+)", line)
if m:
current_ruby = m.group(1)
gemsets[current_ruby] = []
m = re.match("^ ([^ ]+)", line)
if m:
gemsets[current_ruby].append(m.group(1))
return gemsets
def do(ruby, command, runas = None):
"""
Execute a command in an RVM controlled environment.
ruby:
The ruby to use.
command:
The command to execute.
runas : None
The user to run rvm as.
"""
return _rvm_do(ruby, command, runas = runas)

70
salt/states/gem.py Normal file
View File

@ -0,0 +1,70 @@
"""
Management of rubygems
=======================
A state module to manage rubygems. Gems can be set up to be installed
or removed. This module will use RVM if it is installed. In that case
you can specify what ruby version and gemset to target.
.. code-block:: yaml
addressable:
gem:
- installed
- runas: rvm
- ruby: jruby@jgemset
"""
def installed(name, ruby = None, runas = None):
"""
Make sure that a gem is installed.
name
The name of the gem to install
ruby : None
For RVM installations: the ruby version and gemset to target.
runas : None
The user to run gem as.
"""
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
if name in __salt__["gem.list"](name, ruby, runas = runas):
ret["result"] = True
ret["comment"] = "Gem is already installed."
return ret
if __salt__["gem.install"](name, ruby, runas = runas):
ret["result"] = True
ret["changes"][name] = "Installed"
ret["comment"] = "Gem was successfully installed"
else:
ret["result"] = False
ret["comment"] = "Could not install gem."
return ret
def removed(name, ruby = None, runas = None):
"""
Make sure that a gem is not installed.
name
The name of the gem to uninstall
ruby : None
For RVM installations: the ruby version and gemset to target.
runas : None
The user to run gem as.
"""
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
if name not in __salt__["gem.list"](name, ruby, runas = runas):
ret["result"] = True
ret["comment"] = "Gem is not installed."
return ret
if __salt__["gem.uninstall"](name, ruby, runas = runas):
ret["result"] = True
ret["changes"][name] = "Removed"
ret["comment"] = "Gem was successfully removed."
else:
ret["result"] = False
ret["comment"] = "Could not remove gem."
return ret

221
salt/states/rvm.py Normal file
View File

@ -0,0 +1,221 @@
"""
Management of ruby installations and gemsets with RVM
=====================================================
This module is used to install and manage ruby installations and
gemsets with RVM, the Ruby Version Manager. Different versions of ruby
can be installed and gemsets created. RVM itself will be installed
automatically if it's not present. This module will not automatically
install packages that RVM depends on or ones that are needed to build
ruby. If you want to run RVM as an unprivileged user (recommended) you
will have to create this user yourself. This is how a state
configuration could look like:
.. code-block:: yaml
rvm:
group:
- present
user:
- present
- gid: rvm
- home: /home/rvm
- require:
- group: rvm
rvm-deps:
pkg:
- installed
- names:
- bash
- coreutils
- gzip
- bzip2
- gawk
- sed
- curl
- git-core
- subversion
- sudo
mri-deps:
pkg:
- installed
- names:
- build-essential
- openssl
- libreadline6
- libreadline6-dev
- curl
- git-core
- zlib1g
- zlib1g-dev
- libssl-dev
- libyaml-dev
- libsqlite3-0
- libsqlite3-dev
- sqlite3
- libxml2-dev
- libxslt1-dev
- autoconf
- libc6-dev
- libncurses5-dev
- automake
- libtool
- bison
- subversion
- ruby
jruby-deps:
pkg:
- installed
- names:
- curl
- g++
- openjdk-6-jre-headless
ruby-1.9.2:
rvm:
- installed
- default: True
- runas: rvm
- require:
- pkg: rvm-deps
- pkg: mri-deps
- user: rvm
jruby:
rvm:
- installed
- runas: rvm
- require:
- pkg: rvm-deps
- pkg: jruby-deps
- user: rvm
jgemset:
rvm:
- gemset_present
- ruby: jruby
- runas: rvm
- require:
- rvm: jruby
mygemset:
rvm:
- gemset_present
- ruby: ruby-1.9.2
- runas: rvm
- require:
- rvm: ruby-1.9.2
"""
import re
def _check_rvm(ret):
if not __salt__["rvm.is_installed"]():
if __salt__["rvm.install"]():
ret["changes"]["rvm"] = "Installed"
else:
ret["result"] = False
ret["comment"] = "Could not install RVM."
return ret
def _check_and_install_ruby(ret, ruby, default = False, runas = None):
ret = _check_ruby(ret, ruby, runas = runas)
if not ret["result"]:
if __salt__["rvm.install_ruby"](ruby, runas = runas):
ret["result"] = True
ret["changes"][ruby] = "Installed"
ret["comment"] = "Successfully installed ruby."
ret["default"] = False
else:
ret["result"] = False
ret["comment"] = "Could not install ruby."
return ret
if not ret["default"] and default:
__salt__["rvm.set_default"](ruby, runas = runas)
return ret
def _check_ruby(ret, ruby, runas = None):
match_version = True
match_micro_version = False
micro_version_regex = re.compile("-([0-9]{4}\.[0-9]{2}|p[0-9]+)$")
if micro_version_regex.match(ruby):
match_micro_version = True
if re.match("^[a-z]+$", ruby):
match_version = False
ruby = re.sub("^ruby-", "", ruby)
for impl, version, default in __salt__["rvm.list"](runas = runas):
if impl != "ruby":
version = "{impl}-{version}".format(impl = impl, version = version)
if not match_micro_version:
version = micro_version_regex.sub("", version)
if not match_version:
version = re.sub("-.*", "")
if version == ruby:
ret["result"] = True
ret["comment"] = "Requested ruby exists."
ret["default"] = default
break
return ret
def installed(name, default = False, runas = None):
"""
Verify that the specified ruby is installed with RVM. RVM is installed when necessary.
name
The version of ruby to install
default : False
Whether to make this ruby the default.
runas : None
The user to run rvm as.
"""
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
ret = _check_rvm(ret)
if ret["result"] == False:
return ret
return _check_and_install_ruby(ret, name, default, runas = runas)
def gemset_present(name, ruby = "default", runas = None):
"""
Verify that the gemset is present.
name
The name of the gemset.
ruby : default
The ruby version this gemset belongs to.
runas : None
The use user to run rvm as.
"""
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
ret = _check_rvm(ret)
if ret["result"] == False:
return ret
if name.find("@") != -1:
ruby, name = name.split("@")
ret = _check_ruby(ret, ruby)
if not ret["result"]:
ret["result"] = False
ret["comment"] = "Requested ruby implementation was not found."
return ret
if name in __salt__["rvm.gemset_list"](ruby, runas = runas):
ret["result"] = True
ret["comment"] = "Gemset already exists."
else:
if __salt__["rvm.gemset_create"](ruby, name, runas = runas):
ret["result"] = True
ret["comment"] = "Gemset successfully created."
ret["changes"][name] = "created"
else:
ret["result"] = False
ret["comment"] = "Gemset could not be created."
return ret