GithubHelp home page GithubHelp logo

sevagh / goat Goto Github PK

View Code? Open in Web Editor NEW
28.0 3.0 13.0 16.42 MB

AWS EBS-EC2 attach utility. UNMAINTAINED, SEE FORK ->

Home Page: https://github.com/steamhaus/goat

License: Other

Go 76.47% Makefile 3.99% Shell 0.94% HCL 18.60%
ebs-volumes ec2-instance eni attach-ebs-volumes raid aws

goat's Introduction

goat

N.B.: the active maintenance fork of this project is available at https://github.com/steamhaus/goat

Attach EBS volumes and ENIs to running EC2 instances

goat is a Go program which runs from inside the EC2 instance.

By setting your tags correctly, goat can discover and attach EBS volumes and ENIs. For EBS volumes, it can perform additional actions such as RAID (with mdadm), mkfs, and mount EBS volumes to the EC2 instance where it's running.

Install and run

Goat is a Go binary that should be able to run on any Linux instance. In the releases tab you can find a zip of the binary, and a .deb and .rpm package with systemd support. Goat needs mdadm to perform RAID (which is a dependency in the deb and rpm).

To use goat, run it during the launch process of your EC2 instance - you can systemctl enable goat@TARGET and systemctl start goat@TARGET (where TARGET is one of ebs or eni) in the EC2 user data script. Full Terraform example here.

Usage

In the most basic case, you should run goat ebs or goat eni.

Full usage:

Usage: goat [OPTIONS] ebs|eni

OPTIONS
  -debug
        Interactive debug prompts
  -logLevel string
        Log level (default "info")
  -tagPrefix string
        Prefix for GOAT related tags (default "GOAT-IN")
  -version
        Display version and exit

You can set -tagPrefix and -logLevel with environment variables (which take precedence):

  • GOAT_LOG_LEVEL
  • GOAT_TAG_PREFIX

Tags

These are the tags you need (recall that the GOAT-IN prefix is configurable):

Tag Name Description Resource type Required Effect
GOAT-IN:Prefix Logical app name EC2, EBS, ENI ✔️ attach
GOAT-IN:NodeId Node id EC2, EBS, ENI ✔️ attach
GOAT-IN:VolumeName Distinct volume name EBS
GOAT-IN:VolumeSize # of disks in vol group EBS mdadm
GOAT-IN:RaidLevel level of RAID (0 or 1) EBS mdadm
GOAT-IN:MountPath Linux path to mount vol EBS mount
GOAT-IN:FsType Linux filesystem type EBS mkfs

If non-required tags are omitted, that step is skipped. The barest case will simply attach the EBS volumes and perform no further actions.

The filesystem and fstab entries are created with the label GOAT-{VolumeName} for convenience. Running goat multiple times will result in it detecting the existing label it intended to create and not proceeding.

Aside from the mount syscall, goat shells out to mdadm, blkid, and mkfs. If the mount and RAID steps are performed, the configs will be persisted to /etc/fstab and /etc/mdadm.conf.

Check the Terraform example for example tag values.

Permissions

It's necessary for the instance to have an IAM Role with at least access to the EBS and ENI resources that it will be attaching - see here. Your roles can be even more permissive (i.e. full EC2 access) but that comes with its own risks.

Unfortunately, resource-level permissions are currently not supported for attaching network interfaces. This means that to use goat@eni, your instances must have full permissions for all ENIs.

Example EBS usecase - attaching old disks to a new instance

The specific use-case that goat was developed to solve is the following. Say you have 3 instances with their own respective disks, and you receive a termination notice for instance 1. I want the goat workflow to be:

  1. Terminate instance 1
  2. Create a new instance with the same GOAT tags (to indicate to goat that it's the logical equivalent as the machine it is replacing)
    1. No need to modify or manipulate the EBS volumes or their tags
  3. On boot, everything works magically

After goat ran on the first fresh run, the EBS volumes got the correct filesystems, labels, and in the case of RAID, mdadm metadata on them.

The event flow on a re-created instance is:

  1. Get EC2 metadata on the running instance, create an EC2 client, and search EBS volumes
  2. Attach the volumes it needs based on their tags
  3. Discover that /dev/disk/by-label already contains the correct disks
    1. From mdadm magic, after the EBS attachment the RAID array is already detected correctly
  4. Proceed to perform the fstab and mount phases - skip mdadm, mkfs

CAVEAT: the mdadm metadata will have the hostname of the previous EC2 instance:

[centos@ip-172-31-29-69 ~]$ sudo mdadm --detail --scan --verbose
ARRAY /dev/md127 level=raid0 num-devices=3 metadata=1.2 name="ip-172-31-25-105:'GOAT-data'" UUID=2d08b310:fd13bd21:bc2417a4:56a1ec57
   devices=/dev/xvdb,/dev/xvdc,/dev/xvdd
[centos@ip-172-31-29-69 ~]$

To avoid this, define a good/persistent hostname for the EC2 instance, that you will then re-apply to any instance taking ownership of the previous instance's disks.

ENI notes

As mentioned, the only action goat will do for ENIs is attaching them. You can try to use ec2-net-utils, a tool available on Amazon Linux AMIs, or this port to CentOS/systemd, to configure an ENI after goat attaches it.

ENI attachments take a parameter called DeviceIndex. Goat isn't smart, and always starts from DeviceIndex 1. This means that your EC2 instance should have no attached ENIs to use goat. If it does, they should be the ones that goat was going to attach anyway, not external ENIs that have no goat tags.

Build and develop

The deb, rpm, and zip are generated from a multi-stage Dockerfile.build. Invoke it with make docker-build. If you have docker locally, you can use the following command in order to quickly get a development env ready: make dev-env.

goat's People

Contributors

bilco105 avatar macropin avatar mvisonneau avatar sevagh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

goat's Issues

Pick a new name

This might sound pedantic, but I hate the name of this project. I can't think of what else I should call it.

goat comes from Go-Attach, since it's an EBS attach util written in Go

In the past I've named this:

  • kraken (picture an octopus holding EBS volumes and EC2 instances in its tentacles?)
  • ebs-wizard (self-explanatory)

Ideas:

  • disk_buddy
  • ebs_buddy
  • ebsutil
  • ??

Feedback

  • Volid/mount path = string, combine? id is misleading, nodeid supersedes uniqueness - document this, change to volumename?
  • KRAKEN prefix on all tags

Mount + mkfs

Need to run these commands.

  • Mount (take mountpoint as parameter using docopt)
  • Mkfs only if FS doesn't exist?

New tags

Per ebs vol:

  • Prefix
  • Vol Id
  • Node Id
  • Disk Id
  • Raid Level
  • Volume Size

"panic: runtime error: index out of range" when Goat attempts to mounts a volume

First of all @sevagh thanks for this nice little tool of yours!

After hundreds of successful attachments, Goat threw this error today:

systemd[1]: Starting GOAT: EC2-EBS attach utility...
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="Running goat for ebs"
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="WELCOME TO GOAT"
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="1: COLLECTING EC2 INFO"
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="Establishing metadata client"
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="Retrieved metadata successfully" instance_id=i-0772edcdbced03ed7
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="Using metadata to initialize EC2 SDK client" az=eu-central-1b instance_id=i-0772edcdbced03ed7 region=eu-cent>
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="2: COLLECTING EBS INFO"
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="Searching for EBS volumes"
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="Classifying EBS volumes based on tags"
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="3: ATTACHING EBS VOLS"
attach-ebs[866]: time="2019-02-22T10:56:37Z" level=info msg="4: MOUNTING ATTACHED VOLS"
attach-ebs[866]: panic: runtime error: index out of range
attach-ebs[866]: goroutine 1 [running]:
attach-ebs[866]: main.prepAndMountDrives(0xc00038c530, 0xd, 0xab2650, 0x0, 0x0)
attach-ebs[866]:         /go/src/github.com/sevagh/goat/ebs.go:43 +0x137a
attach-ebs[866]: main.GoatEbs(0x7d2800, 0x7ce218, 0x7)
attach-ebs[866]:         /go/src/github.com/sevagh/goat/ebs.go:36 +0x256
attach-ebs[866]: main.main()
attach-ebs[866]:         /go/src/github.com/sevagh/goat/main.go:66 +0x4c3

Systemd service in rpm-package fails to start goat

The goat@ service is trying to start goat as:

ExecStart=/usr/bin/goat "%i" --log-level=info

This fails with the following error:

Nov 07 11:39:12 ip-xxx-xxx-xxx-xxx.eu-west-2.compute.internal systemd[1]: Starting GOAT: EC2-ebs attach utility...
Nov 07 11:39:12 ip-xxx-xxx-xxx-xxx.eu-west-2.compute.internal goat[1101]: time="2018-11-07T11:39:12Z" level=fatal msg="Usage: goat [OPTIONS] ebs|eni"
Nov 07 11:39:12 ip-xxx-xxx-xxx-xxx.eu-west-2.compute.internal systemd[1]: [email protected]: main process exited, code=exited, status=1/FAILURE
Nov 07 11:39:12 ip-xxx-xxx-xxx-xxx.eu-west-2.compute.internal systemd[1]: Failed to start GOAT: EC2-ebs attach utility.
Nov 07 11:39:13 ip-xxx-xxx-xxx-xxx.eu-west-2.compute.internal systemd[1]: Unit [email protected] entered failed state.
Nov 07 11:39:13 ip-xxx-xxx-xxx-xxx.eu-west-2.compute.internal systemd[1]: [email protected] failed.

Same if run from command line:

[root@nfs_server-i0efbbef78829bc75f centos]# /usr/bin/goat ebs --log-level=info
FATA[0000] Usage: goat [OPTIONS] ebs|eni 

Note that the --log-level parameter used in the service also seems to have changed:

[root@nfs_server-i0efbbef78829bc75f centos]# /usr/bin/goat --log-level=info ebs
flag provided but not defined: -log-level
Usage of /usr/bin/goat:
  -debug
    	Interactive debug prompts
  -logLevel string
    	Log level (default "info")
  -tagPrefix string
    	Prefix for GOAT related tags (default "GOAT-IN")
  -version

Improvements

  • Docker build script (instead of downloading fpm etc. which outputs binaries)
  • Replace calls to execute.Command with real syscalls (e.g. mount)
  • dep to vgo
  • Rename goat - I hate the name

Panic on EBS dry run after successful attach

[centos@ip-10-0-1-226 ~]$ goat ebs --dry
INFO[0000] Running goat for EBS
INFO[0000] WELCOME TO GOAT
INFO[0000] 1: COLLECTING EC2 INFO
INFO[0000] Establishing metadata client
INFO[0000] Retrieved metadata successfully               instance_id=i-0da5f72185babbf66
INFO[0000] Using metadata to initialize EC2 SDK client   az=us-east-1a instance_id=i-0da5f72185babbf66 region=us-east-1
INFO[0000] 2: COLLECTING EBS INFO
INFO[0000] Searching for EBS volumes
INFO[0000] Classifying EBS volumes based on tags
INFO[0000] 3: ATTACHING EBS VOLS
INFO[0000] 4: MOUNTING ATTACHED VOLS
panic: runtime error: index out of range

goroutine 1 [running]:
github.com/sevagh/goat/commands/ebs.prepAndMountDrives(0xc420176980, 0x4, 0x971680, 0x0, 0x0, 0xc4201a2e01)
        /home/sevagh/go/src/github.com/sevagh/goat/commands/ebs/ebs.go:40 +0x133a
github.com/sevagh/goat/commands/ebs.GoatEbs(0x7a0001)
        /home/sevagh/go/src/github.com/sevagh/goat/commands/ebs/ebs.go:33 +0x2d6
main.main()
        /home/sevagh/go/src/github.com/sevagh/goat/main.go:48 +0x3a2
[centos@ip-10-0-1-226 ~]$

Omit certain parts of the startup

For now goat is rigid. You must supply all the tags.

It would be nice if based on which tags you supply, goat does what it can.

  • Only do mkfs if filesystem tag is present
  • Only do mount if mountpoint tag is present
    etc.

This way, you can use goat purely for attaching volumes, or for doing the full configuration. @nokernel

panic: runtime error: index out of range

Hi @sevagh

First of all, really appreciate the work you've put into this tool - we use it a lot.

Recently though, I've randomly started encountering a problem that I've not seen before, specifically this error:

INFO[0000] Running goat for ebs
INFO[0000] WELCOME TO GOAT
INFO[0000] 1: COLLECTING EC2 INFO
INFO[0000] Establishing metadata client
INFO[0000] Retrieved metadata successfully               instance_id=i-0a403f852293bd8e3
INFO[0000] Using metadata to initialize EC2 SDK client   az=eu-west-1a instance_id=i-0a403f852293bd8e3 region=eu-west-1
INFO[0000] 2: COLLECTING EBS INFO
INFO[0000] Searching for EBS volumes
INFO[0000] Classifying EBS volumes based on tags
INFO[0000] 3: ATTACHING EBS VOLS
INFO[0000] 4: MOUNTING ATTACHED VOLS
panic: runtime error: index out of range

goroutine 1 [running]:
main.prepAndMountDrives(0xc0004388e0, 0x5, 0xab95d0, 0x0, 0x0)
	/home/shanssian/go/src/github.com/sevagh/goat/ebs.go:42 +0x1350
main.GoatEbs(0x7d1b00, 0x7cd503, 0x7)
	/home/shanssian/go/src/github.com/sevagh/goat/ebs.go:35 +0x256
main.main()
	/home/shanssian/go/src/github.com/sevagh/goat/main.go:66 +0x4c

The EBS volumes attach fine, however, they fail to mount. This looked the same as #47 initially, however, I've upgraded to 1.0.2 and the error persists.

The tagging all appears to be correct, GOAT-IN:FsType, GOAT-IN:MountPath, GOAT-IN:NodeId, GOAT-IN:Prefix, & GOAT-IN:VolumeName are all set, and I've verified the IAM permissionns are correct.

Any ideas?

Mdadm --update=host

Find a way to update the hostname when the mdadm devices re-attach to a new machine. Or perhaps always run update hostname when kraken runs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.