Merge pull request #493 from apachelogger/api-over-socket

support serving the API over unix domain socket
This commit is contained in:
Andrey Smirnov
2017-02-28 23:41:09 +03:00
committed by GitHub
5 changed files with 70 additions and 10 deletions

View File

@@ -23,7 +23,7 @@ before_install:
- . env/bin/activate
- pip install six packaging appdirs
- pip install -U pip setuptools
- pip install boto requests python-swiftclient
- pip install boto requests requests-unixsocket python-swiftclient
- mkdir -p $GOPATH/src/github.com/smira
- ln -s $TRAVIS_BUILD_DIR $GOPATH/src/github.com/smira || true
- cd $GOPATH/src/github.com/smira/aptly

View File

@@ -2,11 +2,15 @@ package cmd
import (
"fmt"
"net"
"net/http"
"net/url"
"os"
"github.com/smira/aptly/api"
"github.com/smira/aptly/utils"
"github.com/smira/commander"
"github.com/smira/flag"
"net/http"
)
func aptlyAPIServe(cmd *commander.Command, args []string) error {
@@ -34,6 +38,22 @@ func aptlyAPIServe(cmd *commander.Command, args []string) error {
fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen)
listenURL, err := url.Parse(listen)
if err == nil && listenURL.Scheme == "unix" {
file := listenURL.Path
os.Remove(file)
listener, err := net.Listen("unix", file)
if err != nil {
return fmt.Errorf("failed to listen on: %s\n%s", file, err)
}
defer listener.Close()
err = http.Serve(listener, api.Router(context))
if err != nil {
return fmt.Errorf("unable to serve: %s", err)
}
return nil
}
err = http.ListenAndServe(listen, api.Router(context))
if err != nil {
return fmt.Errorf("unable to serve: %s", err)
@@ -48,16 +68,19 @@ func makeCmdAPIServe() *commander.Command {
UsageLine: "serve",
Short: "start API HTTP service",
Long: `
Stat HTTP server with aptly REST API.
Start HTTP server with aptly REST API. The server can listen to either a port
or Unix domain socket. When using a socket, Aptly will fully manage the socket
file.
Example:
$ aptly api serve -listen=:8080
$ aptly api serve -listen=unix:///tmp/aptly.sock
`,
Flag: *flag.NewFlagSet("aptly-serve", flag.ExitOnError),
}
cmd.Flag.String("listen", ":8080", "host:port for HTTP listening")
cmd.Flag.String("listen", ":8080", "host:port for HTTP listening or unix://path to listen on a Unix domain socket")
cmd.Flag.Bool("no-lock", false, "don't lock the database")
return cmd

View File

@@ -1685,20 +1685,17 @@ host:port for HTTP listening
\fBaptly\fR \fBapi\fR \fBserve\fR
.
.P
Stat HTTP server with aptly REST API\.
Start HTTP server with aptly REST API\. The server can listen to either a port or Unix domain socket\. When using a socket, Aptly will fully manage the socket file\.
.
.P
Example:
.
.P
$ aptly api serve \-listen=:8080
Example: $ aptly api serve \-listen=:8080 $ aptly api serve \-listen=unix:///tmp/aptly\.sock
.
.P
Options:
.
.TP
\-\fBlisten\fR=:8080
host:port for HTTP listening
host:port for HTTP listening or unix://path to listen on a Unix domain socket
.
.TP
\-\fBno\-lock\fR=false
@@ -1882,5 +1879,8 @@ Harald Sitter (https://github\.com/apachelogger)
.IP "\[ci]" 4
Johannes Layher (https://github\.com/jola5)
.
.IP "\[ci]" 4
Charles Hsu (https://github\.com/charz)
.
.IP "" 0

View File

@@ -9,3 +9,4 @@ from .version import *
from .graph import *
from .snapshots import *
from .packages import *
from .unix_socket import *

View File

@@ -0,0 +1,36 @@
import requests_unixsocket
import time
import urllib
from lib import BaseTest
class UnixSocketAPITest(BaseTest):
aptly_server = None
socket_path = "/tmp/_aptly_test.sock"
base_url = ("unix://%s" % socket_path)
def prepare(self):
if self.aptly_server is None:
self.aptly_server = self._start_process("aptly api serve -no-lock -listen=%s" % (self.base_url),)
time.sleep(1)
super(UnixSocketAPITest, self).prepare()
def shutdown(self):
if self.aptly_server is not None:
self.aptly_server.terminate()
self.aptly_server.wait()
self.aptly_server = None
super(UnixSocketAPITest, self).shutdown()
def run(self):
pass
"""
Verify we can listen on a unix domain socket.
"""
def check(self):
session = requests_unixsocket.Session()
r = session.get('http+unix://%s/api/version' % urllib.quote(UnixSocketAPITest.socket_path, safe=''))
# Just needs to come back, we actually don't care much about the code.
# Only needs to verify that the socket is actually responding.
self.check_equal(r.json(), {'Version': '0.9.8~dev'})