{"id":28578855,"url":"https://github.com/syhpoon/xenvman","last_synced_at":"2025-06-11T01:11:15.127Z","repository":{"id":34073330,"uuid":"143100676","full_name":"syhpoon/xenvman","owner":"syhpoon","description":"Environment manager for testing containers and microservices","archived":false,"fork":false,"pushed_at":"2023-01-03T15:57:33.000Z","size":6462,"stargazers_count":12,"open_issues_count":24,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-09-28T09:19:08.209Z","etag":null,"topics":["containers","docker","integration-testing","microservices","testing"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/syhpoon.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-08-01T03:45:10.000Z","updated_at":"2022-03-29T14:03:52.000Z","dependencies_parsed_at":"2023-01-15T04:31:03.916Z","dependency_job_id":null,"html_url":"https://github.com/syhpoon/xenvman","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/syhpoon%2Fxenvman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/syhpoon%2Fxenvman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/syhpoon%2Fxenvman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/syhpoon%2Fxenvman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/syhpoon","download_url":"https://codeload.github.com/syhpoon/xenvman/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/syhpoon%2Fxenvman/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259178542,"owners_count":22817389,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["containers","docker","integration-testing","microservices","testing"],"created_at":"2025-06-11T01:11:13.476Z","updated_at":"2025-06-11T01:11:15.110Z","avatar_url":"https://github.com/syhpoon.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/syhpoon/xenvman.svg?branch=master)](https://travis-ci.org/syhpoon/xenvman)\n[![codecov](https://codecov.io/gh/syhpoon/xenvman/branch/master/graph/badge.svg)](https://codecov.io/gh/syhpoon/xenvman)\n[![Go Report Card](https://goreportcard.com/badge/github.com/syhpoon/xenvman)](https://goreportcard.com/report/github.com/syhpoon/xenvman)\n\nTable of Contents\n=================\n\n   * [Overview](#overview)\n   * [Installation](#installation)\n      * [Download release](#download-release)\n      * [Compilation from source](#compilation-from-source)\n      * [Configuration](#configuration)\n         * [Configuration file](#configuration-file)\n         * [Environment](#environment)\n         * [api_auth (XENVMAN_API_AUTH) [\"\"]](#api_auth-xenvman_api_auth-)\n         * [auth_basic [\"\"]](#auth_basic-)\n         * [container_engine (XENVMAN_CONTAINER_ENGINE) [\"docker\"]](#container_engine-xenvman_container_engine-docker)\n         * [export_address (XENVMAN_EXPORT_ADDRESS) [\"localhost\"]](#export_address-xenvman_export_address-localhost)\n         * [keepalive (XENVMAN_KEEPALIVE) [\"2m\"]](#keepalive-xenvman_keepalive-2m)\n         * [listen (XENVMAN_LISTEN) [\":9876\"]](#listen-xenvman_listen-9876)\n         * [ports_range (XENVMAN_PORTS_RANGE) [[20000, 30000]]](#ports_range-xenvman_ports_range-20000-30000)\n         * [tpl.base_dir (XENVMAN_TPL_BASE_DIR) [\"\"]](#tplbase_dir-xenvman_tpl_base_dir-)\n         * [tpl.ws_dir (XENVMAN_TPL_WS_DIR) [\"\"]](#tplws_dir-xenvman_tpl_ws_dir-)\n         * [tpl.mount_dir (XENVMAN_TPL_MOUNT_DIR) [\"\"]](#tplmount_dir-xenvman_tpl_mount_dir-)\n         * [tls.cert (XENVMAN_TLS_CERT) [\"\"]](#tlscert-xenvman_tls_cert-)\n         * [tls.key (XENVMAN_TLS_key) [\"\"]](#tlskey-xenvman_tls_key-)\n      * [Running API server](#running-api-server)\n   * [Environments](#environments)\n   * [Templates](#templates)\n      * [Data directory](#data-directory)\n      * [Workspace directory](#workspace-directory)\n      * [Mount directory](#mount-directory)\n      * [Template directories summary](#template-directories-summary)\n      * [Javascript API](#javascript-api)\n         * [Template format](#template-format)\n         * [Template API](#template-api)\n            * [BuildImage(name :: string) -\u0026gt; \u003ca href=\"#BuildImage-API\"\u003eBuildImage\u003c/a\u003e](#buildimagename--string---buildimage)\n            * [FetchImage(name :: string) -\u0026gt; \u003ca href=\"#FetchImage-API\"\u003eFetchImage\u003c/a\u003e](#fetchimagename--string---fetchimage)\n            * [AddReadinessCheck(name :: string, params :: object) -\u0026gt; null](#addreadinesscheckname--string-params--object---null)\n         * [BuildImage API](#buildimage-api)\n            * [CopyDataToWorkspace(path :: string...) -\u0026gt; null](#copydatatoworkspacepath--string---null)\n            * [AddFileToWorkspace(path :: string, data :: string, mode int) -\u0026gt; null](#addfiletoworkspacepath--string-data--string-mode-int---null)\n            * [InterpolateWorkspaceFile(file :: string, data :: object) -\u0026gt; null](#interpolateworkspacefilefile--string-data--object---null)\n            * [NewContainer(name :: string) -\u0026gt; \u003ca href=\"#Container-API\"\u003eContainer\u003c/a\u003e](#newcontainername--string---container)\n         * [FetchImage API](#fetchimage-api)\n            * [NewContainer(name :: string) -\u0026gt; \u003ca href=\"#Container-API\"\u003eContainer\u003c/a\u003e](#newcontainername--string---container-1)\n         * [Container API](#container-api)\n            * [SetEnv(env, val :: string) -\u0026gt; null](#setenvenv-val--string---null)\n            * [SetLabel(key :: string, value :: {string, number}) -\u0026gt; null](#setlabelkey--string-value--string-number---null)\n            * [SetCmd(cmd :: string...) -\u0026gt; null](#setcmdcmd--string---null)\n            * [SetEntrypoint(cmd :: string...) -\u0026gt; null](#setentrypointcmd--string---null)\n            * [SetPorts(port :: number...) -\u0026gt; null](#setportsport--number---null)\n            * [MountString(data, contFile :: string, mode :: int, opts :: object) -\u0026gt; null](#mountstringdata-contfile--string-mode--int-opts--object---null)\n            * [MountData(dataFile, contFile :: string, opts :: object) -\u0026gt; null](#mountdatadatafile-contfile--string-opts--object---null)\n         * [Readiness checks](#readiness-checks)\n            * [http](#http)\n            * [net](#net)\n         * [Helper JS functions](#helper-js-functions)\n            * [fmt(format :: string, args :: any...)](#fmtformat--string-args--any)\n            * [type](#type)\n               * [type.EnsureString(arg :: any)](#typeensurestringarg--any)\n               * [type.EnsureNumber(arg :: any)](#typeensurenumberarg--any)\n               * [type.EnsureListOfStrings(arg :: any)](#typeensurelistofstringsarg--any)\n               * [type.EnsureListOfNumbers(arg :: any)](#typeensurelistofnumbersarg--any)\n               * [type.FromBase64(name :: string, value :: string)](#typefrombase64name--string-value--string)\n               * [type.IsArray(arg :: any)](#typeisarrayarg--any)\n               * [type.IsDefined(arg :: any)](#typeisdefinedarg--any)\n      * [Interpolation](#interpolation)\n         * [Workspace files interpolation](#workspace-files-interpolation)\n         * [Mounted files, readiness checks \u0026amp; environ interpolation](#mounted-files-readiness-checks--environ-interpolation)\n            * [.Self -\u0026gt; Container](#self---container)\n            * [.Extra -\u0026gt; Any](#extra---any)\n            * [.ExternalAddress -\u0026gt; string](#externaladdress---string)\n            * [.ContainersWithLabels(label : string, value : string) -\u0026gt; [Container]](#containerswithlabelslabel--string-value--string---container)\n            * [.ContainerWithLabel(label : string, value : string) -\u0026gt; Container](#containerwithlabellabel--string-value--string---container)\n            * [.AllContainers() -\u0026gt; [Container]](#allcontainers---container)\n            * [Container instance methods](#container-instance-methods)\n               * [.IP -\u0026gt; string](#ip---string)\n               * [.Hostname -\u0026gt; string](#hostname---string)\n               * [.Name -\u0026gt; string](#name---string)\n               * [.GetLabel(label : string) -\u0026gt; string](#getlabellabel--string---string)\n               * [.ExposedPort(iport : int) -\u0026gt; int](#exposedportiport--int---int)\n   * [HTTP API](#http-api)\n      * [GET /api/v1/env](#get-apiv1env)\n         * [Response body](#response-body)\n      * [POST /api/v1/env](#post-apiv1env)\n         * [Body](#body)\n         * [Response body](#response-body-1)\n      * [GET /api/v1/env/{id}](#get-apiv1envid)\n         * [Response body](#response-body-2)\n      * [PATCH /api/v1/env/{id}](#patch-apiv1envid)\n         * [Body](#body-1)\n         * [Response body](#response-body-3)\n      * [DELETE /api/v1/env/{id}](#delete-apiv1envid)\n         * [Query parameters](#query-parameters)\n      * [POST /api/v1/env/{id}/keepalive](#post-apiv1envidkeepalive)\n      * [GET /api/v1/tpl](#get-apiv1tpl)\n         * [Response body](#response-body-4)\n      * [Types](#types)\n         * [InputEnv](#inputenv)\n         * [InputEnvOptions](#inputenvoptions)\n         * [OutputEnv](#outputenv)\n         * [PatchEnv](#patchenv)\n         * [InputTpl](#inputtpl)\n         * [TplData](#tpldata)\n         * [ContainerData](#containerdata)\n         * [TplInfo](#tplinfo)\n         * [TplInfoParam](#tplinfoparam)\n   * [Dynamic discovery](#dynamic-discovery)\n   * [Dynamic environment reconfiguration](#dynamic-environment-reconfiguration)\n   * [Web UI](#web-ui)\n   * [Clients](#clients)\n      * [Golang](#golang)\n      * [Python](#python)\n\n# Overview\n\n`xenvman` is an extensible environment manager which is used to\ncreate environments for testing microservices.\n\n![Overview](docs/img/overview.png)\n\nxenvman can be used to:\n\n* Define environment templates using JavaScript\n* Create images on the fly\n* Spawn as many containers as needed inside an environment\n* Link containers together in a single isolated network\n* Expose container ports for external access\n* Dynamically change environment composition (add, stop, restart containers) on the fly\n\nFor a detailed example take a look at [tutorial](http://syhpoon.ca/posts/xenvman-tutorial/).\n\n# Installation\n\nPlease note, that even though `xenvman` binaries are provided for both\nLinux and MacOS, at the moment only Linux is officially supported.\n\n## Download release\n\nSimply download the latest available binary for your OS/platform\nfrom [here](https://github.com/syhpoon/xenvman/releases),\nrename the binary to `xenvman` and place anywhere in your `$PATH`.\n\n## Compilation from source\n\nIn order to compile `xenvman` from source you must have installed\n[Golang](https://golang.org/) with the minimum version of `1.11`.\n\n`xenvman` uses new feature introduced in Go version `1.11` - \n[Modules](https://github.com/golang/go/wiki/Modules) and so you can\nclone the sources anywhere, no need to do it into `$GOPATH`.\n\nThe build process is super simple:\n```bash\n$ cd ~ \u0026\u0026 git clone https://github.com/syhpoon/xenvman.git \u0026\u0026 cd xenvman\n$ make test \u0026\u0026 make build\n```\n\nIf everything is good, there will be a `xenvman` executable in\nthe project root, which you can copy anywhere in your `$PATH`\nand that would be it for the installation.\n\n## Configuration\n\nThere are two ways to provide configuration: configuration file or\nenvironment variables.\n\n### Configuration file\n\n`xenvman` uses [toml](https://github.com/toml-lang/toml) as a configuration\nformat. Most of the configuration parameters have reasonable default\nvalues so you can run the program even without supplying any configuration\nat all. An example file with all the available options can\nbe found [here](https://github.com/syhpoon/xenvman/blob/master/etc/xenvman.toml).\n\nIn order to provide custom configuration, create a `xenvman.toml` file\nanywhere you like and run the server with `-c` option:\n\n`xenvman run -c \u003cpath-to-xenvman.toml\u003e`\n\n### Environment\n\nConfiguration parameters can also be provided using environment variables.\nThe variable must be a capitalized version of config param with a special\n`XENVMAN_` prefix.\n\nFor example, setting server listen address port can be done\nusing these both ways:\n\n`listen = \":9876\"` using configuration file, or\n\n`XENVMAN_LISTEN=\":9876\"` - using env.\n\n`Please note`: use underscore (`_`) to separate nested fields when using env,\nnot dots.\n\n### api_auth (XENVMAN_API_AUTH) [\"\"]\n\nType of authentication backend to use.\nAvailable types include:\n\n* `basic` - HTTP basic auth\n\n### auth_basic [\"\"]\n\nSection specifying mapping from usernames to passwords for http basic auth.\n\n### container_engine (XENVMAN_CONTAINER_ENGINE) [\"docker\"]\n\nType of container engine to use.\nCurrently only `docker` is supported.\n\n### export_address (XENVMAN_EXPORT_ADDRESS) [\"localhost\"]\n\nThe external address to expose to clients.\n\n### keepalive (XENVMAN_KEEPALIVE) [\"2m\"]\n\nDefault environment keepalive\n\n### listen (XENVMAN_LISTEN) [\":9876\"]\n\nIP:port to listen on.\nIf `IP` is ommitted, `localhost` will be used.\n\n### ports_range (XENVMAN_PORTS_RANGE) [[20000, 30000]]\n\nA port range from which to take exposed ports,\nspecified as a list of two [min, max] numbers.\n\n### tpl.base_dir (XENVMAN_TPL_BASE_DIR) [\"\"]\n\nBase directory where to search for [templates](#Templates).\n\n### tpl.ws_dir (XENVMAN_TPL_WS_DIR) [\"\"]\n\nBase directory where temporary image [workspaces](#Workspace-directory)\nwill be created.\n\n### tpl.mount_dir (XENVMAN_TPL_MOUNT_DIR) [\"\"]\n\nBase directory where temporary container [mount dirs](#Mount-directory)\nwill be created.\n\n### tls.cert (XENVMAN_TLS_CERT) [\"\"]\n\nPath to TLS certificate file. If not set, TLS mode will not be used.\n\n### tls.key (XENVMAN_TLS_key) [\"\"]\n\nPath to TLS privatet key file. If not set, TLS mode will not be used.\n\n## Running API server\n\nRunning `xenvman` server is very simple:\n\n1. When using configuration file: `xenvman run -c \u003cpath-to-xenvman.toml\u003e`\n2. When using env variables: `XENVMAN_\u003cPARAM\u003e=\u003cVALUE\u003e xenvman run`\n\n# Environments\n\nEnvironment is an isolated bubble where one or more containers can be run \ntogether in order to provide a necessary playground for integration testing.\n\nEnvironments are created, managed and destroyed using HTTP API provided\nby running `xenvman` server.\n\n`Please note`: here environment is `NOT` the usual shell one.\n\n# Templates\n\nAn environment is set up by executing one or more templates,\nwhere a template is a a small program written in JavaScript\nwhich defines what images to build/fetch, what and how many containers\nto spawn, what files to mount inside containers, what ports to expose etc.\n\nA template script is run by embedded JS interpreter inside `xenvman` server.\nOne template is just one javascript file located within a template base directory (defined by `tpl.base-dir` configuration parameter, or `XENVMAN_TPL.BASE_DIR` environment variable).\n\nA template file name must follow the format: `\u003cname\u003e.tpl.js` and can be located\neither directly within tpl base dir or in any sub-directory.\n\nA fully qualified template name consists of javascript file name without `.tpl.js` suffix, preceeded by directory names relative to template base dir.\n\nTo make it clear, let's consider a simple example.\nLet's say our base dir is `/opt/xenvman/base` and it looks like this:\n\n```\n/opt/xenvman/base/\n   db/\n      mysql.tpl.data/\n      mongo.tpl.data/\n      mysql.tpl.js\n      mongo.tpl.js\n   custom.tpl.data/\n      Dockerfile\n      custom.yaml\n   custom.tpl.js\n```\n\nSo here we have three templates with fully qualified names:\n`db/mysql`, `db/mongo` and `custom`.\n\n## Data directory\n\nThere's usually a bunch of files needed by template like Dockerfile to build\nimages on the fly, configuration templates, required modules, shared libraries\netc. All those files must be placed in a special directory called\n`template data directory` (or just `data dir` for short).\nData dir must be located inside the same dir where template file is\nand must be named using the following format: `\u003cname\u003e.tpl.data`, where `\u003cname\u003e`\nis the same template name as in main json file.\n\nTemplate javascript API provides functions to copy files from data dir to image\nworkspace, mount them inside containers etc.\n\nPlease note, that all files in data directory are never changed\nby a template, they are always copied when needed.\n\n## Workspace directory\n\nBecause `xenvman` allows you to build docker images on the fly,\nthere are often files you'd want to include in the image.\nAll those files are collected in a special temporary dir called\n`workspace`. A workspace is a temporary directory, separately created for \nany image your template is trying to build during template execution.\nThe only required file is a Dockerfile itself, which describes what kind of\nimage you're building.\n\n## Mount directory\n\nA `mount directory` is a temporary dir created for every container\nthe template wants to run and holds files which will be mounted inside\nthe container. You can create files in a mount dir by either copying\nthem from a data dir (using container JS API) or by using data from template runtime parameters.\n\n## Template directories summary\n\nThe following picture provides a general view of template directories\nand their relations.\n\n![Template directories](docs/img/dirs.png)\n\n## Javascript API\n\nAs mentioned above, a template is a JavaScript program which\nuses special API to configure required environment.\nLet's take a closer look at template shape and form.\n\n`Please note`: `xenvman` uses an embedded [JS interpreter](https://github.com/robertkrimen/otto), which implies certain limitations as compared\nto running JS in a browser or in node.js ecosystem:\n\n* No DOM-related functions\n* `\"use strict\"` will parse, but does nothing\n* The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification\n* Only ES5 is supported. ES6 features (eg: Typed Arrays) are not available\n\n### Template format\n\nA template must define an entry point function:\n\n`function execute(tpl, params) {}`\n\nThis function is expected to provide necessary instructions in order\nto configure an environment.\n\nFirst parameter, `tpl`, is a [template instance](#Template-API), while\n`params` is an arbitrary key-value object which is used to \nconfigure template by the caller.\n\n`Please note`: calling tpl instance functions, such as `BuildImage`,\n`FetchImage` etc. does not cause these actions to occur immediately,\ninstead they are scheduled and performed at later stages, after\nJS execution phase.\n\n### Template API\n\nTemplate instance, which is passed as a first argument has the following methods:\n\n#### BuildImage(name :: string) -\u003e [BuildImage](#BuildImage-API)\n\nInstucts `xenvman` to build a new image with the given name.\n`name` parameter is the resulting Docker image name.\n\nReturn value is a [BuildImage](#BuildImage-API) instance.\n\n#### FetchImage(name :: string) -\u003e [FetchImage](#FetchImage-API)\n\nInstructs `xenvman` to fetch an existing image from public or \nprivate image repository.\n \nThe `name` is a fully-qualified docker image name, including\nrepository address and tag, that is the same format is expected as\nfor regular `docker pull` invocation.\n\nFor private repos, existing credentials (acquired by `docker login`)\nare used by the user who started `xenvman` server.\n\n#### AddReadinessCheck(name :: string, params :: object) -\u003e null\n\nAdds a new [readiness check](#Readiness-checks) for the current template.\n\n### BuildImage API\n\nBuildImage instance represents an image which `xenvman` is going to build\non the fly. Files included in the image can be either copied from a\n[template data dir](#Data-directory) or by supplying data for files in\ntemplate HTTP parameters.\n\n#### CopyDataToWorkspace(path :: string...) -\u003e null\n\nThis function takes a variable list of FS object names from data dir\nand copies them into [image workspace](#Workspace-directory).\nObject names must be relative to the data dir.\nFor example, if data dir contained the following files:\n\n```\n\u003cdata-dir\u003e/\n   subdir/\n      subfile.png\n   file1.json\n```\n\nthen the paths would be: `subdir/subfile.png` and `file1.json`.\n\nA special value `*` can be provided in order to copy every object from\ndata dir.\n\n#### AddFileToWorkspace(path :: string, data :: string, mode int) -\u003e null\n\nSometimes you want to dynamically include some file into the image\nwhich is different every time you build it. So it cannot be simply\nplaced into data dir. Imagine you've patched some microservice\nand want to test it, you can simply include the binary itself\n(assuming your microservice is written in a compiled language)\nin the HTTP request as a template parameter and by calling\n`AddFileToWorkspace` it will be copied to image workspace.\n\n* `path` argument is a path inside an image where to save the data.\n* `data` is the data itself as a binary/string. Usually it is base64-encoded\n  during HTTP transfer and then decoded back using `type.FromBase64()`\n  js function.\n* `mode` is a standard Unix file mode as an octal number.  \n\n#### InterpolateWorkspaceFile(file :: string, data :: object) -\u003e null\n\nInstructs `xenvman` to interpolate a file in a workspace dir (that is\nit must already be copied there before).\n\n* `file` is a file path relative to workspace dir.\n* `data` is an object providing values for interpolation.\n\n[More details about interpolation](#Interpolation).\n\n#### NewContainer(name :: string) -\u003e [Container](#Container-API)\n\nCreate a new container with a given name from the image instance.\n\n### FetchImage API\n\nFetchImage instance represents an image which will be fetched by\n`xenvman` (using Docker). Because in this case the image is already built\nthe amount of possible actions is limited as compared to building a new\nimage from scratch. Basically the only possible modification is mounting\nfiles into the container from the host ([Mount dir](#Mount-directory)).\n\n#### NewContainer(name :: string) -\u003e [Container](#Container-API)\n\nCreate a new container with a given name from the image instance.\n\n### Container API\n\n#### SetEnv(env, val :: string) -\u003e null\n\nSets a shell environment variable inside a container.\n\n#### SetLabel(key :: string, value :: {string, number}) -\u003e null\n\nThis function sets a container label. Labels here are `xenvman` entity\nand are used later during [interpolation](#Interpolation) in order\nto filter containers.\n\n#### SetCmd(cmd :: string...) -\u003e null\n\nSets a [`CMD`](https://docs.docker.com/engine/reference/builder/#cmd) for the container.\n\n#### SetEntrypoint(cmd :: string...) -\u003e null\n\nSets an [`ENTRYPOINT`](https://docs.docker.com/engine/reference/builder/#entrypoint) for the container.\n\n#### SetPorts(port :: number...) -\u003e null\n\nInstructs `xenvman` to expose certain ports from the container.\nPorts here are internal container ones, `xenvman` will select different\nexternal ports for every exposed one.\n\n#### MountString(data, contFile :: string, mode :: int, opts :: object) -\u003e null\n\nInstructs `xenvman` to mount the `data` string into a container\nunder the `contFile` name.\n`mode` is a regular Linux file mode expressed as an octal int.\n`opts` is an object, representing additional mounting parameters:\n\n* `readonly` :: bool - If mounted file should be read only.\n* `interpolate` :: bool - If the contents of a mounted file needs to be\n                          interpolated.\n* `extra-interpolate-data` :: object - Additional interpolation data.\n                                       The data is accessible under\n                                       `.Extra` key of a container\n                                       instance inside templates.\n\n#### MountData(dataFile, contFile :: string, opts :: object) -\u003e null\n\nInstructs `xenvman` to copy a `dataFile` from the [data dir](#Data directory) \nand mount it inside a container under `contFile` name.\n\nIn addition to `opts` from `MountString` above, `MountData` can take the\nfollowing:\n\n* `skip-if-nonexistent` :: bool - If set to `true`, an error will not be\n                                  raised if specified `dataFile` does not exist.\n\n### Readiness checks\n\n`xenvman` was primarily designed to create environments for\nintegration testing. Because of that, it needs to make sure\nan environment is `ready` before returning the access data to the caller.\nThis is what readiness checks are for.\n\nAn environment can define any number of readiness checks and\n`xenvman` will only return back to the caller after all the checks for\nall the used templates are completed.\n\nReadiness checks are added by calling [AddReadinessCheck()](#addreadinesscheckname--string-params--object---null)\nfunction of `tpl` instance.\n\nPlease note, that every value in check parameters is\n[interpolated](#Readiness-checks-interpolation).\n\nCurrently available readiness checks include:\n\n#### http\n\nAs the name suggests this readiness check is used to ensure\nreadiness of a http service[s].\n\nAvailalable parameters include:\n\n* `url` :: string - A HTTP URL to try fetching.\n* `codes` :: [int] - A list of successful HTTP response codes.\n                     At lest one must match in order for a check to\n                     be considered successful.\n* `headers` :: [object] - A list of header objects to match.\n\t                      Values within the same objects are matched\n\t                      in a conjuctive way (AND).\n\t                      Values from different objects are matched in\n\t                      a disjunctive way (OR).\n* `body` :: string - A regexp to match response body against.\n* `retry_limit` :: int - How many times to retry a check before giving up.\n* `retry_interval` :: string - How long to wait between retrying.\n                               String must follow Golang [`fmt.Duration`](https://golang.org/pkg/time/#ParseDuration) format.\n\n#### net\n\nA simple low-level network readiness check.\n`protocol` and `address` parametes must be formatted according to\nGolang [`net.Dial`](https://golang.org/pkg/net/#Dial) function.\n\nAvailalable parameters include:\n\n* `protocol` :: string - Network protocol \n* `address` :: string - Address string\n* `retry_limit` :: int - How many times to retry a check before giving up.\n* `retry_interval` :: string - How long to wait between retrying.\n                               String must follow Golang [`fmt.Duration`](https://golang.org/pkg/time/#ParseDuration) format.\n\n### Helper JS functions\n\nIn addition to image and container specific APIs there are also some\nadditional helper modules which can be used directly anywhere in the template\nscript.\n\n#### fmt(format :: string, args :: any...)\n\nA useful shorthand for printing formatted messages.\nIt's nothing more than an exported Golang function [`fmt.Printf`](https://golang.org/pkg/fmt/#Printf).\n\n#### type\n\n`type` module contains functions related to managing types.\n\nAll `Ensure*` functions take a value and panic if the value is not\nof correspdonging type. It passes otherwise (including value not\nbeing defined).\n\n##### type.EnsureString(arg :: any)\n##### type.EnsureNumber(arg :: any)\n##### type.EnsureListOfStrings(arg :: any)\n##### type.EnsureListOfNumbers(arg :: any)\n##### type.FromBase64(name :: string, value :: string)\n\nDecodes a value from base64 string to a byte array.\n`name` argument is only used for logging in case of errors.\n\n##### type.IsArray(arg :: any)\n\nReturns true if given argument is of array type.\n\n##### type.IsDefined(arg :: any)\n\nReturns true if given argument is neither `null` nor `undefined`.\n\n## Interpolation\n\nSometimes a static file, either embedded into an image or mounted\ninto a container in runtime is not enough, we need to be able to\ninclude some dynamic parts, parts which can take different values\nfrom environment to environment. For example you may need to\nspecify a database address in a config for your service.\nBut the hostname will always be different, you cannot just hardcode it.\n\nThis is where interpolation kicks in. Interpolation is just a fancy name\nfor variable substitution. Basically you just reserve certain placeholders\nin your configs and they will be filled with needed values in due time.\n\nThere are two main types of interpolation in `xenvman`:\n\n1. Workspace files\n2. Mounted files, readiness checks and environ interpolation\n\nThe main difference between them is the available data.\n\nFor workspace files the only data you can substitute is the\none you supply yourself. The reason for this is that workspace files\nare baked into an image and thus cannot be modified in any way\nduring container lifetime.\n\nAll the rest, on the other hand, do have access to some runtime info\nlike containers, ports etc.\n\nAll the interpolation is done using [Golang template language](https://golang.org/pkg/text/template/).\n\n### Workspace files interpolation\n\nWorkspace files interpolation is very simple, you just call\n[InterpolateWorkspaceFile()](#interpolateworkspacefilefile--string-data--object---null) function on\na file you want to interpolate. You must copy the file using\n[CopyDataToWorkspace()](#copydatatoworkspacepath--string---null) or \n[AddFileToWorkspace()](#addfiletoworkspacepath--string-data--string-mode-int---null) first. \n\nYou can supply arbitrary object and its fields in your interpolation\nplaceholders.\n\nFor example, let's say we have a `Dockerfile` in our data dir.\nIt will be included into an image every time we build it.\nAnd we allow clients to supply their own executable binary.\nThus we don't know what the binary will be so we cannot hardcode\nthe executable name and so we'll use interpolation for it.\n\nLet's examine template code first:\n\n```javascript\nfunction execute(tpl, params) {\n    var img = tpl.BuildImage(\"service-%s\", params.service);\n    \n    img.CopyDataToWorkspace(\"Dockerfile\");\n    img.InterpolateWorkspaceFile(\"Dockerfile\", {\"service\": params.service});\n}\n```\n\nAnd the Dockerfile itself:\n\n```dockerfile\nFROM ubuntu\n\nCOPY {{.service}} /\nCMD [\"/{{.service}}\", \"run\"]\n```\n\nHere `{{.service}}` will be substituted with whaterver was provided in\n\n```javascript\n    img.InterpolateWorkspaceFile(\"Dockerfile\", {\"service\": params.service});\n```\n\nin our template.\n\n### Mounted files, readiness checks \u0026 environ interpolation\n\nFor this type of interpolation, in addition to providing your own\nplaceholder data, there's also some internal environment-specific data\navailable for you.\n\nLet's take a look at what's available:\n\n#### .Self -\u003e Container\n\nReturn a current container instance.\n\n#### .Extra -\u003e Any\n\nReturns a user-provided data, if any.\n\n#### .ExternalAddress -\u003e string\n\nReturns an external address.\n\n#### .ContainersWithLabels(label : string, value : string) -\u003e [Container]\n\nFind all containers with a given label name and value.\nEmpty `value` matches any label.\n\n#### .ContainerWithLabel(label : string, value : string) -\u003e Container\n\nFind a container with a given label name and value.\nEmpty `value` matches any label.\n\n#### .AllContainers() -\u003e [Container]\n\nReturn a list of all containers in the environment.\n\n#### Container instance methods\n\n##### .IP -\u003e string\n\nReturns internal container IP address.\n\n##### .Hostname -\u003e string\n\nReturns container hostname.\n\n##### .Name -\u003e string\n\nReturns container name.\n\n##### .GetLabel(label : string) -\u003e string\n\nReturns label value. Empty string is returned if there's no such label\non the container.\n\n##### .ExposedPort(iport : int) -\u003e int\n\nReturns an external (exposed) port for the given internal one.\nIt's an error if there's no such port exposed on the container.\n\n# HTTP API\n\n`xenvman` exposes all its functionality using HTTP API.\n\n## GET /api/v1/env\n\nList active environments.\n\n### Response body\n\n[[OutputEnv]](#outputenv)\n\n## POST /api/v1/env\n\nCreate a new environment.\n\n### Body\n\n[InputEnv](#inputenv)\n\n### Response body\n\n[OutputEnv](#outputenv)\n\n## GET /api/v1/env/{id}\n\nGet environment info.\n\n### Response body\n\n[OutputEnv](#outputenv)\n\n## PATCH /api/v1/env/{id}\n\nUpdate existing environment.\n\n### Body\n\n[PatchEnv](#patchenv)\n\n### Response body\n\n[OutputEnv](#outputenv)\n\n## DELETE /api/v1/env/{id}\n\nDelete an environment.\n\n### Query parameters\n\n* id - Environment id\n\n## POST /api/v1/env/{id}/keepalive\n\nKeep alive an environment.\n\nA client can periodicall call this endpoint in order to keep\nthe environment running. Otherwise an environment will be terminated\nafter the configured keepalive interval.\n\n## GET /api/v1/tpl\n\nGet templates info.\n\n### Response body\n```{name: string -\u003e TplInfo}```\n\n## Types\n\n### InputEnv\n```\n{\n   // Environment name\n   name: string,\n \n   // Environment description\n   description: string,\n \n   // Templates to use\n   templates: [InputTpl]\n\n   // Additional env options\n   options: InputEnvOptions\n}\n```\n\n### InputEnvOptions\n```\n{\n  // Environment keep alive setting\n  keep_alive: string,\n  \n  // Whether to disable dynamic discovery DNS agent and revert back to static\n  // hostnames\n  disable_discovery: bool\n}\n```\n\n### OutputEnv\n```\n{\n    // Environment id\n    id: string,\n\t\n    // Environment name\n    name: string,\n    \n    // Environment description\n    description: string,\n    \n    // Workspace directory\n    ws_dir: string,\n    \n    // Mount directory\n    mount_dir: string,\n    \n    // Container engine network id for the environment\n    net_id: string,\n    \n    // Creation time\n    created: string,\n    \n    // Environment keep alive setting\n    keep_alive: string,\n    \n    // External address (hostname or IP) of the xenvman server\n    external_address: string,\n    \n    // Templates data\n    templates: {name: string -\u003e [TplData]}\n}\n```\n\n### PatchEnv\n\n```\n{\n   // A list of fully-qualified container names to stop\n   stop_containers: [string],\n  \n   // A list of fully-qualified container names to restart\n   start_containers: [string],\n \n   // New templates to execute\n   templates: [InputTpl]\n}\n```\n\n### InputTpl\n```\n{\n  // Template name (a path relative to xenvman base template dir)\n  tpl: string,\n  \n  // Template parameters as arbitrary JSON object\n  parameters: object \n}\n```\n\n### TplData\n```\n{\n   // Template containers\n   containers: {name: string -\u003e [ContainerData]}\n}\n```\n\n### ContainerData\n```\n{\n   // Unique container id\n   id: string,\n   // Internal container hostname\n   hostname: string,\n   // Mapping between internal container port and corresponding external one\n   ports: {port: string -\u003e int}\n}\n```\n\n### TplInfo\n```\n   // Template description\n   description: string,\n   \n   // Template parameters\n   parameters: {name: string -\u003e TplInfoParam},\n   \n   // List of files in template data directory\n   data_dir: [string]\n```\n\n### TplInfoParam\n```\n   // Parameter description\n   description: string,\n   \n   // Parameter type\n   type: string,\n   \n   // Whether a parameter is mandatory\n   mandatory: bool,\n   \n   // Default value\n   default: any,\n```\n\n# Dynamic discovery\n\nIn the version `v2.0.0` a new dynamic discovery agent has been introduced.\nIt is basically a simple DNS proxy configurable over HTTP which\nall the containers running inside an environment are configured to use.\nThis allows us to dynamicall re-configure environment on-the-fly,\nadd/update/stop containers and make sure newly added containers can \nbe discovered by the old ones.\n\nThe discovery agent is injected as just any another template and\na [tiny image from docker hub](https://hub.docker.com/r/syhpoon/xenvman)\nis fetched with size of about 8 mb. \nThis template creates a single container with a running agent.\nThe hostname of the container is `discovery.0.discovery.xenv` and\nit exposes port `8080` over which it is configured later by\n`xenvman` server.\n\nYou can disable this feature and opt in for static DNS config by\nsetting `disable_discovery=true` [env option](#env_options).\nIf you do this though, you will not be able to dynamically\nchange the environment composition (add/stop containers)\nafter it has started.\n\nBy default discovery agent is enabled.\n\nThe following picture illustrates these two different approaches:\n\n![Static vs Dynamic DNS configuration](docs/img/discovery_agent.png)\n\n# Dynamic environment reconfiguration\n\nStarting from version `v2.0.0` it is possible to change environment\ncomposition while it is running. One can stop existing containers \n(perhaps to emulate network split) or inject new templates and\nintroduce new containers (peers arrival). A new API endpoint\nhave been added for this purpose: `PATCH /api/v1/env/{id}`.\n\n`Please note:` the environment reconfiguration is only available if\n[dynamic agent](#dynamic-discovery) has not been disabled.\n\n# Web UI\n\nStarting from version `v2.0.0` xenman has a simple embedded web application.\nIt can be used to:\n\n* Inspect currently running environments\n* Terminate an environment\n* Browse through all available templates\n* Inspect invidual templates and its parameters\n\nOnce `xenvman` is running simply point your browser at\n`http://\u003cHOST\u003e:\u003cPORT\u003e/`, where `\u003cHOST\u003e` is the hostname/ip where `xenvman`\nis running and `\u003cPORT\u003e` is the post which `xenvman` is listening on.\n\nList of active environments:\n![List of environments](docs/img/webapp-1.png)\n\nEnvironment info:\n![Environment info](docs/img/webapp-2.png)\n\nTemplates browser:\n![Templates browser](docs/img/webapp-3.png)\n\n# Clients\n\nBecause `xenvman` uses plain HTTP API, any language/tool capable of\ntalking HTTP can be used as a client. But it's arguably easier to have\nnative and idiomatic libraries for a language of choice, especially\nto embed managing environments directly into integration tests themselves.\n\nCurrently `xenvman` supports the following language clients:\n\n## Golang\n\nGo documentation for client package is available\n[here](https://godoc.org/github.com/syhpoon/xenvman/pkg/client).\n\nAn example of how to use the client API is available\nin [xenvman-tutorial](https://github.com/syhpoon/xenvman-tutorial/blob/master/bro_xenv_test.go).\n\n## Python\n\nPython client is available [here](https://github.com/syhpoon/xenvman-python).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsyhpoon%2Fxenvman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsyhpoon%2Fxenvman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsyhpoon%2Fxenvman/lists"}