Git post-receive hook Deployment server-side code immediately reboot effective

Source: Internet
Author: User
Tags lua readline sha1 stdin

This article presents my approach with the example of deploying a Openresty-based server-side program.

Technical information

Os:centos 6.3
Server Software: Openresty
Development language: Lua

noun explanation

Servers: server hardware + OS
Server-side programs: Openresty Processes in servers
Server-side code: The Lua source program deployed in Openresty

One, git service end hook type

Pre-receive
Executes first when the client pushes, and can be used to reject the push of the client.
Update
Similar to pre-receive, but will be performed once per branch.
Post-receive
Executed after the client push completes.

According to my needs, I choose post-receive hook to do this thing. Because I don't want to reject the push of the client (so programmers may not know what to do). The push always succeeds, but the command is unsuccessful. When the command is unsuccessful, the client only needs to push a correct command again.

The configuration of the command is detailed later.

two, git repostories

I set up 2 git warehouses to complete this task. The advantage of partitioning into 2 warehouses is that the server-side code is updated and the server-side program is not disturbed.

On the development server, I can shut down Openresty's Lua file cache. This will take effect immediately after the service-side code is updated, without restarting the server-side program.

And if the server-side program is wrong, just update its status (Reopen/reload, etc.), and do not need to update the server-side code.
Server.git

This warehouse holds the server-side logic code, and the client's folder structure is as follows:

Server
├──readme.md
└──src
└──main.lua

Each time the code is submitted, a specific command can be included in the submission, and when the commit is pushed, the GIT server hook works and updates the submitted code to the appropriate location.

If there are no specific commands in the submission, then this is an ordinary push.

In this case, the hook does what it does to update all the code in the Src/folder to the server program.
Serverctrl.git

This warehouse is empty and will never have content. By including specific commands in the submission information, the GIT server hook will perform a given operation on our service-side program.

third, use the hook to restart the server program

Process Control of Openresty

Use the-s parameter provided by Nginx to control the server-side program:

nginx-s [Stop|quit|reopen|reload]-p/path/to

Without the-s parameter is the start function:

Nginx-p/path/to

Command

Serverctrl is an empty project and it is impossible to have any content. Therefore, I require the submission of information directly to write operation commands.

To control server-side program restart, you only need to do this commit and push:

git commit--allow-empty-m ' reopen ' && git push Origin Zrong

implementation of [Start|stop|quit|reload] is also the same reason.

Specific code

The following code shows the contents of the post-receive hooks in the Serverctrl project. Hooks can be written in any scripting language that the operating system can recognize. I'm using Python (2.7 and 3.4 generic) here.

The following code and comments are very clear, I say a few points to note.

In the Callnginx method, the stderr parameter of the Subprocess.check_output method needs to be set to STDOUT. Because if you perform nginx error, the error message is written to the STDERR by default, and if you do not make such a modification, the input information returned when the error occurs is empty.
You need to set the Nginx program as well as the '/opt/openresty/nginx ' entire folder and owner of the file below it as a git user, otherwise the hook will not have permission to start the nginx process.
The owner of the Post-receive Hook itself will also be set up as a git user and given execution privileges.
If there is already a nginx process running with the-p parameter (prefix), note that it ends first. Otherwise, the GIT user may not have permission to close the process.

-

#!/usr/bin/env python
Import Sys
Import OS
Import subprocess

# prefix configuration path
Openresty = '/opt/openresty/nginx '
# Execute File path
Nginx = openresty + '/sbin/nginx '
# signals that can be identified
Signals = (' Start ', ' Stop ', ' Quit ', ' reopen ', ' reload ')
# Supported branches (user)
Branches = (' Master ', ' Allen ', ' Zrong ', ' Xiefei ', ' ZM ')

def Getgitargs (*args):
If args:
return [' Git ', '--bare ', '--git-dir ', OS.GETCWD ()] + list (args)
return []

def callgit (*args):
return Subprocess.check_output ([' Env ', '-i '] + Getgitargs (*args),
Universal_newlines=true)

def Callnginx (Action):
args = [Nginx, ' P ', openresty]
If action!= ' start ':
args + = [' s ', action]
Return Subprocess.check_output (args,
Stderr=subprocess. STDOUT, Universal_newlines=true)

# The Hook will write the information from STDIN and read the information into the variable
Oldrev,newrev,refname = Sys.stdin.readline (). Strip (). Split (")
# for our program, only the branch name is useful
Branch = Refname.split ('/') [-1]
Print (' oldref:%s, newrev:%s, refname:%s '% (Oldrev, Newrev, refname))
If not branch in branches:
Print (' The branch '%s ' is not in available list! '
' The list is%s '% (branch, str (branches))
Exit (1)

Try
# get the latest submissions under the branch currently available
commitmsg = callgit (' Log ', branch, '--oneline ', '-1 ') [8:-1]
Print (branch+ ' +commitmsg)
If commitmsg in signals:
Callnginx (COMMITMSG)
Print (' =======%s%s SUCCESS ======= '% (branch, commitmsg))
Else
Print (' The signal '%s ' is not in available list! '
' The list is%s '% (commitmsg, str (signals))
Except Subprocess. Calledprocesserror as ERR:
Print (' =======%s%s '%s ERROR ======= '% (branch, commitmsg, Err.output))
Exit (1)

Exit (0)

Iv. Deploying the server-side code from git bare repostory

In this example, I assume that the Git warehouse and the test server are on the same server. This is also a relatively common situation for small team development.
Structure of the service-side code

The server-side code is located in the/opt/openresty/nginx/lua folder. In this folder there is a subfolder based on the user name (branch name), which allows multiple developers to operate independently of the server code.

The following folder structure shows that two developers master and Zrong have deployed their own server-side code.

/opt/openresty/nginx/lua/
├──master
│└──main.lua
└──zrong
└──main.lua

Programmers can even choose to deploy other people's code into their own folders. It only needs to provide the branch name of the user you want to deploy (or simply provide a git commit SHA1) when you execute the command, and you can achieve this effect.
Command

The server contains the service-side code, and commands need to differentiate between the code-content push-back and the code-deployment push, or both.

The command is designed as follows:

If the first line of submissions contains up words, it is a command push. If there are other submissions at the same time, you can write a newline.

If it's just an ordinary submission, then write directly.

Assuming that the current Git library is located in the Zrong branch and that the current git warehouse is clean, here are a few examples:
Sample 1

Push the submitted code to the server and update the service-side code:

git commit--allow-empty-m ' up ' && git push Origin Zrong

Sample 2

To update the contents of the Allen branch in the server warehouse to/opt/openresty/nginx/lua/zrong:

git commit--allow-empty-m ' up Allen ' && git push Origin Zrong

Sample 3

Update the content in the commit SHA1 for 7ebbf4f3151e2dfd5bdcbe9fe276fc9b6afd25e7 to the/opt/openresty/nginx/lua/zrong:

git commit--allow-empty-m ' up 7ebbf4f ' && git push Origin Zrong

Export the contents of a bare warehouse

A git warehouse located on a server, usually bare, has no work-tree and cannot update the service-side code directly by copying it.

But we can use the git archive command to first export the code in the warehouse into a package, and then unpack the package to the appropriate deployment path to implement the server-side code update.

The following code does a few things:

Find server.git this bare warehouse;
Handle Zrong Branch;
Package the src/folder as a Src.tar file.

-

git--git-dir server.git archive-o src.tar zrong src/

If you want only one of these files, we can use git show to output the contents of this file to a file:

Git--git-dir server.git show Zrong:src/main.lua > Main.lua

Specific code

The following code shows the contents of the Post-receive hook in the server project.

#!/usr/bin/env python import sys import re Import os import subprocess import shutil luahome =  '/opt/openresty/nginx/lua ' #  uses the regular get command code and the branching information to be processed actionfmt = r ' ^up ? (\w+) $ ' branches =  (' master ',  ' Allen ',  ' Zrong ',  ' Xiefei ',  ' ZM ') def  Getgitargs (*args):     if args:         return  [' git ',  '--bare ',  '--git-dir ',  OS.GETCWD ()] + list (args)      return [] Def callgit (*args):     return subprocess.check_output ([' Env ' ,  ' i '] + getgitargs (*args),          universal_ Newlines=true, stderr=subprocess. STDOUT) #  The true branch Def getref (branch) to be processed from the submission information:     commitmsg = callgit (' Log ', branch,  '--oneline ',  '-1 ') [8:-1]     matchobj = re.search (actionfmt, commitmsg)     if matchobj:          if matchobj.group (1):              return matchobj.group (1)         return 
Branch     return none #   server/src  Backup to a file def archive (refname):     tarfile =  '%s/%s.tar '% (luahome, refname)     callgit (' Archive ',  ' o ', tarfile, refname,  ' src/')     return tarfile #   Unzip backup files to the correct folder Def tarxf (tarfile, refname, branch):     refdir =  os.path.join (Luahome, branch)     if os.path.exists (refdir):          shutil.rmtree (refdir)     args = [' tar ',   ' XF ', &Nbsp;tarfile,  '-C ',  luahome]     output = subprocess.check_output (args,         stderr=subprocess. Stdout, universal_newlines=true)     shutil.move (Os.path.join (luahome,  ' src/'),  refdir)     os.remove (tarfile)     return output Oldrev,newrev , Refname = sys.stdin.readline (). Strip (). Split ('   ') print (' oldref:%s, newrev:%s,  refname:%s '% (oldrev, newrev, refname)) branch = refname.split ('/') [-1] if not  Branch in branches:     print (' the branch  '%s '  is not in  available list!  '          ' the list is % S. '% (branch, str (branches)))     exit (1) Try:     refname =  getref (Branch)     if refnAme:         tarfile = archive (refname)          SUCC = TARXF (Tarfile, refname, branch)          print (' update [%s] by [%s] success. '% ( Branch, refname)  )         print (' ======= update [% s] by [%s] success ======= '% (branch, refname)) except subprocess. Calledprocesserror as err:     print (' update [%s] by [%s]  error: %s '% (branch, refname, err.output))     print (' ======= update
 [%s] by [%s] error ======= '% (branch, refname))     exit (1) Exit (0)


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.