We're using chef to manage Ruby versions in our vagrant setup using rbenv and ruby-build. One feature we'd like, even though rbenv pointedly refuses to implement it, is to have "fuzzy" version matching for ruby versions (e.g. converting 1.9.3 to 1.9.3-p123).
I'd like this to be handled transparently in a standalone recipe which can be placed between ruby-build and rbenv in the run_list. My code "works" (determines the latest matching ruby version based on the output of ruby-build --definitions), but changes are not persisted when running the rbenv cookbook, so I assume they are local to my cookbook. Is there any way to update an attribute globally for the duration of the run?
I should add that I'm not familiar with chef. This is outside of the domain that I usually work in. I know that this is probably a strange use case, and if what I'm trying to do is truly egregious, what would be a better way to accomplish what I want?
Here's the general outline of my current recipe:
original_rbenv_rubies = node[:rbenv][:rubies]
new_rbenv_rubies = determine_full_ruby_versions original_rbenv_rubies
node.force_override[:rbenv][:rubies] = new_rbenv_rubies
I've solved this by using my cookbook as a wrapper for the rbenv cookbook. I moved the logic above into the default attributes file, and used include_recipe to include the original recipes in my own. For some reason, the new attributes still weren't being picked up, so I moved the original values into node[:rbenv_wrapper][:rubies], and used override to set the new ones in node[:rbenv][:rubies], after which everything worked as expected.
Related
We have a local Ruby Library that we include in a lot of our ruby projects. It contains a lot of configuration information that would be extremely useful to use in our chef scripts. This allows us to put all of our configuration in one place, so we don't have to make multiple places everytime we change a database etc. Trying to keep the code DRY. That being said, the code are straight ruby functions, not in the chef DSL.
I have been trying to pull the library into Chef, but have found it very difficult. Which makes me think I'm going against some sort of pattern.
I have tried and didn't work.
- Add the Ruby Code via require_relative and includes.
- Add the Ruby Code to it's own cookbook, then wrap the cookbook.
- Create a local ruby gem (not retrievable via rubygems, or other repo)
What worked:
- Copying and pasting the code into a cookbook. (but it's not sharable.)
My real question, what is the best way to share this ruby code library amongst many cookbooks? Depending on the best way, how do you actually do it?, or pointers in the right direction.
thanks.
myles.
I would use Halite (disclaimer: my project) to convert the gem into a cookbook and then upload it as a cookbook. Then you can depend on it and require stuff from it like normal in your Chef code.
You can create a cookbook and copy the ruby code into libraries folder of the cookbook. Then it will be loaded by Chef automatically on node, as soon as you include the cookbook into run list.
Could you tell, what exactly you did, and what didn't work when you tried "Add the Ruby Code to it's own cookbook, then wrap the cookbook"?
I have created a ruby library. Basically, it reads the ip of the server in opsworks. Once it gets that it knows what environment it is in, and it will set a hash. This hash is then used to set the attributes. This way all the server configurations are stored in one place.
I can put the code in each different cookbook that needs it. However, I have to duplicate the code in each different cookbook. I would like to put the code in one place, and include it in each cookbook. That way if I have to modify it, I only have to do it in one place.
I tried making it a gem, and requiring it with no luck.
I also created a cookbook with nothing but the ruby code in a library. I then included "depends etc" that cookbook in another and tried to run the library functions, but I couldn't get it to work.
I may have been on the right track, but I stopped before I got it working.
Essentially I want to write a simple ruby code library, that I can use in any cookbook I want. There must be a way to do this, but I've run into some dead ends. I'll keep banging my head against the wall. Eventually, a hole will open up!
I have two isolated Ruby installations (one for Chef, one for Sensu). From within the Chef installation, I'd like to get a list of all versions of a gem installed into the Sensu ruby. I know the absolute paths of both installations at runtime.
I've used Gem::Specification::find_all_by_name before to great effect, and this is the sort of method I'm looking for, but it only seems to work on the currently executing ruby, and doesn't seem to have any kind of notion of reusability.
One way would be to use gem list with grep and parse that output, but i'd really rather not have to shell out to solve the problem, I prefer an in-ruby solution. I could also inspect the filesystem myself and recreate the logic of Gem::Specification, but that's not that much better than shelling out.
Is there a way to get equivalent output to Gem::Specification without duplicating the parsing logic myself?
Gem::Specification has a (global) property called dirs which allows you to specify an array of paths that Gem::Specification will use when searching for specifications.
Note that the path it expects must be the parent folder of "specifications", so for instance /opt/embedded/product/lib/specifications will not work, but /opt/embedded/product/lib will work.
I'm using gem-ctags and rbenv-ctags to index my gems and ruby libraries.
Also using a few plugins that affect where Vim looks for tag files:
vim-ruby (ruby standard library)
vim-bundler (gems)
vim-fugitive (git repo)
vim-rails (Rails project)
It's great being able to jump around a well-indexed code-base, but I'm finding that Vim's 'tags' option is getting mishandled as I navigate the tag stack.
I'll start in a Rails project and find I can jump pretty much anywhere I want: within the app, into the ruby standard library (for the version of ruby relevant to the current project), or into a gem. So I jump into a gem, but then Vim can no longer find the tags for that gem, so I can't do any more easy navigation inside it.
For example: I have ruby 2.1.0 and 2.2.0 installed, and 2.2.0 is set as the global default.
Start Vim with an empty buffer from the root directory of a Rails app that uses ruby 2.1.0.
Executing :verbose set tags? shows 'tags' was last set by vim-rails.
Tags are available within the app itself, in ruby's standard library (2.1.0), and in gems (also 2.1.0).
Open a file in the project.
It now reports 'tags' was last set by vim-fugitive.
Same tag goodness as above. Fine so far.
Jump to a tag in a gem.
Now 'tags' was last set by vim-bundler, and it only includes the working directory, the current buffer's directory, and the ruby 2.2.0 standard library.
How can I make sure the tags file sitting in the root directory of whatever gem I'm navigating are found?
NOTE: I took inspiration from Tim Pope's rbenv-sentience and added an appropriate .ruby-version file to the root of each ruby installation. 'tags' still loses the gems paths when I navigate into a gem, but now it at least reflects the right version of the standard library. One step closer...
I think I got it. Part of the answer was setting a .ruby-version local to each ruby installation. This ensured that whenever I was in a subdirectory of that installation (within an installed gem, for instance), it looked to the correct ruby installation's standard library.
The main fix, however seems to be searching recursively upwards from the current buffer or directory:
set tags-=./tags,tags
set tags+=./tags;~,tags;~
As per this thread, the semi-colon syntax allows you to search upwards until a designated "stop" directory (in my case ~).
Actually, I probably only need to apply this change to the directory-of-current-buffer (./tags;~), since that'll cover 99% of my use cases.
It would also be nice if it could recognize the project's root directory and only search that far upwards, but I haven't found a way to accomplish that yet.
As the title states, I'm a beginner in Ruby.
My project uses 2 existing gems - which I want to modify.
I've forked the gems on GitHub and put them as modules in my repo and they show up as a subdirectory.
I've tried researching this, but I keep on getting lost - I'm thinking I'm missing some basic concepts/knowledge here.
My questions:
Am I going about this right/wrong?
Is it even possible to include the code of those (forked) gems in my actual project, or should I update them separately and just use them as actual gems with require (this seems very cumbersome)
If these gems are part of my project, how do I use them properly, I assume I don't need the require piece? If not, how do I access/use them?
Thanks!
BTW, using Ruby 1.9.2-p194 on Ubuntu with RubyMine as the IDE.
Probably wrong. Ruby is a very flexible language, and has what are called open classes. This means that you can open up and change classes at run-time. Doing this on an external library is called monkey patching. So instead of having to replicate all of the code you want to stay consistent, you can just modify the classes and override any methods you want.
A simple example:
class Fixnum
def is_multiple_of_three?
self % 3 == 0
end
end
However, if the changes you want are really significant, it could make sense to fork the gem.
I recommend the bundler gem. This will let you make a Gemfile which lists all of your dependencies. You can list a github repository as a source for the gem, like so:
gem 'gem_name_here', :git => 'git://github.com/username_here/gem_name_here.git'
and then run bundle install to install your dependencies.
If you install the gems with bundler, it acts just like any other gem you have installed.
Why should I/should I not use RVM?
I'm new to the ruby language and servers as a whole. I've had some trouble installing using RVM...so I'm inclined to not use it right now, but it seems like it may make installations down the road easier?
I'm interested to hear about your experience with RVM and your thoughts as it pertains to maintaining a server.
RVM is useful even if you don't want to install multiple versions at the same time. I'm a ruby hobbyist (PHP during the day :(), and I have no reason to want to use old versions, but I still use RVM.
Installing ruby is a pain. Getting it from the package manager (at least in ubuntu) gives you an outdated version that changes installation directories from the defaults. I've had nothing but problems with it.
So you think, "I'll just build it from source". Building from source requires getting a load of dependencies and configuring options. Often times I've built ruby only to find out I forgot to enable SSL support or readline support.
RVM takes care of all of this. In 3 or so commands, you have a perfectly built version of ruby.
And I didn't even cover how RVM manages multiple ruby installations for you, which is its killer feature. If you have that need, there is really no other sane solution.
RVM is great as this allows your to install different versions without touching your system's default Ruby install. It is rather similar to virtualenv's in Python.
Another great advantage to having RVM are the gemsets - you can create as many gemsets that are unique to the version, and patch level, of ruby.
I've extolled some of its virtues here and you should also see this blog post.
In terms of maintaining a server - let's take a Passenger install for example; do remember that Passenger is installed as a gem, so with rvm the benefit here is that you can have multiple installs of passenger, tied to a different version of ruby. Of course, typically, you'll have Passenger running on one version at a time, although there are ways to have Passenger, in particular, running on different ruby versions.
I use different Ruby versions for different projects (that's where .rvmrc is really handy). Some deployment environments are happy with 1.9, while there are a couple of legacy servers using 1.8 for some reasons. Also, occasionally I want to launch a specific version of ruby to compare how they work. RVM does all that for me.
When you are first getting used to Ruby, it may not entirely be necessary. That said, what it does is set you up for success in the future. Because once you get hooked, you may end up playing with projects that need to move from, say, MRI 1.8.x to 1.9.x. Or from 1.9.x, to JRuby 1.6.x. My experience is that this happens irregularly, but when it does, there's no substitute for RVM.
Outside of that, the other biggest feature that I use regularly, is the ability to segment one particular release. So I can have an environment for 'stable' gems, and an environment for 'unstable' gems. For instance, while Rails 3.1 has been in release candidate mode, I've had one main workspace for 1.9.2 and a separate space for Rails 3.1.rc? gems on 1.9.2. That makes it possible for me to keep developing my main Rails 3.0 stuff (with one command at the CLI), without having to specify full file paths to the appropriate rails bin files in order to use the older files.
If you're using a Debian based platform where the packagers/policy leads to a really bad default installation you'll have a way better experience using rvm.