Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improving installation of Bundler #217

Closed
thbar opened this issue Jul 27, 2020 · 11 comments
Closed

Improving installation of Bundler #217

thbar opened this issue Jul 27, 2020 · 11 comments
Assignees

Comments

@thbar
Copy link
Contributor

thbar commented Jul 27, 2020

Poke @rvm/ansible. I'm consolidating a couple of thoughts here as a basis for discussion.

No strong certainties here, mostly a brain dump at this point, and I could be wrong here or there!

There are a number of attempts to let someone specify the version of Bundler:

I believe we'll still have a couple of problems with those approaches:

  • If for some reason a bundler version is installed by default now or in the future, the fact of specifying a version for Bundler won't trigger a reinstall if the version does not match
  • There is no way to install different versions of bundler for different versions of rubies (something which could be problematic in deployments handling old rubies, or different rubies like TruffleRuby or JRuby).

It could be perfectly acceptable for now, but even if that's the case, more testing will be needed.

I'll do more testing & revisit this.

EDIT: if for some reason there is an "order problem" (like I believe I met in the past), we could resort to hooks like Ansistrano does, but I'm not sure at all it is necessary yet, just referencing that for completeness.

@pkuczynski
Copy link
Member

Yeah, I was wondering the same but didn't have any idea how to solve the issue :/

@gildegoma
Copy link
Contributor

gildegoma commented Jul 28, 2020

@thbar thank you very much for filing this issue ❤️
It was exactly what I planned to do "ASAP" (as I was afraid that one of these PRs get merged "too quickly" 😉)

There is no way to install different versions of bundler for different versions of rubies

You mean in the proposed PRs, don't you?

I think this is indeed the way to go: Allow to optionally specify a Bundler version per Ruby.

The probably tricky thing to implement: an optional "detailed" format for elements of the rvm1_rubies array (so you can keep backward compatibility):

rvm1_rubies:
  - 'ruby-2.7.1' # latest release of bundler (if rvm1_bundler_install is true)
  - { ruby: '2.2.10', bundler: '1.17.3' } # install bundler v1.17.3 (if rvm1_bundler_install is true)

In the same "spirit" of roles declaration in a play:

- hosts: webservers
  roles:
    - common
    - { role: foo_app_instance, dir: '/opt/a',  app_port: 5000 }
    - { role: foo_app_instance, dir: '/opt/b',  app_port: 5001 }

@thbar
Copy link
Contributor Author

thbar commented Jul 28, 2020

You welcome @gildegoma! Indeed I was concerned about PR merged too fast, and having to handle back compatibility & changes later.

There is no way to install different versions of bundler for different versions of rubies
You mean in the proposed PRs, don't you?

Yes, this is what I meant indeed!

I thought of exactly the Hash structure you are proposing, keeping backward compatibility with a single string too (but maybe not forever, time will tell).

When you wrote ruby: '2.2.10', I suggest using ruby: 'ruby-2.2.10' instead (full RVM string), because it is required for non-MRI rubies (e.g. JRuby).

I wonder also about:

  • if having a "default bundler version" could also help as a fallback
  • should we allow not installing bundler at all (I would vote for yes)

Let's mull over that a bit. Maybe having #215 sorted out first will be a good thing, so we can write tests more easily to ensure we have backward compatibility here!

@thbar
Copy link
Contributor Author

thbar commented Jul 28, 2020

I am closing the various related PRs for now. I noticed an extra bit of feedback which we can take into account to design a more complete solution:

#197 (comment)

We're using this but something that tripped me up is that by default RVM installs Bundler. That means that the Install bundler if not installed task never runs. I added --without-gems="bundler" to our rvm1_install_flags and it's working as expected.

We should make it easy to avoid the installation of bundler completely, in addition to what's already outlined above.

@thbar
Copy link
Contributor Author

thbar commented Jul 29, 2020

@Kulgar has good thoughts on Slack related to another solution: the removal of installation of bundler from this role. I must verify on my end what this would mean, but it is probably a better solution actually.

I'll let him comment here so we can discuss!

@Kulgar
Copy link

Kulgar commented Jul 29, 2020

So, yeah, I was mostly saying that maybe we shouldn't care about bundler within this rvm ansible role.

We can easily handle bundler installation thanks to the ansible gem module. I already do that for almost all my ansible projects after I installed ruby through this rvm role and it works just fine.

Here is an example of a task I created:

    - name: Ensure bundler gem is installed in right version (with some other gems)
      tags:
        - update-ruby
        - update-gems
      become_user: "{{ rvm_user }}"
      gem:
        name: "{{ item.name }}"
        version: "{{ item.version }}"
        user_install: no
      with_items: "{{ base_gems }}"

# and the items:
base_gems:
  - name: bundler
    version: 1.17.3

In case you need to install bundler for a specific ruby version, I found this old issue: #46
With this interesting part in the latest answer:

    environment:
      PATH: "{{ ansible_env.HOME }}/.rvm/gems/ruby-{{ ruby_version }}/bin:\
             {{ ansible_env.HOME }}/.rvm/gems/ruby-{{ ruby_version }}@global/bin:\
             {{ ansible_env.HOME }}/.rvm/rubies/ruby-{{ ruby_version }}/bin:\
             {{ ansible_env.HOME }}/.rvm/bin:\
             {{ lookup('env', 'PATH') }}"
      GEM_PATH: "{{ ansible_env.HOME }}/.rvm/gems/ruby-{{ ruby_version }}:\
                 {{ ansible_env.HOME }}/.rvm/gems/ruby-{{ ruby_version }}@global"

That way, it would be totally possible to specify which ruby version we want to use to install the gem.
Or you could use the executable option of the ansible gem module to directly point to the right gem binary you want to use (for the right ruby version).

Or if it is more convenient, a simple shell command doing: rvm use ruby_version && gem install bundler would also be something doable.

So... there are a lot of easy way to deal with your bundler installation yourself in your playbooks. I don't think rvm ansible should take care of that, because rvm ansible is a role to install RVM and rubies, not to install gems... I think it is best to rely on the official Ansible module for that part :-)

I think it is best to let the devops deal with the bundler installation themselves and provide them with some documentations on how to do that within the readme or wiki of this ansible role, like : "how to install bundler for a specific ruby version?", or "how to install a gem for a specific gemset created in rvm", etc.

What do you think?

@thbar
Copy link
Contributor Author

thbar commented Jul 30, 2020

@Kulgar overall I feel letting the user install bundler is more flexible & powerful, compared to the attempts I pointed to. The only drawback is that what is described in #46 is not elegant at all. Maybe this could be solved with a bit of documentation or templates, though.

I will have to play around with it in the coming weeks on client projects to figure out what I really prefer, personally!

@gildegoma curious to have your opinion here. Both takes have drawbacks & advantages. Let us know what you think!

@Kulgar
Copy link

Kulgar commented Jul 30, 2020

I was mostly pointing to #46 to show different examples of what can be done.
But... I mostly think that bundler should be part of the app deployment process, as each ruby/rails app may use a different version of bundler (or may even not use it), I rather see bundler as an app dependency rather than a server requirement.

So it may be best to install bundler from the remote app folder where a .ruby-version is specified. So that bundler is installed in the right version for the right ruby version used by the app.

@thbar
Copy link
Contributor Author

thbar commented Sep 12, 2020

I had the opportunity (thanks to clients needs) to practice more in that area over the last few weeks. I must say I still prefer to have bundler installed via Ansible in my cases (not by the application), but I do not use this role for that specific part anymore (I use rvm1_bundler_install: false).

My position would be at this point, based on what I know now:

  • We could keep the feature as it is (= an optional, best effort installation of the most recent version of bundler)
  • I would not bake "version selection" in it, because it would give a "false sense of security"; e.g. if the user specifies a version, but the Ruby already comes bundled with a more recent version of Bundler, the version the user specified will be installed but not actually used (as far as I understand that point)
  • I would make clearer documentation on that point, and probably share a few sample tasks that people use for more advanced scenarios (maybe in separate roles, or just snippets), to help.

The rationale behind that is after working in more depth on that topic, I believe it is hard to have a unique solution for everyone (well it could be found, with a lot more time & polish).

For instance, in my cases, here is what I'm doing:

  • Bundler version check (with regexp format verification on version, and result code checking)
  • Installation of bundler (but I do not uninstall the versions that I do not want)
  • Post-installation double check with verification of actually activated version

But other people would maybe use "default" flags, or uninstall some incorrect versions, or handle error logic differently.

Thoughts?

@thbar
Copy link
Contributor Author

thbar commented Sep 25, 2020

I have summarised my current solution in this article:

https://thibautbarrere.com/2020/09/19/managing-bundler-and-rubygems-with-ansible

@thbar
Copy link
Contributor Author

thbar commented Mar 30, 2022

I will close for now. I must add to my article that in some cases, for JRuby only, I must first remove an pre-existing bundler installation. I will share some code on demand here.

@thbar thbar closed this as completed Mar 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants