mirror of https://github.com/docker/docs.git
Merge branch 'master' into fix_tests
This commit is contained in:
commit
bb284ce59d
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
#### Notable features since 0.6.0
|
#### Notable features since 0.6.0
|
||||||
|
|
||||||
* Storage drivers: choose from aufs, device mapper, vfs or btrfs.
|
* Storage drivers: choose from aufs, device-mapper, or vfs.
|
||||||
* Standard Linux support: docker now runs on unmodified linux kernels and all major distributions.
|
* Standard Linux support: docker now runs on unmodified Linux kernels and all major distributions.
|
||||||
* Links: compose complex software stacks by connecting containers to each other.
|
* Links: compose complex software stacks by connecting containers to each other.
|
||||||
* Container naming: organize your containers by giving them memorable names.
|
* Container naming: organize your containers by giving them memorable names.
|
||||||
* Advanced port redirects: specify port redirects per interface, or keep sensitive ports private.
|
* Advanced port redirects: specify port redirects per interface, or keep sensitive ports private.
|
||||||
|
|
15
api.go
15
api.go
|
@ -15,6 +15,7 @@ import (
|
||||||
"mime"
|
"mime"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -1037,9 +1038,21 @@ func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AttachProfiler(router *mux.Router) {
|
||||||
|
router.HandleFunc("/debug/pprof/", pprof.Index)
|
||||||
|
router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||||
|
router.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||||
|
router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||||
|
router.HandleFunc("/debug/pprof/heap", pprof.Handler("heap").ServeHTTP)
|
||||||
|
router.HandleFunc("/debug/pprof/goroutine", pprof.Handler("goroutine").ServeHTTP)
|
||||||
|
router.HandleFunc("/debug/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP)
|
||||||
|
}
|
||||||
|
|
||||||
func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
|
if os.Getenv("DEBUG") != "" {
|
||||||
|
AttachProfiler(r)
|
||||||
|
}
|
||||||
m := map[string]map[string]HttpApiFunc{
|
m := map[string]map[string]HttpApiFunc{
|
||||||
"GET": {
|
"GET": {
|
||||||
"/events": getEvents,
|
"/events": getEvents,
|
||||||
|
|
|
@ -288,7 +288,7 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error {
|
||||||
destPath = destPath + "/"
|
destPath = destPath + "/"
|
||||||
}
|
}
|
||||||
if !strings.HasPrefix(origPath, b.context) {
|
if !strings.HasPrefix(origPath, b.context) {
|
||||||
return fmt.Errorf("Forbidden path: %s", origPath)
|
return fmt.Errorf("Forbidden path outside the build context: %s (%s)", orig, origPath)
|
||||||
}
|
}
|
||||||
fi, err := os.Stat(origPath)
|
fi, err := os.Stat(origPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -2199,7 +2199,7 @@ func (cli *DockerCli) CmdCp(args ...string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) CmdSave(args ...string) error {
|
func (cli *DockerCli) CmdSave(args ...string) error {
|
||||||
cmd := cli.Subcmd("save", "IMAGE DESTINATION", "Save an image to a tar archive")
|
cmd := cli.Subcmd("save", "IMAGE", "Save an image to a tar archive (streamed to stdout)")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,3 +17,34 @@ meaning you can use Vagrant to control Docker containers.
|
||||||
|
|
||||||
* [docker-provider](https://github.com/fgrehm/docker-provider)
|
* [docker-provider](https://github.com/fgrehm/docker-provider)
|
||||||
* [vagrant-shell](https://github.com/destructuring/vagrant-shell)
|
* [vagrant-shell](https://github.com/destructuring/vagrant-shell)
|
||||||
|
|
||||||
|
## Setting up Vagrant-docker with the Remote API
|
||||||
|
|
||||||
|
The initial Docker upstart script will not work because it runs on `127.0.0.1`, which is not accessible to the host machine. Instead, we need to change the script to connect to `0.0.0.0`. To do this, modify `/etc/init/docker.conf` to look like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
description "Docker daemon"
|
||||||
|
|
||||||
|
start on filesystem and started lxc-net
|
||||||
|
stop on runlevel [!2345]
|
||||||
|
|
||||||
|
respawn
|
||||||
|
|
||||||
|
script
|
||||||
|
/usr/bin/docker -d -H=tcp://0.0.0.0:4243/
|
||||||
|
end script
|
||||||
|
```
|
||||||
|
|
||||||
|
Once that's done, you need to set up a SSH tunnel between your host machine and the vagrant machine that's running Docker. This can be done by running the following command in a host terminal:
|
||||||
|
|
||||||
|
```
|
||||||
|
ssh -L 4243:localhost:4243 -p 2222 vagrant@localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
(The first 4243 is what your host can connect to, the second 4243 is what port Docker is running on in the vagrant machine, and the 2222 is the port Vagrant is providing for SSH. If VirtualBox is the VM you're using, you can see what value "2222" should be by going to: Network > Adapter 1 > Advanced > Port Forwarding in the VirtualBox GUI.)
|
||||||
|
|
||||||
|
Note that because the port has been changed, to run docker commands from within the command line you must run them like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo docker -H 0.0.0.0:4243 < commands for docker >
|
||||||
|
```
|
||||||
|
|
|
@ -797,7 +797,7 @@ Known Issues (kill)
|
||||||
-link="": Remove the link instead of the actual container
|
-link="": Remove the link instead of the actual container
|
||||||
|
|
||||||
Known Issues (rm)
|
Known Issues (rm)
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
* :issue:`197` indicates that ``docker kill`` may leave directories
|
* :issue:`197` indicates that ``docker kill`` may leave directories
|
||||||
behind and make it difficult to remove the container.
|
behind and make it difficult to remove the container.
|
||||||
|
@ -881,8 +881,15 @@ containers will not be deleted.
|
||||||
-name="": Assign the specified name to the container. If no name is specific docker will generate a random name
|
-name="": Assign the specified name to the container. If no name is specific docker will generate a random name
|
||||||
-P=false: Publish all exposed ports to the host interfaces
|
-P=false: Publish all exposed ports to the host interfaces
|
||||||
|
|
||||||
Examples
|
Known Issues (run -volumes-from)
|
||||||
--------
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* :issue:`2702`: "lxc-start: Permission denied - failed to mount"
|
||||||
|
could indicate a permissions problem with AppArmor. Please see the
|
||||||
|
issue for a workaround.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
@ -974,16 +981,10 @@ id may be optionally suffixed with ``:ro`` or ``:rw`` to mount the volumes in
|
||||||
read-only or read-write mode, respectively. By default, the volumes are mounted
|
read-only or read-write mode, respectively. By default, the volumes are mounted
|
||||||
in the same mode (rw or ro) as the reference container.
|
in the same mode (rw or ro) as the reference container.
|
||||||
|
|
||||||
Known Issues (run -volumes-from)
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
* :issue:`2702`: "lxc-start: Permission denied - failed to mount"
|
|
||||||
could indicate a permissions problem with AppArmor. Please see the
|
|
||||||
issue for a workaround.
|
|
||||||
|
|
||||||
.. _cli_save:
|
.. _cli_save:
|
||||||
|
|
||||||
``save``
|
``save``
|
||||||
|
---------
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
|
|
@ -131,8 +131,6 @@ Attach to the container to see the results in real-time.
|
||||||
|
|
||||||
- **"docker attach**" This will allow us to attach to a background
|
- **"docker attach**" This will allow us to attach to a background
|
||||||
process to see what is going on.
|
process to see what is going on.
|
||||||
- **"-sig-proxy=true"** Proxify all received signal to the process
|
|
||||||
(even in non-tty mode)
|
|
||||||
- **$CONTAINER_ID** The Id of the container we want to attach too.
|
- **$CONTAINER_ID** The Id of the container we want to attach too.
|
||||||
|
|
||||||
Exit from the container attachment by pressing Control-C.
|
Exit from the container attachment by pressing Control-C.
|
||||||
|
|
|
@ -45,19 +45,21 @@ Install ``python-software-properties``.
|
||||||
apt-get -y install python-software-properties
|
apt-get -y install python-software-properties
|
||||||
apt-get -y install software-properties-common
|
apt-get -y install software-properties-common
|
||||||
|
|
||||||
Add Pitti's PostgreSQL repository. It contains the most recent stable release
|
Add PostgreSQL's repository. It contains the most recent stable release
|
||||||
of PostgreSQL i.e. ``9.2``.
|
of PostgreSQL i.e. ``9.3``.
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
add-apt-repository ppa:pitti/postgresql
|
apt-get -y install wget
|
||||||
|
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
|
||||||
|
echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > /etc/apt/sources.list.d/pgdg.list
|
||||||
apt-get update
|
apt-get update
|
||||||
|
|
||||||
Finally, install PostgreSQL 9.2
|
Finally, install PostgreSQL 9.3
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
apt-get -y install postgresql-9.2 postgresql-client-9.2 postgresql-contrib-9.2
|
apt-get -y install postgresql-9.3 postgresql-client-9.3 postgresql-contrib-9.3
|
||||||
|
|
||||||
Now, create a PostgreSQL superuser role that can create databases and
|
Now, create a PostgreSQL superuser role that can create databases and
|
||||||
other roles. Following Vagrant's convention the role will be named
|
other roles. Following Vagrant's convention the role will be named
|
||||||
|
@ -76,14 +78,14 @@ role.
|
||||||
|
|
||||||
Adjust PostgreSQL configuration so that remote connections to the
|
Adjust PostgreSQL configuration so that remote connections to the
|
||||||
database are possible. Make sure that inside
|
database are possible. Make sure that inside
|
||||||
``/etc/postgresql/9.2/main/pg_hba.conf`` you have following line (you will need
|
``/etc/postgresql/9.3/main/pg_hba.conf`` you have following line (you will need
|
||||||
to install an editor, e.g. ``apt-get install vim``):
|
to install an editor, e.g. ``apt-get install vim``):
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
host all all 0.0.0.0/0 md5
|
host all all 0.0.0.0/0 md5
|
||||||
|
|
||||||
Additionaly, inside ``/etc/postgresql/9.2/main/postgresql.conf``
|
Additionaly, inside ``/etc/postgresql/9.3/main/postgresql.conf``
|
||||||
uncomment ``listen_addresses`` so it is as follows:
|
uncomment ``listen_addresses`` so it is as follows:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
@ -115,9 +117,9 @@ Finally, run PostgreSQL server via ``docker``.
|
||||||
|
|
||||||
CONTAINER=$(sudo docker run -d -p 5432 \
|
CONTAINER=$(sudo docker run -d -p 5432 \
|
||||||
-t <your username>/postgresql \
|
-t <your username>/postgresql \
|
||||||
/bin/su postgres -c '/usr/lib/postgresql/9.2/bin/postgres \
|
/bin/su postgres -c '/usr/lib/postgresql/9.3/bin/postgres \
|
||||||
-D /var/lib/postgresql/9.2/main \
|
-D /var/lib/postgresql/9.3/main \
|
||||||
-c config_file=/etc/postgresql/9.2/main/postgresql.conf')
|
-c config_file=/etc/postgresql/9.3/main/postgresql.conf')
|
||||||
|
|
||||||
Connect the PostgreSQL server using ``psql`` (You will need postgres installed
|
Connect the PostgreSQL server using ``psql`` (You will need postgres installed
|
||||||
on the machine. For ubuntu, use something like
|
on the machine. For ubuntu, use something like
|
||||||
|
@ -132,7 +134,7 @@ As before, create roles or databases if needed.
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
psql (9.2.4)
|
psql (9.3.1)
|
||||||
Type "help" for help.
|
Type "help" for help.
|
||||||
|
|
||||||
docker=# CREATE DATABASE foo OWNER=docker;
|
docker=# CREATE DATABASE foo OWNER=docker;
|
||||||
|
@ -160,9 +162,9 @@ container starts.
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
sudo docker commit -run='{"Cmd": \
|
sudo docker commit -run='{"Cmd": \
|
||||||
["/bin/su", "postgres", "-c", "/usr/lib/postgresql/9.2/bin/postgres -D \
|
["/bin/su", "postgres", "-c", "/usr/lib/postgresql/9.3/bin/postgres -D \
|
||||||
/var/lib/postgresql/9.2/main -c \
|
/var/lib/postgresql/9.3/main -c \
|
||||||
config_file=/etc/postgresql/9.2/main/postgresql.conf"], "PortSpecs": ["5432"]}' \
|
config_file=/etc/postgresql/9.3/main/postgresql.conf"], "PortSpecs": ["5432"]}' \
|
||||||
<container_id> <your username>/postgresql
|
<container_id> <your username>/postgresql
|
||||||
|
|
||||||
From now on, just type ``docker run <your username>/postgresql`` and
|
From now on, just type ``docker run <your username>/postgresql`` and
|
||||||
|
|
|
@ -12,27 +12,28 @@ Arch Linux
|
||||||
.. include:: install_unofficial.inc
|
.. include:: install_unofficial.inc
|
||||||
|
|
||||||
Installing on Arch Linux is not officially supported but can be handled via
|
Installing on Arch Linux is not officially supported but can be handled via
|
||||||
either of the following AUR packages:
|
one of the following AUR packages:
|
||||||
|
|
||||||
* `lxc-docker <https://aur.archlinux.org/packages/lxc-docker/>`_
|
* `lxc-docker <https://aur.archlinux.org/packages/lxc-docker/>`_
|
||||||
* `lxc-docker-git <https://aur.archlinux.org/packages/lxc-docker-git/>`_
|
* `lxc-docker-git <https://aur.archlinux.org/packages/lxc-docker-git/>`_
|
||||||
|
* `lxc-docker-nightly <https://aur.archlinux.org/packages/lxc-docker-nightly/>`_
|
||||||
|
|
||||||
The lxc-docker package will install the latest tagged version of docker.
|
The lxc-docker package will install the latest tagged version of docker.
|
||||||
The lxc-docker-git package will build from the current master branch.
|
The lxc-docker-git package will build from the current master branch.
|
||||||
|
The lxc-docker-nightly package will install the latest build.
|
||||||
|
|
||||||
Dependencies
|
Dependencies
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Docker depends on several packages which are specified as dependencies in
|
Docker depends on several packages which are specified as dependencies in
|
||||||
either AUR package.
|
the AUR packages. The core dependencies are:
|
||||||
|
|
||||||
* aufs3
|
|
||||||
* bridge-utils
|
* bridge-utils
|
||||||
* go
|
* device-mapper
|
||||||
* iproute2
|
* iproute2
|
||||||
* linux-aufs_friendly
|
|
||||||
* lxc
|
* lxc
|
||||||
|
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -41,20 +42,14 @@ The instructions here assume **yaourt** is installed. See
|
||||||
for information on building and installing packages from the AUR if you have not
|
for information on building and installing packages from the AUR if you have not
|
||||||
done so before.
|
done so before.
|
||||||
|
|
||||||
Keep in mind that if **linux-aufs_friendly** is not already installed that a
|
|
||||||
new kernel will be compiled and this can take quite a while.
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
yaourt -S lxc-docker-git
|
yaourt -S lxc-docker
|
||||||
|
|
||||||
|
|
||||||
Starting Docker
|
Starting Docker
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Prior to starting docker modify your bootloader to use the
|
|
||||||
**linux-aufs_friendly** kernel and reboot your system.
|
|
||||||
|
|
||||||
There is a systemd service unit created for docker. To start the docker service:
|
There is a systemd service unit created for docker. To start the docker service:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
package devmapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/dotcloud/docker/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func stringToLoopName(src string) [LoNameSize]uint8 {
|
||||||
|
var dst [LoNameSize]uint8
|
||||||
|
copy(dst[:], src[:])
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNextFreeLoopbackIndex() (int, error) {
|
||||||
|
f, err := osOpenFile("/dev/loop-control", osORdOnly, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
index, err := ioctlLoopCtlGetFree(f.Fd())
|
||||||
|
if index < 0 {
|
||||||
|
index = 0
|
||||||
|
}
|
||||||
|
return index, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func openNextAvailableLoopback(index int, sparseFile *osFile) (loopFile *osFile, err error) {
|
||||||
|
// Start looking for a free /dev/loop
|
||||||
|
for {
|
||||||
|
target := fmt.Sprintf("/dev/loop%d", index)
|
||||||
|
index++
|
||||||
|
|
||||||
|
fi, err := osStat(target)
|
||||||
|
if err != nil {
|
||||||
|
if osIsNotExist(err) {
|
||||||
|
utils.Errorf("There are no more loopback device available.")
|
||||||
|
}
|
||||||
|
return nil, ErrAttachLoopbackDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Mode()&osModeDevice != osModeDevice {
|
||||||
|
utils.Errorf("Loopback device %s is not a block device.", target)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenFile adds O_CLOEXEC
|
||||||
|
loopFile, err = osOpenFile(target, osORdWr, 0644)
|
||||||
|
if err != nil {
|
||||||
|
utils.Errorf("Error openning loopback device: %s", err)
|
||||||
|
return nil, ErrAttachLoopbackDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to attach to the loop file
|
||||||
|
if err := ioctlLoopSetFd(loopFile.Fd(), sparseFile.Fd()); err != nil {
|
||||||
|
loopFile.Close()
|
||||||
|
|
||||||
|
// If the error is EBUSY, then try the next loopback
|
||||||
|
if err != sysEBusy {
|
||||||
|
utils.Errorf("Cannot set up loopback device %s: %s", target, err)
|
||||||
|
return nil, ErrAttachLoopbackDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we keep going with the loop
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// In case of success, we finished. Break the loop.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// This can't happen, but let's be sure
|
||||||
|
if loopFile == nil {
|
||||||
|
utils.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", sparseFile.Name())
|
||||||
|
return nil, ErrAttachLoopbackDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
return loopFile, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// attachLoopDevice attaches the given sparse file to the next
|
||||||
|
// available loopback device. It returns an opened *osFile.
|
||||||
|
func attachLoopDevice(sparseName string) (loop *osFile, err error) {
|
||||||
|
|
||||||
|
// Try to retrieve the next available loopback device via syscall.
|
||||||
|
// If it fails, we discard error and start loopking for a
|
||||||
|
// loopback from index 0.
|
||||||
|
startIndex, err := getNextFreeLoopbackIndex()
|
||||||
|
if err != nil {
|
||||||
|
utils.Debugf("Error retrieving the next available loopback: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenFile adds O_CLOEXEC
|
||||||
|
sparseFile, err := osOpenFile(sparseName, osORdWr, 0644)
|
||||||
|
if err != nil {
|
||||||
|
utils.Errorf("Error openning sparse file %s: %s", sparseName, err)
|
||||||
|
return nil, ErrAttachLoopbackDevice
|
||||||
|
}
|
||||||
|
defer sparseFile.Close()
|
||||||
|
|
||||||
|
loopFile, err := openNextAvailableLoopback(startIndex, sparseFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the status of the loopback device
|
||||||
|
loopInfo := &LoopInfo64{
|
||||||
|
loFileName: stringToLoopName(loopFile.Name()),
|
||||||
|
loOffset: 0,
|
||||||
|
loFlags: LoFlagsAutoClear,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioctlLoopSetStatus64(loopFile.Fd(), loopInfo); err != nil {
|
||||||
|
utils.Errorf("Cannot set up loopback device info: %s", err)
|
||||||
|
|
||||||
|
// If the call failed, then free the loopback device
|
||||||
|
if err := ioctlLoopClrFd(loopFile.Fd()); err != nil {
|
||||||
|
utils.Errorf("Error while cleaning up the loopback device")
|
||||||
|
}
|
||||||
|
loopFile.Close()
|
||||||
|
return nil, ErrAttachLoopbackDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
return loopFile, nil
|
||||||
|
}
|
|
@ -383,7 +383,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
|
||||||
return fmt.Errorf("Can't shrink file")
|
return fmt.Errorf("Can't shrink file")
|
||||||
}
|
}
|
||||||
|
|
||||||
dataloopback := FindLoopDeviceFor(&osFile{File: datafile})
|
dataloopback := FindLoopDeviceFor(datafile)
|
||||||
if dataloopback == nil {
|
if dataloopback == nil {
|
||||||
return fmt.Errorf("Unable to find loopback mount for: %s", datafilename)
|
return fmt.Errorf("Unable to find loopback mount for: %s", datafilename)
|
||||||
}
|
}
|
||||||
|
@ -395,7 +395,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
|
||||||
}
|
}
|
||||||
defer metadatafile.Close()
|
defer metadatafile.Close()
|
||||||
|
|
||||||
metadataloopback := FindLoopDeviceFor(&osFile{File: metadatafile})
|
metadataloopback := FindLoopDeviceFor(metadatafile)
|
||||||
if metadataloopback == nil {
|
if metadataloopback == nil {
|
||||||
return fmt.Errorf("Unable to find loopback mount for: %s", metadatafilename)
|
return fmt.Errorf("Unable to find loopback mount for: %s", metadatafilename)
|
||||||
}
|
}
|
||||||
|
@ -491,14 +491,14 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
||||||
if info.Exists == 0 {
|
if info.Exists == 0 {
|
||||||
utils.Debugf("Pool doesn't exist. Creating it.")
|
utils.Debugf("Pool doesn't exist. Creating it.")
|
||||||
|
|
||||||
dataFile, err := AttachLoopDevice(data)
|
dataFile, err := attachLoopDevice(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Debugf("\n--->Err: %s\n", err)
|
utils.Debugf("\n--->Err: %s\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer dataFile.Close()
|
defer dataFile.Close()
|
||||||
|
|
||||||
metadataFile, err := AttachLoopDevice(metadata)
|
metadataFile, err := attachLoopDevice(metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Debugf("\n--->Err: %s\n", err)
|
utils.Debugf("\n--->Err: %s\n", err)
|
||||||
return err
|
return err
|
||||||
|
@ -637,7 +637,7 @@ func (devices *DeviceSet) deactivateDevice(hash string) error {
|
||||||
// or b) the 1 second timeout expires.
|
// or b) the 1 second timeout expires.
|
||||||
func (devices *DeviceSet) waitRemove(hash string) error {
|
func (devices *DeviceSet) waitRemove(hash string) error {
|
||||||
utils.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, hash)
|
utils.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, hash)
|
||||||
defer utils.Debugf("[deviceset %s] waitRemove END", devices.devicePrefix, hash)
|
defer utils.Debugf("[deviceset %s] waitRemove(%) END", devices.devicePrefix, hash)
|
||||||
devname, err := devices.byHash(hash)
|
devname, err := devices.byHash(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -177,25 +177,18 @@ func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
|
||||||
start, length, targetType, params
|
start, length, targetType, params
|
||||||
}
|
}
|
||||||
|
|
||||||
func AttachLoopDevice(filename string) (*osFile, error) {
|
|
||||||
var fd int
|
|
||||||
res := DmAttachLoopDevice(filename, &fd)
|
|
||||||
if res == "" {
|
|
||||||
return nil, ErrAttachLoopbackDevice
|
|
||||||
}
|
|
||||||
return &osFile{File: osNewFile(uintptr(fd), res)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLoopbackBackingFile(file *osFile) (uint64, uint64, error) {
|
func getLoopbackBackingFile(file *osFile) (uint64, uint64, error) {
|
||||||
dev, inode, err := DmGetLoopbackBackingFile(file.Fd())
|
loopInfo, err := ioctlLoopGetStatus64(file.Fd())
|
||||||
if err != 0 {
|
if err != nil {
|
||||||
|
utils.Errorf("Error get loopback backing file: %s\n", err)
|
||||||
return 0, 0, ErrGetLoopbackBackingFile
|
return 0, 0, ErrGetLoopbackBackingFile
|
||||||
}
|
}
|
||||||
return dev, inode, nil
|
return loopInfo.loDevice, loopInfo.loInode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoopbackSetCapacity(file *osFile) error {
|
func LoopbackSetCapacity(file *osFile) error {
|
||||||
if err := DmLoopbackSetCapacity(file.Fd()); err != 0 {
|
if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
|
||||||
|
utils.Errorf("Error loopbackSetCapacity: %s", err)
|
||||||
return ErrLoopbackSetCapacity
|
return ErrLoopbackSetCapacity
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -223,11 +216,10 @@ func FindLoopDeviceFor(file *osFile) *osFile {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
dev, inode, err := getLoopbackBackingFile(&osFile{File: file})
|
dev, inode, err := getLoopbackBackingFile(file)
|
||||||
if err == nil && dev == targetDevice && inode == targetInode {
|
if err == nil && dev == targetDevice && inode == targetInode {
|
||||||
return &osFile{File: file}
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
file.Close()
|
file.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,8 +278,9 @@ func RemoveDevice(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBlockDeviceSize(file *osFile) (uint64, error) {
|
func GetBlockDeviceSize(file *osFile) (uint64, error) {
|
||||||
size, errno := DmGetBlockSize(file.Fd())
|
size, err := ioctlBlkGetSize64(file.Fd())
|
||||||
if size == -1 || errno != 0 {
|
if err != nil {
|
||||||
|
utils.Errorf("Error getblockdevicesize: %s", err)
|
||||||
return 0, ErrGetBlockSize
|
return 0, ErrGetBlockSize
|
||||||
}
|
}
|
||||||
return uint64(size), nil
|
return uint64(size), nil
|
||||||
|
@ -420,7 +413,7 @@ func suspendDevice(name string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := task.Run(); err != nil {
|
if err := task.Run(); err != nil {
|
||||||
return fmt.Errorf("Error running DeviceSuspend")
|
return fmt.Errorf("Error running DeviceSuspend: %s", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -437,7 +430,7 @@ func resumeDevice(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := task.Run(); err != nil {
|
if err := task.Run(); err != nil {
|
||||||
return fmt.Errorf("Error running DeviceSuspend")
|
return fmt.Errorf("Error running DeviceResume")
|
||||||
}
|
}
|
||||||
|
|
||||||
UdevWait(cookie)
|
UdevWait(cookie)
|
||||||
|
|
|
@ -2,124 +2,14 @@ package devmapper
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo LDFLAGS: -L. -ldevmapper
|
#cgo LDFLAGS: -L. -ldevmapper
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <libdevmapper.h>
|
#include <libdevmapper.h>
|
||||||
#include <linux/loop.h>
|
#include <linux/loop.h> // FIXME: present only for defines, maybe we can remove it?
|
||||||
#include <sys/types.h>
|
#include <linux/fs.h> // FIXME: present only for BLKGETSIZE64, maybe we can remove it?
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#ifndef LOOP_CTL_GET_FREE
|
|
||||||
#define LOOP_CTL_GET_FREE 0x4C82
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// FIXME: this could easily be rewritten in go
|
|
||||||
char* attach_loop_device(const char *filename, int *loop_fd_out)
|
|
||||||
{
|
|
||||||
struct loop_info64 loopinfo = {0};
|
|
||||||
struct stat st;
|
|
||||||
char buf[64];
|
|
||||||
int i, loop_fd, fd, start_index;
|
|
||||||
char* loopname;
|
|
||||||
|
|
||||||
|
|
||||||
*loop_fd_out = -1;
|
|
||||||
|
|
||||||
start_index = 0;
|
|
||||||
fd = open("/dev/loop-control", O_RDONLY);
|
|
||||||
if (fd >= 0) {
|
|
||||||
start_index = ioctl(fd, LOOP_CTL_GET_FREE);
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
if (start_index < 0)
|
|
||||||
start_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = open(filename, O_RDWR);
|
|
||||||
if (fd < 0) {
|
|
||||||
perror("open");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
loop_fd = -1;
|
|
||||||
for (i = start_index ; loop_fd < 0 ; i++ ) {
|
|
||||||
if (sprintf(buf, "/dev/loop%d", i) < 0) {
|
|
||||||
close(fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stat(buf, &st)) {
|
|
||||||
if (!S_ISBLK(st.st_mode)) {
|
|
||||||
fprintf(stderr, "[error] Loopback device %s is not a block device.\n", buf);
|
|
||||||
} else if (errno == ENOENT) {
|
|
||||||
fprintf(stderr, "[error] There are no more loopback device available.\n");
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "[error] Unkown error trying to stat the loopback device %s (errno: %d).\n", buf, errno);
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
loop_fd = open(buf, O_RDWR);
|
|
||||||
if (loop_fd < 0 && errno == ENOENT) {
|
|
||||||
fprintf(stderr, "[error] The loopback device %s does not exists.\n", buf);
|
|
||||||
close(fd);
|
|
||||||
return NULL;
|
|
||||||
} else if (loop_fd < 0) {
|
|
||||||
fprintf(stderr, "[error] Unkown error openning the loopback device %s. (errno: %d)\n", buf, errno);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) {
|
|
||||||
int errsv = errno;
|
|
||||||
close(loop_fd);
|
|
||||||
loop_fd = -1;
|
|
||||||
if (errsv != EBUSY) {
|
|
||||||
close(fd);
|
|
||||||
fprintf(stderr, "cannot set up loopback device %s: %s", buf, strerror(errsv));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
strncpy((char*)loopinfo.lo_file_name, buf, LO_NAME_SIZE);
|
|
||||||
loopinfo.lo_offset = 0;
|
|
||||||
loopinfo.lo_flags = LO_FLAGS_AUTOCLEAR;
|
|
||||||
|
|
||||||
if (ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo) < 0) {
|
|
||||||
perror("ioctl LOOP_SET_STATUS64");
|
|
||||||
if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
|
|
||||||
perror("ioctl LOOP_CLR_FD");
|
|
||||||
}
|
|
||||||
close(loop_fd);
|
|
||||||
fprintf (stderr, "cannot set up loopback device info");
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
loopname = strdup(buf);
|
|
||||||
if (loopname == NULL) {
|
|
||||||
close(loop_fd);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
*loop_fd_out = loop_fd;
|
|
||||||
return (loopname);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// FIXME: Can't we find a way to do the logging in pure Go?
|
||||||
extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
|
extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
|
||||||
|
|
||||||
static void log_cb(int level, const char *file, int line,
|
static void log_cb(int level, const char *file, int line, int dm_errno_or_class, const char *f, ...)
|
||||||
int dm_errno_or_class, const char *f, ...)
|
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
@ -135,7 +25,6 @@ static void log_with_errno_init()
|
||||||
{
|
{
|
||||||
dm_log_with_errno_init(log_cb);
|
dm_log_with_errno_init(log_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
@ -145,31 +34,64 @@ import (
|
||||||
|
|
||||||
type (
|
type (
|
||||||
CDmTask C.struct_dm_task
|
CDmTask C.struct_dm_task
|
||||||
|
|
||||||
|
CLoopInfo64 C.struct_loop_info64
|
||||||
|
LoopInfo64 struct {
|
||||||
|
loDevice uint64 /* ioctl r/o */
|
||||||
|
loInode uint64 /* ioctl r/o */
|
||||||
|
loRdevice uint64 /* ioctl r/o */
|
||||||
|
loOffset uint64
|
||||||
|
loSizelimit uint64 /* bytes, 0 == max available */
|
||||||
|
loNumber uint32 /* ioctl r/o */
|
||||||
|
loEncrypt_type uint32
|
||||||
|
loEncrypt_key_size uint32 /* ioctl w/o */
|
||||||
|
loFlags uint32 /* ioctl r/o */
|
||||||
|
loFileName [LoNameSize]uint8
|
||||||
|
loCryptName [LoNameSize]uint8
|
||||||
|
loEncryptKey [LoKeySize]uint8 /* ioctl w/o */
|
||||||
|
loInit [2]uint64
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// FIXME: Make sure the values are defined in C
|
||||||
|
// IOCTL consts
|
||||||
|
const (
|
||||||
|
BlkGetSize64 = C.BLKGETSIZE64
|
||||||
|
|
||||||
|
LoopSetFd = C.LOOP_SET_FD
|
||||||
|
LoopCtlGetFree = C.LOOP_CTL_GET_FREE
|
||||||
|
LoopGetStatus64 = C.LOOP_GET_STATUS64
|
||||||
|
LoopSetStatus64 = C.LOOP_SET_STATUS64
|
||||||
|
LoopClrFd = C.LOOP_CLR_FD
|
||||||
|
LoopSetCapacity = C.LOOP_SET_CAPACITY
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LoFlagsAutoClear = C.LO_FLAGS_AUTOCLEAR
|
||||||
|
LoFlagsReadOnly = C.LO_FLAGS_READ_ONLY
|
||||||
|
LoFlagsPartScan = C.LO_FLAGS_PARTSCAN
|
||||||
|
LoKeySize = C.LO_KEY_SIZE
|
||||||
|
LoNameSize = C.LO_NAME_SIZE
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DmAttachLoopDevice = dmAttachLoopDeviceFct
|
DmGetLibraryVersion = dmGetLibraryVersionFct
|
||||||
DmGetBlockSize = dmGetBlockSizeFct
|
DmGetNextTarget = dmGetNextTargetFct
|
||||||
DmGetLibraryVersion = dmGetLibraryVersionFct
|
DmLogInitVerbose = dmLogInitVerboseFct
|
||||||
DmGetNextTarget = dmGetNextTargetFct
|
DmSetDevDir = dmSetDevDirFct
|
||||||
DmLogInitVerbose = dmLogInitVerboseFct
|
DmTaskAddTarget = dmTaskAddTargetFct
|
||||||
DmSetDevDir = dmSetDevDirFct
|
DmTaskCreate = dmTaskCreateFct
|
||||||
DmTaskAddTarget = dmTaskAddTargetFct
|
DmTaskDestroy = dmTaskDestroyFct
|
||||||
DmTaskCreate = dmTaskCreateFct
|
DmTaskGetInfo = dmTaskGetInfoFct
|
||||||
DmTaskDestroy = dmTaskDestroyFct
|
DmTaskRun = dmTaskRunFct
|
||||||
DmTaskGetInfo = dmTaskGetInfoFct
|
DmTaskSetAddNode = dmTaskSetAddNodeFct
|
||||||
DmTaskRun = dmTaskRunFct
|
DmTaskSetCookie = dmTaskSetCookieFct
|
||||||
DmTaskSetAddNode = dmTaskSetAddNodeFct
|
DmTaskSetMessage = dmTaskSetMessageFct
|
||||||
DmTaskSetCookie = dmTaskSetCookieFct
|
DmTaskSetName = dmTaskSetNameFct
|
||||||
DmTaskSetMessage = dmTaskSetMessageFct
|
DmTaskSetRo = dmTaskSetRoFct
|
||||||
DmTaskSetName = dmTaskSetNameFct
|
DmTaskSetSector = dmTaskSetSectorFct
|
||||||
DmTaskSetRo = dmTaskSetRoFct
|
DmUdevWait = dmUdevWaitFct
|
||||||
DmTaskSetSector = dmTaskSetSectorFct
|
LogWithErrnoInit = logWithErrnoInitFct
|
||||||
DmUdevWait = dmUdevWaitFct
|
|
||||||
GetBlockSize = getBlockSizeFct
|
|
||||||
LogWithErrnoInit = logWithErrnoInitFct
|
|
||||||
DmGetLoopbackBackingFile = dmGetLoopbackBackingFileFct
|
|
||||||
DmLoopbackSetCapacity = dmLoopbackSetCapacityFct
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func free(p *C.char) {
|
func free(p *C.char) {
|
||||||
|
@ -185,28 +107,26 @@ func dmTaskCreateFct(taskType int) *CDmTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
func dmTaskRunFct(task *CDmTask) int {
|
func dmTaskRunFct(task *CDmTask) int {
|
||||||
return int(C.dm_task_run((*C.struct_dm_task)(task)))
|
ret, _ := C.dm_task_run((*C.struct_dm_task)(task))
|
||||||
|
return int(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dmTaskSetNameFct(task *CDmTask, name string) int {
|
func dmTaskSetNameFct(task *CDmTask, name string) int {
|
||||||
Cname := C.CString(name)
|
Cname := C.CString(name)
|
||||||
defer free(Cname)
|
defer free(Cname)
|
||||||
|
|
||||||
return int(C.dm_task_set_name((*C.struct_dm_task)(task),
|
return int(C.dm_task_set_name((*C.struct_dm_task)(task), Cname))
|
||||||
Cname))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dmTaskSetMessageFct(task *CDmTask, message string) int {
|
func dmTaskSetMessageFct(task *CDmTask, message string) int {
|
||||||
Cmessage := C.CString(message)
|
Cmessage := C.CString(message)
|
||||||
defer free(Cmessage)
|
defer free(Cmessage)
|
||||||
|
|
||||||
return int(C.dm_task_set_message((*C.struct_dm_task)(task),
|
return int(C.dm_task_set_message((*C.struct_dm_task)(task), Cmessage))
|
||||||
Cmessage))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dmTaskSetSectorFct(task *CDmTask, sector uint64) int {
|
func dmTaskSetSectorFct(task *CDmTask, sector uint64) int {
|
||||||
return int(C.dm_task_set_sector((*C.struct_dm_task)(task),
|
return int(C.dm_task_set_sector((*C.struct_dm_task)(task), C.uint64_t(sector)))
|
||||||
C.uint64_t(sector)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
|
func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
|
||||||
|
@ -214,13 +134,11 @@ func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
|
||||||
defer func() {
|
defer func() {
|
||||||
*cookie = uint(cCookie)
|
*cookie = uint(cCookie)
|
||||||
}()
|
}()
|
||||||
return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie,
|
return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie, C.uint16_t(flags)))
|
||||||
C.uint16_t(flags)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dmTaskSetAddNodeFct(task *CDmTask, addNode AddNodeType) int {
|
func dmTaskSetAddNodeFct(task *CDmTask, addNode AddNodeType) int {
|
||||||
return int(C.dm_task_set_add_node((*C.struct_dm_task)(task),
|
return int(C.dm_task_set_add_node((*C.struct_dm_task)(task), C.dm_add_node_t(addNode)))
|
||||||
C.dm_add_node_t(addNode)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dmTaskSetRoFct(task *CDmTask) int {
|
func dmTaskSetRoFct(task *CDmTask) int {
|
||||||
|
@ -236,26 +154,7 @@ func dmTaskAddTargetFct(task *CDmTask,
|
||||||
Cparams := C.CString(params)
|
Cparams := C.CString(params)
|
||||||
defer free(Cparams)
|
defer free(Cparams)
|
||||||
|
|
||||||
return int(C.dm_task_add_target((*C.struct_dm_task)(task),
|
return int(C.dm_task_add_target((*C.struct_dm_task)(task), C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
|
||||||
C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
|
|
||||||
}
|
|
||||||
|
|
||||||
func dmGetLoopbackBackingFileFct(fd uintptr) (uint64, uint64, sysErrno) {
|
|
||||||
var lo64 C.struct_loop_info64
|
|
||||||
_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_GET_STATUS64,
|
|
||||||
uintptr(unsafe.Pointer(&lo64)))
|
|
||||||
return uint64(lo64.lo_device), uint64(lo64.lo_inode), sysErrno(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func dmLoopbackSetCapacityFct(fd uintptr) sysErrno {
|
|
||||||
_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_SET_CAPACITY, 0)
|
|
||||||
return sysErrno(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func dmGetBlockSizeFct(fd uintptr) (int64, sysErrno) {
|
|
||||||
var size int64
|
|
||||||
_, _, err := sysSyscall(sysSysIoctl, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size)))
|
|
||||||
return size, sysErrno(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
|
func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
|
||||||
|
@ -287,30 +186,10 @@ func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64, targ
|
||||||
*params = C.GoString(Cparams)
|
*params = C.GoString(Cparams)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
nextp := C.dm_get_next_target((*C.struct_dm_task)(task),
|
nextp := C.dm_get_next_target((*C.struct_dm_task)(task), unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
|
||||||
unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
|
|
||||||
return uintptr(nextp)
|
return uintptr(nextp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dmAttachLoopDeviceFct(filename string, fd *int) string {
|
|
||||||
cFilename := C.CString(filename)
|
|
||||||
defer free(cFilename)
|
|
||||||
|
|
||||||
var cFd C.int
|
|
||||||
defer func() {
|
|
||||||
*fd = int(cFd)
|
|
||||||
}()
|
|
||||||
|
|
||||||
ret := C.attach_loop_device(cFilename, &cFd)
|
|
||||||
defer free(ret)
|
|
||||||
return C.GoString(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBlockSizeFct(fd uintptr, size *uint64) sysErrno {
|
|
||||||
_, _, err := sysSyscall(sysSysIoctl, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size)))
|
|
||||||
return sysErrno(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func dmUdevWaitFct(cookie uint) int {
|
func dmUdevWaitFct(cookie uint) int {
|
||||||
return int(C.dm_udev_wait(C.uint32_t(cookie)))
|
return int(C.dm_udev_wait(C.uint32_t(cookie)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,12 +55,6 @@ func denyAllDevmapper() {
|
||||||
DmGetNextTarget = func(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
|
DmGetNextTarget = func(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
|
||||||
panic("DmGetNextTarget: this method should not be called here")
|
panic("DmGetNextTarget: this method should not be called here")
|
||||||
}
|
}
|
||||||
DmAttachLoopDevice = func(filename string, fd *int) string {
|
|
||||||
panic("DmAttachLoopDevice: this method should not be called here")
|
|
||||||
}
|
|
||||||
DmGetBlockSize = func(fd uintptr) (int64, sysErrno) {
|
|
||||||
panic("DmGetBlockSize: this method should not be called here")
|
|
||||||
}
|
|
||||||
DmUdevWait = func(cookie uint) int {
|
DmUdevWait = func(cookie uint) int {
|
||||||
panic("DmUdevWait: this method should not be called here")
|
panic("DmUdevWait: this method should not be called here")
|
||||||
}
|
}
|
||||||
|
@ -76,9 +70,6 @@ func denyAllDevmapper() {
|
||||||
DmTaskDestroy = func(task *CDmTask) {
|
DmTaskDestroy = func(task *CDmTask) {
|
||||||
panic("DmTaskDestroy: this method should not be called here")
|
panic("DmTaskDestroy: this method should not be called here")
|
||||||
}
|
}
|
||||||
GetBlockSize = func(fd uintptr, size *uint64) sysErrno {
|
|
||||||
panic("GetBlockSize: this method should not be called here")
|
|
||||||
}
|
|
||||||
LogWithErrnoInit = func() {
|
LogWithErrnoInit = func() {
|
||||||
panic("LogWithErrnoInit: this method should not be called here")
|
panic("LogWithErrnoInit: this method should not be called here")
|
||||||
}
|
}
|
||||||
|
@ -155,11 +146,10 @@ func (r Set) Assert(t *testing.T, names ...string) {
|
||||||
|
|
||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
calls = make(Set)
|
calls = make(Set)
|
||||||
devicesAttached = make(Set)
|
taskMessages = make(Set)
|
||||||
taskMessages = make(Set)
|
taskTypes = make(Set)
|
||||||
taskTypes = make(Set)
|
home = mkTestDirectory(t)
|
||||||
home = mkTestDirectory(t)
|
|
||||||
)
|
)
|
||||||
defer osRemoveAll(home)
|
defer osRemoveAll(home)
|
||||||
|
|
||||||
|
@ -233,29 +223,6 @@ func TestInit(t *testing.T) {
|
||||||
taskMessages[message] = true
|
taskMessages[message] = true
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
var (
|
|
||||||
fakeDataLoop = "/dev/loop42"
|
|
||||||
fakeMetadataLoop = "/dev/loop43"
|
|
||||||
fakeDataLoopFd = 42
|
|
||||||
fakeMetadataLoopFd = 43
|
|
||||||
)
|
|
||||||
var attachCount int
|
|
||||||
DmAttachLoopDevice = func(filename string, fd *int) string {
|
|
||||||
calls["DmAttachLoopDevice"] = true
|
|
||||||
if _, exists := devicesAttached[filename]; exists {
|
|
||||||
t.Fatalf("Already attached %s", filename)
|
|
||||||
}
|
|
||||||
devicesAttached[filename] = true
|
|
||||||
// This will crash if fd is not dereferenceable
|
|
||||||
if attachCount == 0 {
|
|
||||||
attachCount++
|
|
||||||
*fd = fakeDataLoopFd
|
|
||||||
return fakeDataLoop
|
|
||||||
} else {
|
|
||||||
*fd = fakeMetadataLoopFd
|
|
||||||
return fakeMetadataLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DmTaskDestroy = func(task *CDmTask) {
|
DmTaskDestroy = func(task *CDmTask) {
|
||||||
calls["DmTaskDestroy"] = true
|
calls["DmTaskDestroy"] = true
|
||||||
expectedTask := &task1
|
expectedTask := &task1
|
||||||
|
@ -263,14 +230,6 @@ func TestInit(t *testing.T) {
|
||||||
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
|
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fakeBlockSize := int64(4242 * 512)
|
|
||||||
DmGetBlockSize = func(fd uintptr) (int64, sysErrno) {
|
|
||||||
calls["DmGetBlockSize"] = true
|
|
||||||
if expectedFd := uintptr(42); fd != expectedFd {
|
|
||||||
t.Fatalf("Wrong libdevmapper call\nExpected: DmGetBlockSize(%v)\nReceived: DmGetBlockSize(%v)\n", expectedFd, fd)
|
|
||||||
}
|
|
||||||
return fakeBlockSize, 0
|
|
||||||
}
|
|
||||||
DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
|
DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
|
||||||
calls["DmTaskSetTarget"] = true
|
calls["DmTaskSetTarget"] = true
|
||||||
expectedTask := &task1
|
expectedTask := &task1
|
||||||
|
@ -345,11 +304,9 @@ func TestInit(t *testing.T) {
|
||||||
"DmTaskSetName",
|
"DmTaskSetName",
|
||||||
"DmTaskRun",
|
"DmTaskRun",
|
||||||
"DmTaskGetInfo",
|
"DmTaskGetInfo",
|
||||||
"DmAttachLoopDevice",
|
|
||||||
"DmTaskDestroy",
|
"DmTaskDestroy",
|
||||||
"execRun",
|
"execRun",
|
||||||
"DmTaskCreate",
|
"DmTaskCreate",
|
||||||
"DmGetBlockSize",
|
|
||||||
"DmTaskSetTarget",
|
"DmTaskSetTarget",
|
||||||
"DmTaskSetCookie",
|
"DmTaskSetCookie",
|
||||||
"DmUdevWait",
|
"DmUdevWait",
|
||||||
|
@ -357,7 +314,6 @@ func TestInit(t *testing.T) {
|
||||||
"DmTaskSetMessage",
|
"DmTaskSetMessage",
|
||||||
"DmTaskSetAddNode",
|
"DmTaskSetAddNode",
|
||||||
)
|
)
|
||||||
devicesAttached.Assert(t, path.Join(home, "devicemapper", "data"), path.Join(home, "devicemapper", "metadata"))
|
|
||||||
taskTypes.Assert(t, "0", "6", "17")
|
taskTypes.Assert(t, "0", "6", "17")
|
||||||
taskMessages.Assert(t, "create_thin 0", "set_transaction_id 0 1")
|
taskMessages.Assert(t, "create_thin 0", "set_transaction_id 0 1")
|
||||||
}
|
}
|
||||||
|
@ -408,17 +364,9 @@ func mockAllDevmapper(calls Set) {
|
||||||
calls["DmTaskSetMessage"] = true
|
calls["DmTaskSetMessage"] = true
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
DmAttachLoopDevice = func(filename string, fd *int) string {
|
|
||||||
calls["DmAttachLoopDevice"] = true
|
|
||||||
return "/dev/loop42"
|
|
||||||
}
|
|
||||||
DmTaskDestroy = func(task *CDmTask) {
|
DmTaskDestroy = func(task *CDmTask) {
|
||||||
calls["DmTaskDestroy"] = true
|
calls["DmTaskDestroy"] = true
|
||||||
}
|
}
|
||||||
DmGetBlockSize = func(fd uintptr) (int64, sysErrno) {
|
|
||||||
calls["DmGetBlockSize"] = true
|
|
||||||
return int64(4242 * 512), 0
|
|
||||||
}
|
|
||||||
DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
|
DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
|
||||||
calls["DmTaskSetTarget"] = true
|
calls["DmTaskSetTarget"] = true
|
||||||
return 1
|
return 1
|
||||||
|
@ -489,6 +437,32 @@ func TestDriverCreate(t *testing.T) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||||
|
calls["sysSyscall"] = true
|
||||||
|
if trap != sysSysIoctl {
|
||||||
|
t.Fatalf("Unexpected syscall. Expecting SYS_IOCTL, received: %d", trap)
|
||||||
|
}
|
||||||
|
switch a2 {
|
||||||
|
case LoopSetFd:
|
||||||
|
calls["ioctl.loopsetfd"] = true
|
||||||
|
case LoopCtlGetFree:
|
||||||
|
calls["ioctl.loopctlgetfree"] = true
|
||||||
|
case LoopGetStatus64:
|
||||||
|
calls["ioctl.loopgetstatus"] = true
|
||||||
|
case LoopSetStatus64:
|
||||||
|
calls["ioctl.loopsetstatus"] = true
|
||||||
|
case LoopClrFd:
|
||||||
|
calls["ioctl.loopclrfd"] = true
|
||||||
|
case LoopSetCapacity:
|
||||||
|
calls["ioctl.loopsetcapacity"] = true
|
||||||
|
case BlkGetSize64:
|
||||||
|
calls["ioctl.blkgetsize"] = true
|
||||||
|
default:
|
||||||
|
t.Fatalf("Unexpected IOCTL. Received %d", a2)
|
||||||
|
}
|
||||||
|
return 0, 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
func() {
|
func() {
|
||||||
d := newDriver(t)
|
d := newDriver(t)
|
||||||
|
|
||||||
|
@ -498,16 +472,18 @@ func TestDriverCreate(t *testing.T) {
|
||||||
"DmTaskSetName",
|
"DmTaskSetName",
|
||||||
"DmTaskRun",
|
"DmTaskRun",
|
||||||
"DmTaskGetInfo",
|
"DmTaskGetInfo",
|
||||||
"DmAttachLoopDevice",
|
|
||||||
"execRun",
|
"execRun",
|
||||||
"DmTaskCreate",
|
"DmTaskCreate",
|
||||||
"DmGetBlockSize",
|
|
||||||
"DmTaskSetTarget",
|
"DmTaskSetTarget",
|
||||||
"DmTaskSetCookie",
|
"DmTaskSetCookie",
|
||||||
"DmUdevWait",
|
"DmUdevWait",
|
||||||
"DmTaskSetSector",
|
"DmTaskSetSector",
|
||||||
"DmTaskSetMessage",
|
"DmTaskSetMessage",
|
||||||
"DmTaskSetAddNode",
|
"DmTaskSetAddNode",
|
||||||
|
"sysSyscall",
|
||||||
|
"ioctl.blkgetsize",
|
||||||
|
"ioctl.loopsetfd",
|
||||||
|
"ioctl.loopsetstatus",
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := d.Create("1", ""); err != nil {
|
if err := d.Create("1", ""); err != nil {
|
||||||
|
@ -579,6 +555,32 @@ func TestDriverRemove(t *testing.T) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||||
|
calls["sysSyscall"] = true
|
||||||
|
if trap != sysSysIoctl {
|
||||||
|
t.Fatalf("Unexpected syscall. Expecting SYS_IOCTL, received: %d", trap)
|
||||||
|
}
|
||||||
|
switch a2 {
|
||||||
|
case LoopSetFd:
|
||||||
|
calls["ioctl.loopsetfd"] = true
|
||||||
|
case LoopCtlGetFree:
|
||||||
|
calls["ioctl.loopctlgetfree"] = true
|
||||||
|
case LoopGetStatus64:
|
||||||
|
calls["ioctl.loopgetstatus"] = true
|
||||||
|
case LoopSetStatus64:
|
||||||
|
calls["ioctl.loopsetstatus"] = true
|
||||||
|
case LoopClrFd:
|
||||||
|
calls["ioctl.loopclrfd"] = true
|
||||||
|
case LoopSetCapacity:
|
||||||
|
calls["ioctl.loopsetcapacity"] = true
|
||||||
|
case BlkGetSize64:
|
||||||
|
calls["ioctl.blkgetsize"] = true
|
||||||
|
default:
|
||||||
|
t.Fatalf("Unexpected IOCTL. Received %d", a2)
|
||||||
|
}
|
||||||
|
return 0, 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
func() {
|
func() {
|
||||||
d := newDriver(t)
|
d := newDriver(t)
|
||||||
|
|
||||||
|
@ -588,16 +590,18 @@ func TestDriverRemove(t *testing.T) {
|
||||||
"DmTaskSetName",
|
"DmTaskSetName",
|
||||||
"DmTaskRun",
|
"DmTaskRun",
|
||||||
"DmTaskGetInfo",
|
"DmTaskGetInfo",
|
||||||
"DmAttachLoopDevice",
|
|
||||||
"execRun",
|
"execRun",
|
||||||
"DmTaskCreate",
|
"DmTaskCreate",
|
||||||
"DmGetBlockSize",
|
|
||||||
"DmTaskSetTarget",
|
"DmTaskSetTarget",
|
||||||
"DmTaskSetCookie",
|
"DmTaskSetCookie",
|
||||||
"DmUdevWait",
|
"DmUdevWait",
|
||||||
"DmTaskSetSector",
|
"DmTaskSetSector",
|
||||||
"DmTaskSetMessage",
|
"DmTaskSetMessage",
|
||||||
"DmTaskSetAddNode",
|
"DmTaskSetAddNode",
|
||||||
|
"sysSyscall",
|
||||||
|
"ioctl.blkgetsize",
|
||||||
|
"ioctl.loopsetfd",
|
||||||
|
"ioctl.loopsetstatus",
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := d.Create("1", ""); err != nil {
|
if err := d.Create("1", ""); err != nil {
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package devmapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ioctlLoopCtlGetFree(fd uintptr) (int, error) {
|
||||||
|
index, _, err := sysSyscall(sysSysIoctl, fd, LoopCtlGetFree, 0)
|
||||||
|
if err != 0 {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(index), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {
|
||||||
|
if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetFd, sparseFd); err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ioctlLoopSetStatus64(loopFd uintptr, loopInfo *LoopInfo64) error {
|
||||||
|
if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ioctlLoopClrFd(loopFd uintptr) error {
|
||||||
|
if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopClrFd, 0); err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ioctlLoopGetStatus64(loopFd uintptr) (*LoopInfo64, error) {
|
||||||
|
loopInfo := &LoopInfo64{}
|
||||||
|
|
||||||
|
if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopGetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return loopInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ioctlLoopSetCapacity(loopFd uintptr, value int) error {
|
||||||
|
if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetCapacity, uintptr(value)); err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ioctlBlkGetSize64(fd uintptr) (int64, error) {
|
||||||
|
var size int64
|
||||||
|
if _, _, err := sysSyscall(sysSysIoctl, fd, BlkGetSize64, uintptr(unsafe.Pointer(&size))); err != 0 {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return size, nil
|
||||||
|
}
|
|
@ -19,7 +19,11 @@ var (
|
||||||
sysCloseOnExec = syscall.CloseOnExec
|
sysCloseOnExec = syscall.CloseOnExec
|
||||||
sysSyscall = syscall.Syscall
|
sysSyscall = syscall.Syscall
|
||||||
|
|
||||||
osOpenFile = os.OpenFile
|
osOpenFile = func(name string, flag int, perm os.FileMode) (*osFile, error) {
|
||||||
|
f, err := os.OpenFile(name, flag, perm)
|
||||||
|
return &osFile{File: f}, err
|
||||||
|
}
|
||||||
|
osOpen = func(name string) (*osFile, error) { f, err := os.Open(name); return &osFile{File: f}, err }
|
||||||
osNewFile = os.NewFile
|
osNewFile = os.NewFile
|
||||||
osCreate = os.Create
|
osCreate = os.Create
|
||||||
osStat = os.Stat
|
osStat = os.Stat
|
||||||
|
@ -30,9 +34,7 @@ var (
|
||||||
osRename = os.Rename
|
osRename = os.Rename
|
||||||
osReadlink = os.Readlink
|
osReadlink = os.Readlink
|
||||||
|
|
||||||
execRun = func(name string, args ...string) error {
|
execRun = func(name string, args ...string) error { return exec.Command(name, args...).Run() }
|
||||||
return exec.Command(name, args...).Run()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -40,9 +42,12 @@ const (
|
||||||
sysMsRdOnly = syscall.MS_RDONLY
|
sysMsRdOnly = syscall.MS_RDONLY
|
||||||
sysEInval = syscall.EINVAL
|
sysEInval = syscall.EINVAL
|
||||||
sysSysIoctl = syscall.SYS_IOCTL
|
sysSysIoctl = syscall.SYS_IOCTL
|
||||||
|
sysEBusy = syscall.EBUSY
|
||||||
|
|
||||||
osORdWr = os.O_RDWR
|
osORdOnly = os.O_RDONLY
|
||||||
osOCreate = os.O_CREATE
|
osORdWr = os.O_RDWR
|
||||||
|
osOCreate = os.O_CREATE
|
||||||
|
osModeDevice = os.ModeDevice
|
||||||
)
|
)
|
||||||
|
|
||||||
func toSysStatT(i interface{}) *sysStatT {
|
func toSysStatT(i interface{}) *sysStatT {
|
||||||
|
|
|
@ -19,18 +19,35 @@ fi
|
||||||
bundle_test() {
|
bundle_test() {
|
||||||
{
|
{
|
||||||
date
|
date
|
||||||
for test_dir in $(find_test_dirs); do (
|
|
||||||
set -x
|
TESTS_FAILED=()
|
||||||
cd $test_dir
|
for test_dir in $(find_test_dirs); do
|
||||||
|
echo
|
||||||
|
|
||||||
# Install packages that are dependencies of the tests.
|
if ! (
|
||||||
# Note: Does not run the tests.
|
set -x
|
||||||
go test -i -ldflags "$LDFLAGS" $BUILDFLAGS
|
cd $test_dir
|
||||||
|
|
||||||
# Run the tests with the optional $TESTFLAGS.
|
# Install packages that are dependencies of the tests.
|
||||||
export TEST_DOCKERINIT_PATH=$DEST/../dynbinary/dockerinit-$VERSION
|
# Note: Does not run the tests.
|
||||||
go test -v -ldflags "$LDFLAGS -X github.com/dotcloud/docker/utils.INITSHA1 \"$DOCKER_INITSHA1\"" $BUILDFLAGS $TESTFLAGS
|
go test -i -ldflags "$LDFLAGS" $BUILDFLAGS
|
||||||
) done
|
|
||||||
|
# Run the tests with the optional $TESTFLAGS.
|
||||||
|
export TEST_DOCKERINIT_PATH=$DEST/../dynbinary/dockerinit-$VERSION
|
||||||
|
go test -v -ldflags "$LDFLAGS -X github.com/dotcloud/docker/utils.INITSHA1 \"$DOCKER_INITSHA1\"" $BUILDFLAGS $TESTFLAGS
|
||||||
|
); then
|
||||||
|
TESTS_FAILED+=("$test_dir")
|
||||||
|
sleep 1 # give it a second, so observers watching can take note
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# if some tests fail, we want the bundlescript to fail, but we want to
|
||||||
|
# try running ALL the tests first, hence TESTS_FAILED
|
||||||
|
if [ "${#TESTS_FAILED[@]}" -gt 0 ]; then
|
||||||
|
echo
|
||||||
|
echo "Test failures in: ${TESTS_FAILED[@]}"
|
||||||
|
false
|
||||||
|
fi
|
||||||
} 2>&1 | tee $DEST/test.log
|
} 2>&1 | tee $DEST/test.log
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,17 +13,34 @@ set -e
|
||||||
bundle_test() {
|
bundle_test() {
|
||||||
{
|
{
|
||||||
date
|
date
|
||||||
for test_dir in $(find_test_dirs); do (
|
|
||||||
set -x
|
TESTS_FAILED=()
|
||||||
cd $test_dir
|
for test_dir in $(find_test_dirs); do
|
||||||
|
echo
|
||||||
|
|
||||||
# Install packages that are dependencies of the tests.
|
if ! (
|
||||||
# Note: Does not run the tests.
|
set -x
|
||||||
go test -i -ldflags "$LDFLAGS $LDFLAGS_STATIC" $BUILDFLAGS
|
cd $test_dir
|
||||||
|
|
||||||
# Run the tests with the optional $TESTFLAGS.
|
# Install packages that are dependencies of the tests.
|
||||||
go test -v -ldflags "$LDFLAGS $LDFLAGS_STATIC" $BUILDFLAGS $TESTFLAGS
|
# Note: Does not run the tests.
|
||||||
) done
|
go test -i -ldflags "$LDFLAGS $LDFLAGS_STATIC" $BUILDFLAGS
|
||||||
|
|
||||||
|
# Run the tests with the optional $TESTFLAGS.
|
||||||
|
go test -v -ldflags "$LDFLAGS $LDFLAGS_STATIC" $BUILDFLAGS $TESTFLAGS
|
||||||
|
); then
|
||||||
|
TESTS_FAILED+=("$test_dir")
|
||||||
|
sleep 1 # give it a second, so observers watching can take note
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# if some tests fail, we want the bundlescript to fail, but we want to
|
||||||
|
# try running ALL the tests first, hence TESTS_FAILED
|
||||||
|
if [ "${#TESTS_FAILED[@]}" -gt 0 ]; then
|
||||||
|
echo
|
||||||
|
echo "Test failures in: ${TESTS_FAILED[@]}"
|
||||||
|
false
|
||||||
|
fi
|
||||||
} 2>&1 | tee $DEST/test.log
|
} 2>&1 | tee $DEST/test.log
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -483,7 +483,7 @@ func TestForbiddenContextPath(t *testing.T) {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err.Error() != "Forbidden path: /" {
|
if err.Error() != "Forbidden path outside the build context: ../../ (/)" {
|
||||||
t.Logf("Error message is not expected: %s", err.Error())
|
t.Logf("Error message is not expected: %s", err.Error())
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,8 +32,8 @@ lxc.rootfs = {{$ROOTFS}}
|
||||||
|
|
||||||
{{if and .HostnamePath .HostsPath}}
|
{{if and .HostnamePath .HostsPath}}
|
||||||
# enable domain name support
|
# enable domain name support
|
||||||
lxc.mount.entry = {{.HostnamePath}} {{$ROOTFS}}/etc/hostname none bind,ro 0 0
|
lxc.mount.entry = {{escapeFstabSpaces .HostnamePath}} {{escapeFstabSpaces $ROOTFS}}/etc/hostname none bind,ro 0 0
|
||||||
lxc.mount.entry = {{.HostsPath}} {{$ROOTFS}}/etc/hosts none bind,ro 0 0
|
lxc.mount.entry = {{escapeFstabSpaces .HostsPath}} {{escapeFstabSpaces $ROOTFS}}/etc/hosts none bind,ro 0 0
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
# use a dedicated pts for the container (and limit the number of pseudo terminal
|
# use a dedicated pts for the container (and limit the number of pseudo terminal
|
||||||
|
@ -84,27 +85,27 @@ lxc.cgroup.devices.allow = c 10:200 rwm
|
||||||
lxc.pivotdir = lxc_putold
|
lxc.pivotdir = lxc_putold
|
||||||
# WARNING: procfs is a known attack vector and should probably be disabled
|
# WARNING: procfs is a known attack vector and should probably be disabled
|
||||||
# if your userspace allows it. eg. see http://blog.zx2c4.com/749
|
# if your userspace allows it. eg. see http://blog.zx2c4.com/749
|
||||||
lxc.mount.entry = proc {{$ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
|
lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
|
||||||
# WARNING: sysfs is a known attack vector and should probably be disabled
|
# WARNING: sysfs is a known attack vector and should probably be disabled
|
||||||
# if your userspace allows it. eg. see http://bit.ly/T9CkqJ
|
# if your userspace allows it. eg. see http://bit.ly/T9CkqJ
|
||||||
lxc.mount.entry = sysfs {{$ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
|
lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
|
||||||
lxc.mount.entry = devpts {{$ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0
|
lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0
|
||||||
#lxc.mount.entry = varrun {{$ROOTFS}}/var/run tmpfs mode=755,size=4096k,nosuid,nodev,noexec 0 0
|
#lxc.mount.entry = varrun {{escapeFstabSpaces $ROOTFS}}/var/run tmpfs mode=755,size=4096k,nosuid,nodev,noexec 0 0
|
||||||
#lxc.mount.entry = varlock {{$ROOTFS}}/var/lock tmpfs size=1024k,nosuid,nodev,noexec 0 0
|
#lxc.mount.entry = varlock {{escapeFstabSpaces $ROOTFS}}/var/lock tmpfs size=1024k,nosuid,nodev,noexec 0 0
|
||||||
lxc.mount.entry = shm {{$ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
|
lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
|
||||||
|
|
||||||
# Inject dockerinit
|
# Inject dockerinit
|
||||||
lxc.mount.entry = {{.SysInitPath}} {{$ROOTFS}}/.dockerinit none bind,ro 0 0
|
lxc.mount.entry = {{escapeFstabSpaces .SysInitPath}} {{escapeFstabSpaces $ROOTFS}}/.dockerinit none bind,ro 0 0
|
||||||
|
|
||||||
# Inject env
|
# Inject env
|
||||||
lxc.mount.entry = {{.EnvConfigPath}} {{$ROOTFS}}/.dockerenv none bind,ro 0 0
|
lxc.mount.entry = {{escapeFstabSpaces .EnvConfigPath}} {{escapeFstabSpaces $ROOTFS}}/.dockerenv none bind,ro 0 0
|
||||||
|
|
||||||
# In order to get a working DNS environment, mount bind (ro) the host's /etc/resolv.conf into the container
|
# In order to get a working DNS environment, mount bind (ro) the host's /etc/resolv.conf into the container
|
||||||
lxc.mount.entry = {{.ResolvConfPath}} {{$ROOTFS}}/etc/resolv.conf none bind,ro 0 0
|
lxc.mount.entry = {{escapeFstabSpaces .ResolvConfPath}} {{escapeFstabSpaces $ROOTFS}}/etc/resolv.conf none bind,ro 0 0
|
||||||
{{if .Volumes}}
|
{{if .Volumes}}
|
||||||
{{ $rw := .VolumesRW }}
|
{{ $rw := .VolumesRW }}
|
||||||
{{range $virtualPath, $realPath := .Volumes}}
|
{{range $virtualPath, $realPath := .Volumes}}
|
||||||
lxc.mount.entry = {{$realPath}} {{$ROOTFS}}/{{$virtualPath}} none bind,{{ if index $rw $virtualPath }}rw{{else}}ro{{end}} 0 0
|
lxc.mount.entry = {{escapeFstabSpaces $realPath}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $virtualPath}} none bind,{{ if index $rw $virtualPath }}rw{{else}}ro{{end}} 0 0
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
@ -144,6 +145,12 @@ lxc.cgroup.cpu.shares = {{.Config.CpuShares}}
|
||||||
|
|
||||||
var LxcTemplateCompiled *template.Template
|
var LxcTemplateCompiled *template.Template
|
||||||
|
|
||||||
|
// Escape spaces in strings according to the fstab documentation, which is the
|
||||||
|
// format for "lxc.mount.entry" lines in lxc.conf. See also "man 5 fstab".
|
||||||
|
func escapeFstabSpaces(field string) string {
|
||||||
|
return strings.Replace(field, " ", "\\040", -1)
|
||||||
|
}
|
||||||
|
|
||||||
func getMemorySwap(config *Config) int64 {
|
func getMemorySwap(config *Config) int64 {
|
||||||
// By default, MemorySwap is set to twice the size of RAM.
|
// By default, MemorySwap is set to twice the size of RAM.
|
||||||
// If you want to omit MemorySwap, set it to `-1'.
|
// If you want to omit MemorySwap, set it to `-1'.
|
||||||
|
@ -164,9 +171,10 @@ func getCapabilities(container *Container) *Capabilities {
|
||||||
func init() {
|
func init() {
|
||||||
var err error
|
var err error
|
||||||
funcMap := template.FuncMap{
|
funcMap := template.FuncMap{
|
||||||
"getMemorySwap": getMemorySwap,
|
"getMemorySwap": getMemorySwap,
|
||||||
"getHostConfig": getHostConfig,
|
"getHostConfig": getHostConfig,
|
||||||
"getCapabilities": getCapabilities,
|
"getCapabilities": getCapabilities,
|
||||||
|
"escapeFstabSpaces": escapeFstabSpaces,
|
||||||
}
|
}
|
||||||
LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
|
LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -100,3 +100,21 @@ func grepFile(t *testing.T, path string, pattern string) {
|
||||||
}
|
}
|
||||||
t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
|
t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEscapeFstabSpaces(t *testing.T) {
|
||||||
|
var testInputs = map[string]string{
|
||||||
|
" ": "\\040",
|
||||||
|
"": "",
|
||||||
|
"/double space": "/double\\040\\040space",
|
||||||
|
"/some long test string": "/some\\040long\\040test\\040string",
|
||||||
|
"/var/lib/docker": "/var/lib/docker",
|
||||||
|
" leading": "\\040leading",
|
||||||
|
"trailing ": "trailing\\040",
|
||||||
|
}
|
||||||
|
for in, exp := range testInputs {
|
||||||
|
if out := escapeFstabSpaces(in); exp != out {
|
||||||
|
t.Logf("Expected %s got %s", exp, out)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1011,16 +1011,9 @@ func (srv *Server) ImagePull(localName string, tag string, out io.Writer, sf *ut
|
||||||
localName = remoteName
|
localName = remoteName
|
||||||
}
|
}
|
||||||
|
|
||||||
err = srv.pullRepository(r, out, localName, remoteName, tag, endpoint, sf, parallel)
|
if err = srv.pullRepository(r, out, localName, remoteName, tag, endpoint, sf, parallel); err != nil {
|
||||||
if err == registry.ErrLoginRequired {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
if err := srv.pullImage(r, out, remoteName, endpoint, nil, sf); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidState = errors.New("Invlid terminal state")
|
ErrInvalidState = errors.New("Invalid terminal state")
|
||||||
)
|
)
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
|
|
Loading…
Reference in New Issue