RFC: Re-thinking Forklift's Workflow to Expand Use Cases

Background

Forklift started as a way to easily get production testing environments and development configurations setup for developers and to some degree users. The target was using Vagrant, a well known developer platform, and single machine setups. Over time the project expanded to some limited multi-host topologies but never anything truly past Vagrant with Libvirt. This has served us well to this point.

Problems and Limitations of Current Design

  • Vagrant focused
  • Good at single node, bad at multinode
  • Starts with Vagrant but meat is in the Ansible

Proposal: Bring Your Own Inventory (BYOI)

With the influx of users and use cases I think the time has come to expand Forklift by modifying the workflow to allow for myriad use cases. The proposal is to modify the workflow of Forklift to a bring your own inventory model with some limited support for “easy” mode via Vagrant.

The way Forklift works today assumes an all in one solution of provisioning a machine, then configuring the machine and providing facilities to destroy that machine. This proposal attempts to split this into:

  1. Provisioning capabilities that produce an Ansible inventory somehow
  2. Playbooks and roles that are the bulk of the configuration
Provisioning

The focus on provisioning will no longer be the forefront of Forklift’s intent but it would still provide the current baseline functionality and perhaps other tools in the future. In the case of Vagrant, the project would shift to providing the ability to spin up a Vagrant box, thereby producing an Ansible inventory through the dynamic Vagrant inventory. The user would then be responsible for configuring that box with one of the available playbooks. This would expand the one command today into two:

vagrant up centos7
ansible-playbook -l centos7 playbooks/devel.yml

Another example would be someone who acquires a machine through beaker. The user would provision that beaker machine through some-tool and write out an inventory (or using a dynamic inventory):

acquire-beaker-machine

echo "[katello]\ntest.example.com" > inventories/my_beaker
ansible-playbook -l katello playbooks/katello.yml
Configuration

The configuration of machines would be a continued focus on self-contained and focused roles with a general set of playbooks combining those roles for use. Facilities would be provided to allow users to configure their own setups in three ways:

  1. User defined playbooks
  2. Inventory configurations
  3. Common and user supplied vars files

User defined playbooks would expand on the existing user playbooks to allow users to define playbooks locally and not risk committing them to git. Playbooks that can be generalized for a broader audience would be encouraged to be committed to Forklift.

Inventory configurations would involve documenting how to create inventories that also define the variables one needs to customize a deployment with. This might be something akin to configuring a development environment with your own machine:

cat  > inventories/devel_inventory <<EOF
[devel]
test-dev.example.com

[devel:vars]
devel_github_username=ehelms
katello_repositories_environment=staging
EOF

Common and user supported vars files would be allowing playbooks to remain general (e.g. katello.yml) and providing common configurations through vars files that can be used to customize the playbooks. This would also be at the user level for common configurations a user wants locally. An example might be wanting to have production nightly and staging nightly installations:

$ cat vars/nightly_staging.yml
---
katello_repositories_environment: staging
foreman_repositories_environment: staging

$ ansible-playbook -l centos7 playbooks/katello.yml -e @vars/nightly_staging.yml

Looking Ahead

Looking ahead, this shift will allow us to provide a wide range of users and compute resources to be used for environments. Advanced cases such as multi-host topologies can be more readily brought to bear by adding tooling to spin that up and generate an inventory or having a user bring their own. For example, a tool like Linchpin or Terraform could be used to spin up multi-host or even our own custom Vagrant forklift role. For example, say we have one of those spin up a multi-host setup and produce an inventory like:

[server]
server.example.com

[proxy]
proxy.example.com

[clients]
client-el7.example.com
client-deb.example.com

We can then have a playbook that is designed to target host groups server, proxy and clients to configure, orchestrate and install a server, proxy and set of clients for testing. A user could do this individually as well, e.g.

ansible-playbook -l server playbooks/katello.yml
ansible-playbook -l proxy playbooks/proxy.yml
ansible-playbook -l client-deb.example.com playbooks/puppet_client.yml
ansible-playbook -l client-ell7.example.com playbooks/client.yml

As we get into a more container oriented world, this focus on the roles and playbooks opens up the possibility to simply shift the focus of the “machine” to that of a container and still apply the same set of core logic built up in the roles and playbooks.

Feedback

Obviously, I am looking for feedback on this proposal as a whole but I am also looking for feedback on user and developer experiences. Things like:

  1. Does this proposal help meet your needs?
  2. Are there changes in Forklift you’d like to see that this does not help with?
3 Likes

As a fairly non-technical user I truly appreciate the setup that forklift
allows. For example, using sshfs, setting up network, memory/cpu/disk.
Having the ability to specify custom installer options and even individual
PRs to test is a very common use case for me. As long as these features
remain, I don’t mind running one or more playbooks directly.

Hello,

I like this direction very much! I plan to use the best provisioning tool
[1] out there to get few machines and then use forklift playbooks through
foreman_ansible. The only part that I’ll need to handle manually is syncing
playbooks to job templates. I hope at some point foreman_templates will
help with that. The only potential problem I see is that some playbooks now
rely on host being in devel group. It would be great if all that addresses
allinone setups would use hosts: all. I see katello.yml already does that.

[1] https://theforeman.org

Thanks!

Is this a required step to allow doing the rest? I find it convenient being able to do just vagrant up foreman-nighlty

Overall, +1 as this will open up opportunities to use forklift on different environments and servers with more resources.

I do agree with others that it is very nice to run one command and have a working environment, so anything to keep that usability will be appreciated

Wouldn’t you have to do an ssh-copy-id before running the playbook?

I also would add that these changes should have some “Explain like I’m 5” documentation with them, this is a big change in everyone’s workflow and will be much easier with good documentation.

I totally agree. Although I was able to get the katello.yaml playbook (aka nightly) to run fine. I ran into a lot of issues with the devel one.

It seems to assume there is a username “vagrant” and uses things like “su vagrant” and has hardcoded paths like "/home/vagrant/somedir/’

+1 from me! Any separation of inventory from provisioning is a big win.

Yes, thank you. As a Linux user, I never was a Vagrant user. I use Beaker for remote boxes and virt-builder / virt-install (libvirt) for local boxes and I am really happy with it. Having Forklift deeply integrated with Vagrant, I was staying out of it on purpose, because it was a pain for me to find out how to call configuration bits without knowledge of how Vagrant actually works. We had some old documentation about it, never worked for me.

So from me this is huge plus. I am also all for cleaning up the git repo. Today this is what I see in the root folder: Vagrant, shell/runcible, bats, containers and ansible. I’d be very happy if we’d pick one tool for configuration and having one git repo or directory for that. It’s fine having more things in one git repo, let’s just separate this into directories so it’s more logical to navigate and use:

build/
 doc/
 bin/
 Vagrantfile
 beaker-example.cfg
 build-vagrant.sh
 build-beaker.sh
 build-libvirt.sh
configure/
 doc/
 roles/
 blah/
 configure.sh
pack/
 containers
test/
 bats/
 runcible/
 run-suite.sh

I always liked the vagrant workflow. As a heavy user of vagrant [up|provision|ssh] it provided me with a simple interface. Throwing that away would be a big step backwards to me.

That said, I do welcome changes to make it easier to use with other systems and improve the multi host deployments.

:-1: to making ansible-playbook the primary interface. To me linchpin looks like a much more complete alternative. It has multiple providers that appear to cover the alternatives we currently use (libvirt, openstack) and those desired (beaker) although it is missing an easy way to get a console. Also not sure about the pure bare metal case.

Recently I used forklift playbooks with beaker-boxes inventory managed by Ivan’s script [1] and it was working quite well.

Form that experience it would seem logical to move the playbooks and perhaps the inventory configurations from forklift into separate repo and make them independent on vagrant. Then forklift (from users perspective) could remain the same tool around vagrant using the playbooks and configs. Similar tooling could be built around other provisioning tools following the respective workflow differences.

Does it make sense and does it comply with the proposal?

[1] https://gitlab.sat.lab.tlv.redhat.com/inecas/devtools/tree/master/beaker_ansible

Posting internal URLs is not very useful in the upstream context.

1 Like

I actually appreciate ansible-playbook as the primary interface. It does support both libvirt and libvirt network management I am mostly interested in. In provisioning, I need to have my own network(s) with DHCP disabled, so this allows me to do this. Also list of supported clouds is rather long, it is much longer than linchpin. While linchpin would do the job for me, I do not want to learn another tool for such a simple task of creating one to three VMs.

As Martin said, whatever we do, let’s please make sure that Ansible bits live in their own git repo or directory to ensure other workflows can be integrated easily.

I think that’s just creating a lot of overhead. They live in their own directory already and are usable, even without vagrant. There is coupling between the two. What does splitting them off in their own repository give us?

1 Like

I’m not familiar with Forklift internals so what I suggested may be technically over-complicated.
But I expect the split could help users to easier distinguish which Forklift features are vagrant independent and thus reusable with other provisioning tools. It could also push contributors to design their additions vagrant independent and open to more users. With more vagrant independent code it would be easier to create ‘forklift runners’ e.g. forklift-vagrant, forklift-beaker or forklift-docker using the strengths of the other tools combined with forklift.

1 Like

I think the Vagrant is very useful, especially for quick tests and devel boxes and therefore the existing functionality should remain as previously stated by others.

Definitely +1 for the effort to make forklift more flexible so that it can be used in different environments