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

inertia deploy [REMOTE] (up, down, status, reset) and authentication #30

Merged
merged 35 commits into from Jan 7, 2018

Conversation

@bobheadxi
Copy link
Member

bobheadxi commented Dec 26, 2017

⌛️ Status: ready for review

🎟 Ticket(s): Closes #27, closes #32, closes #33, closes #38


👷 Changes

  • inertia deploy [REMOTE] down:

    • Checks if inertia is only active container, errors if it is
    • Kills all other containers
  • inertia deploy [REMOTE] up:

    • If no git repository on server, clone using the repo URL in the post request
    • deploy() project
  • inertia deploy [REMOTE] status:

    • Returns a list of active non-daemon containers
  • inertia deploy [REMOTE] reset:

    • kills containers and deletes contents of project folder
  • authentication using github token (#39)

  • Push events to Daemon:

    • If no git repository on server, clone using the repo URL in the event
    • deploy() project
  • deploy():

    • Pulls from working tree, fresh clone if that fails (go-git doesn't support force pull)
    • Run docker-compose using similar docker-in-docker workaround to daemon-up
  • A bunch of minor typo fixes, refactored some shared helper functions to util.go

Todo

  • Clone on up
  • Error codes and better responses
  • docker-compose
  • Authorization 🤔 (see #38 )
  • Tests (minimal 😢 )

🔦 Testing Instructions

inertia init
inertia remote add local 0.0.0.0 -u robertlin
docker build -t inertia .

This next thing basically bootstraps without pulling master inertia:

sudo docker run -p 8081:8081 -e HOME -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/app/host -e SSH_KNOWN_HOSTS='/app/host/.ssh/known_hosts' -e HOME=$HOME --name="inertia-daemon" inertia

If needed, do docker rm -f $(docker ps -a -q)
Now you can:

inertia remote status local
inertia deploy local up
inertia deploy local down
inertia deploy local status

For example, with Sleuth:

Roberts-MacBook-Pro:inertia robertlin$ inertia deploy local up
(Status code 201) Project up

Roberts-MacBook-Pro:inertia robertlin$ inertia deploy local status
(Status code 200) 7b7be0b7097a26169e17037f4220fd0ce039bde1 refs/heads/master
Active containers:
project_frontend (/project_frontend_1)
project_web (/project_web_1)
project_solr (/project_solr_1)
postgres (/project_db_1)

Roberts-MacBook-Pro:inertia robertlin$ inertia deploy local down
(Status code 200) Project down

Roberts-MacBook-Pro:inertia robertlin$ inertia deploy local down
(Status code 412) No containers are currently active

Roberts-MacBook-Pro:inertia robertlin$ inertia deploy local status
(Status code 200) 7b7be0b7097a26169e17037f4220fd0ce039bde1 refs/heads/master
There are currently no active containers.
@bobheadxi bobheadxi added the pr: wip label Dec 26, 2017
err = CheckForGit()
if err != nil {
// Clone project
remoteURL := "" // TODO

This comment has been minimized.

Copy link
@bobheadxi

bobheadxi Dec 26, 2017

Author Member

Is this in config somewhere?

This comment has been minimized.

Copy link
@chadlagore

chadlagore Dec 26, 2017

Contributor

Try using getRepo and pull out the repo.Remotes() list. The information you want should be in there.

This comment has been minimized.

Copy link
@bobheadxi

bobheadxi Dec 27, 2017

Author Member

I think this particular case is for when CheckForGit() fails and I need to do a clone - wouldn't that mean there's either no repository at all, or that the repository has no remotes to do repo.Remotes() on?

This comment has been minimized.

Copy link
@chadlagore

chadlagore Dec 27, 2017

Contributor

Why don't we ship that info in the /up body? 😬

@bobheadxi bobheadxi requested a review from chadlagore Dec 26, 2017
// downHandler tries to bring the project down.
// deploy does git pull, docker-compose build, docker-compose up
func deploy(repo *git.Repository) error {
cfg, err := GetProjectConfigFromDisk()

This comment has been minimized.

Copy link
@chadlagore

chadlagore Dec 26, 2017

Contributor

This seems to be booting up the daemon? If this function is called, it's the daemon that called it 😂 Maybe this is just WIP.

}

w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)

This comment has been minimized.

Copy link
@chadlagore

chadlagore Dec 26, 2017

Contributor

201 - Created might be a nice return code here.

This comment has been minimized.

Copy link
@bobheadxi

bobheadxi Dec 27, 2017

Author Member

This is for shut down 😛 changed up to return created

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 1, 2018

Contributor

Reviews on iPhones 🙈👍

http.Error(w, err.Error(), 501)
}
if len(containers) == 1 {
http.Error(w, "No Docker containers are currently active", 501)

This comment has been minimized.

Copy link
@chadlagore

chadlagore Dec 26, 2017

Contributor

Nice! Maybe a 412 - Precondition Failed works here.

}

// Take project offline
daemonCmd, err := Asset("cmd/bootstrap/project-down.sh")

This comment has been minimized.

Copy link
@chadlagore

chadlagore Dec 26, 2017

Contributor

Don't know if it's necessary to take the daemon down - if we do, they have to re-bootstrap the HTTP communication to continue using the server.

This comment has been minimized.

Copy link
@bobheadxi

bobheadxi Dec 27, 2017

Author Member

The script (project-down) looks like this:

DAEMON_NAME=inertia-daemon
docker rm $(docker ps -a -q | grep -v "$DAEMON_NAME")

From what I understand this should leave the daemon alone right?

cmd/init.go Outdated
@@ -146,7 +146,7 @@ func CheckForGit() error {
return errors.New("this does not appear to be a git repository")
}

repo, err := git.NewFilesystemRepository(gitFolder)
repo, err := git.PlainOpen(gitFolder)

This comment has been minimized.

Copy link
@chadlagore

chadlagore Dec 26, 2017

Contributor

👍 Could not make this function work - silly git package.

@@ -0,0 +1,4 @@
# Script for taking down all Docker containers except the Inertia daemon

This comment has been minimized.

Copy link
@chadlagore

chadlagore Dec 27, 2017

Contributor

Any reason you wouldn't use the golang docker client to handle this?

Copy link
Contributor

chadlagore left a comment

Couple drive-by comments. Haven’t read the whole thing yet. But looking great! 🤩

I’d really like to avoid using bash to bring up the project! The bash work should be done once the server is bootstrapped. Is there a reason we can’t play with containers only using the go docker client?

sudo docker run -d \
-p "$PORT":8081 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 1, 2018

Contributor

As far as I can tell, there’s no guarantee this binary (installed for the host) works inside of the container (the container likely runs a different OS).

This comment has been minimized.

Copy link
@bobheadxi

bobheadxi Jan 1, 2018

Author Member

Haven’t had the opportunity to test that but I don’t see any indication that the container runs a different OS to the host with the way we’re starting the daemon up here, or maybe I jut don’t understand docker 😅 I’ll look into it

This comment has been minimized.

Copy link
@bobheadxi

bobheadxi Jan 1, 2018

Author Member

Looks like the container should be the same as the host:

Docker originally used LinuX Containers (LXC), but later switched to runC (formerly known as libcontainer), which runs in the same operating system as its host. This allows it to share a lot of the host operating system resources.

source

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 1, 2018

Contributor

The first comment to that thread:

Ken, in some places you conflate the OS with the kernel. All containers on a host run under the same kernel, but the rest of the OS files can be unique per container.

One host kernel is orchestrating our container processes here. But each container we run via the host may use a different OS. Here is the example in inertia's case (say we've just allocated a gcloud vps with ubuntu installed on it):

  1. We boostrap the VPS (installing docker via this).
  2. It figures out what operating system its running on and installs docker for that OS.
  3. You mount that binary into the daemon (running Alpine Linux).

Theres no guarantee that the binary is executable on Alpine Linux! 🙈

Heres a working example (pretending the host is running macOS 😂):

~/git/tmp  master ✔
▶ cp `which docker` .
~/git/tmp  master ✗                                                                                                                                                              
▶ docker run -it -v `pwd`:/home alpine
/ $ ls
bin    dev    etc    home   lib    media  mnt    proc   root   run    sbin   srv    sys    tmp    usr    var
/ $ cd home
/home $ ls
docker
/home $ ./docker
./docker: line 1: ������: not found
./docker: line 2: @��__gosymtab__TEXT������__gopclntab__TEXT���5�A���__cstring__TEXT�t�l�t�__const__TEXTP: not found
./docker: line 2: ��P: not found
./docker: line 2: �__unwind_info__TEXT
                                      ���
                                         ��__eh_frame__TEXT��-��h__DATA��: not found
./docker: line 2: ���,: not found
./docker: line 2: �H__PAGEZER__TEXT����
                                       __text__TEXT#n�#�__stubs__TEXTn��n�__stub_helper__TEXTD�D��__rodata__TEXT�__typelink__TEXT: not found
./docker: line 3: ���: not found
./docker: line 4: syntax error: unexpected word (expecting ")")
/home $

This comment has been minimized.

Copy link
@bobheadxi

bobheadxi Jan 2, 2018

Author Member

Hang on, I've been mounting my local (macOS) installation into the daemon, should that not be working?

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 2, 2018

Contributor

You don't appear to be using the docker binary anywhere in this PR. That's probably why it works.

The go docker library does everything you need, it never has to access a docker binary in a file somewhere, all it needs is to look at /var/run/docker.sock and find a socket there 😄 - which we provide with -v /var/run/docker.sock:/var/run/docker.sock.

I think we can just remove the -v /usr/bin/docker:/usr/bin/docker here. It's not doing anything and it would break if we tried to actually use it somewhere.

This comment has been minimized.

Copy link
@bobheadxi

bobheadxi Jan 3, 2018

Author Member

Oh yeah you're right, was using the docker binary for back when I was still using the shell script - not needed anymore

Speaking of which running that project-up.sh script was working before and I think that used the mounted docker binary?

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 3, 2018

Contributor

Not sure! It may work sporadically, if we happen to use a host compatible with Alpine - but in general we can't assume that a binary built from source in one OS will work inside other OS.

repo := event.GetRepo()
log.Println("Received PushEvent")
log.Println(fmt.Sprintf("Repository Name: %s", *repo.Name))
log.Println(fmt.Sprintf("Repository Git URL: %s", *repo.GitURL))
log.Println(fmt.Sprintf("Ref: %s", event.GetRef()))

// Clone repository if not available
err := checkForGit(projectDirectory)

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 1, 2018

Contributor

💫

}

w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 1, 2018

Contributor

Reviews on iPhones 🙈👍

@bobheadxi

This comment has been minimized.

Copy link
Member Author

bobheadxi commented Jan 1, 2018

Thanks @chadlagore !

The main problem is docker-compose has to be installed separately from Docker, and the Go Docker client doesn't offer docker-compose actions. Hence the bash hack, which should install a docker-compose image and run it as a container, allowing it to be platform agnostic:

docker run -d \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v $HOME:/build \
    -w="/build/project" \
    docker/compose:1.18.0 up --build

Note I'm mounting all of $HOME here instead of just the project directory because of one particular pesky project (cough sleuth cough 😅 ) that requires "neighbouring" repositories.

Tried mounting docker-compose from host but it seems on MacOS at least it doesn't work, though from what I've read it /should/ work on Linux... just need to add this when bringing the daemon up:

    -v /usr/local/bin/docker-compose:/usr/local/bin/docker-compose

There is a docker client for docker-compose in Go that I wanted to try but believe it or not, it currently has a dependency clash with the normal go docker client resulting from a case change (capital S vs lowercase s in something) 😠 I didn’t look too much into it because I thought there would still be the issue about the lack of docker-compose installation

@bobheadxi

This comment has been minimized.

Copy link
Member Author

bobheadxi commented Jan 1, 2018

@chadlagore got rid of the project-up script

bobheadxi added 2 commits Jan 4, 2018
Chad/#38 authorization
return err
}

println(token)

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 4, 2018

Contributor

This is my fault - 🔫

@bobheadxi bobheadxi changed the title inertia deploy [REMOTE] up, down, status inertia deploy [REMOTE] (up, down, status, reset) and authentication Jan 4, 2018
@bobheadxi

This comment has been minimized.

Copy link
Member Author

bobheadxi commented Jan 4, 2018

Forgot in the commit message but 40ba979 also compares the remote URL of requests (e.g. from up or from webhook events) and fails if they dont match the git repository on daemon

@bobheadxi bobheadxi requested a review from chadlagore Jan 6, 2018
Hotfix the config writer; unexport initialization functions
@bobheadxi

This comment has been minimized.

Copy link
Member Author

bobheadxi commented Jan 7, 2018

Thanks @chadlagore !

inertia robertlin$ go test ./cmd -cover
ok      github.com/ubclaunchpad/inertia/cmd     0.017s  coverage: 19.2% of statements
sudo chmod +x $DOCKER_COMPOSE_DEST

# Try using.
docker-compose --version

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 7, 2018

Contributor

👍

@bobheadxi

This comment has been minimized.

Copy link
Member Author

bobheadxi commented Jan 7, 2018

Note some of the tooltip updates in 718645c might be for #48 😅

@@ -18,5 +18,6 @@ else
ssh-keygen -f $ID_DESTINATION -t rsa -N ''
fi

ssh-keyscan github.com >> ~/.ssh/known_hosts

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 7, 2018

Contributor

😮

println("It is recommended that you DO NOT commit this folder in source")
println("control since it will be used to store sensitive information.")
println("\nYou can now use 'inertia remote add' to connect your remote")
println("VPS instance.")

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 7, 2018

Contributor

🎉


assert.Equal(t, sshURL, getSSHRemoteURL(httpsURL))
assert.Equal(t, sshURL, getSSHRemoteURL(sshURL))
}

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 7, 2018

Contributor

👏 for regression tests!

# Generate a daemon token using CLI.
sudo docker run --rm \
-v $HOME:/app/host \
-e SSH_KNOWN_HOSTS=$SSH_KNOWN_HOSTS \
-e SSH_KNOWN_HOSTS='/app/host/.ssh/known_hosts' \

This comment has been minimized.

Copy link
@chadlagore

chadlagore Jan 7, 2018

Contributor

🤦‍♂️

Copy link
Contributor

chadlagore left a comment

+1 best code 🏅

Deployed my project:

~/git/inertia-deploy-test  master ✗                                                                                                                                           6m ◒
▶ ./inertia deploy gcloud up
(Status code 201) Project up

~/git/inertia-deploy-test  master ✗                                                                                                                                           6m ◒
▶ ./inertia deploy gcloud status
(Status code 200) git@github.com:chadlagore/inertia-deploy-test.git
b3bc12a2f816f727be550dd05759144a0abf0ffa refs/heads/master
Active containers:
python (/project_webdev_1)

Looks totally awesome:

image

For the record, we keep getting this error:

▶ ./inertia deploy gcloud up
(Status code 500) Unknown response from daemon: Error response from daemon: Conflict. The container name "/docker-compose" is already in use by container "9e223216098ede70e100ea8de80e472943aa6e7afcde91c746790951d679e22f". You have to remove (or rename) that container to be able to reuse that name.

And we're not in love with this chunk:

   // Check if build failed abruptly
    time.Sleep(2 * time.Second)
    _, err = getActiveContainers(cli)
    if err != nil {
        err := killActiveContainers(cli)
        return errors.New("Docker-compose failed: " + err.Error())
    }

And we know it breaks when the project expects its images to have docker-compose canonical names.

But this thing works for straightforward docker-compose projects 👍

@bobheadxi bobheadxi merged commit 9bc08c4 into master Jan 7, 2018
@bobheadxi bobheadxi deleted the rob/#27-serverside-daemon branch Jan 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.