diff --git a/.gitignore b/.gitignore index c7c30d3..936332c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ *.so _docs/ -vls.log diff --git a/README.md b/README.md index 333ace1..5db18f6 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,3 @@ # Docker -V library for interacting with the Docker HTTP API v1.41. - -The structure of this project largely follows the official Docker -[client](https://github.com/moby/moby/tree/master/client) structure. - -## Installation - -You can install vdocker from source using V: - -``` -v install --git https://git.rustybever.be/vieter-v/vdocker -``` +V library for interacting with the Docker HTTP API. diff --git a/containers.v b/containers.v index 0e69c05..0aee8f4 100644 --- a/containers.v +++ b/containers.v @@ -1,24 +1,81 @@ -module docker +module vdocker import json import time import net.http { Method } -import types { ContainerListItem } -[params] -pub struct ContainerListConfig { - all bool - limit int - size bool - filters map[string][]string +pub struct Port { + ip string [json: IP] + private_port u16 [json: PrivatePort] + public_port u16 [json: PublicPort] + type_ string [json: Type] } -pub fn (mut d DockerConn) container_list(c ContainerListConfig) ?[]ContainerListItem { - d.get('/containers/json') - d.params(c) - d.send()? +pub struct HostConfig { + network_mode string [json: NetworkMode] +} - return d.read_json_response<[]ContainerListItem>() +pub struct EndpointIpamConfig { + ipv4_address string [json: IPv4Address] + ipv6_address string [json: IPv6Address] + link_local_ips []string [json: LinkLocalIPs] +} + +pub struct EndpointSettings { + ipam_config EndpointIpamConfig [json: IPAMConfig] + links []string [json: Links] + aliases []string [json: Aliases] + network_id string [json: NetworkID] + endpoint_id string [json: EndpointID] + gateway string [json: Gateway] + ip_address string [json: IPAddress] + ip_prefix_len int [json: IPPrefixLen] + ipv6_gateway string [json: IPv6Gateway] + global_ipv6_address string [json: GlobalIPv6Address] + global_ipv6_prefix_len i64 [json: GlobalIPv6PrefixLen] + mac_address string [json: MacAddress] + driver_opts map[string]string [json: DriverOpts] +} + +pub struct NetworkSettings { + networks map[string]EndpointSettings [json: Networks] +} + +pub struct MountPoint { + type_ string [json: Type] + name string [json: Name] + source string [json: Source] + destination string [json: Destination] + driver string [json: Driver] + mode string [json: Mode] + rw bool [json: RW] + propagation string [json: Propagation] +} + +pub struct ContainerListItem { + id string [json: Id] + names []string [json: Names] + image string [json: Image] + image_id string [json: ImageID] + command string [json: Command] + created i64 [json: Created] + ports []Port [json: Ports] + size_rw i64 [json: SizeRw] + size_root_fs i64 [json: SizeRootFs] + labels map[string]string [json: Labels] + state string [json: State] + status string [json: Status] + host_config HostConfig [json: HostConfig] + network_settings NetworkSettings [json: NetworkSettings] + mounts []MountPoint [json: Mounts] +} + +pub fn (mut d DockerConn) container_list() ?[]ContainerListItem { + d.send_request(Method.get, '/containers/json')? + + data := d.read_json_response<[]ContainerListItem>()? + + return data } pub struct NewContainer { @@ -53,7 +110,7 @@ pub fn (mut d DockerConn) container_create(c NewContainer) ?CreatedContainer { // start_container starts the container with the given id. pub fn (mut d DockerConn) container_start(id string) ? { - d.send_request(Method.post, '/containers/$id/start')? + d.send_request(Method.post, 'containers/$id/start')? head, body := d.read_response()? if head.status_code != 204 { @@ -82,7 +139,7 @@ pub mut: } pub fn (mut d DockerConn) container_inspect(id string) ?ContainerInspect { - d.send_request(Method.get, '/containers/$id/json')? + d.send_request(Method.get, 'containers/$id/json')? head, body := d.read_response()? if head.status_code != 200 { @@ -104,7 +161,7 @@ pub fn (mut d DockerConn) container_inspect(id string) ?ContainerInspect { } pub fn (mut d DockerConn) container_remove(id string) ? { - d.send_request(Method.delete, '/containers/$id')? + d.send_request(Method.delete, 'containers/$id')? head, body := d.read_response()? if head.status_code != 204 { @@ -115,7 +172,7 @@ pub fn (mut d DockerConn) container_remove(id string) ? { } pub fn (mut d DockerConn) container_get_logs(id string) ?&StreamFormatReader { - d.send_request(Method.get, '/containers/$id/logs?stdout=true&stderr=true')? + d.send_request(Method.get, 'containers/$id/logs?stdout=true&stderr=true')? head := d.read_response_head()? if head.status_code != 200 { diff --git a/docker.v b/docker.v index 3fe6171..a171a2e 100644 --- a/docker.v +++ b/docker.v @@ -1,4 +1,4 @@ -module docker +module vdocker import net.unix import io @@ -17,22 +17,15 @@ const ( api_version = 'v1.41' ) -[heap] pub struct DockerConn { mut: socket &unix.StreamConn reader &io.BufferedReader - // Data for the request that's currently being constructed. - method http.Method - url string - params map[string]string - content_type string - body string } // new_conn creates a new connection to the Docker daemon. pub fn new_conn() ?&DockerConn { - s := unix.connect_stream(docker.socket)? + s := unix.connect_stream(vdocker.socket)? d := &DockerConn{ socket: s @@ -49,7 +42,7 @@ pub fn (mut d DockerConn) close() ? { // send_request sends an HTTP request without body. fn (mut d DockerConn) send_request(method http.Method, url_str string) ? { - url := urllib.parse('/$docker.api_version$url_str')? + url := urllib.parse('/$vdocker.api_version$url_str')? req := '$method $url.request_uri() HTTP/1.1\nHost: localhost\n\n' d.socket.write_string(req)? @@ -60,7 +53,7 @@ fn (mut d DockerConn) send_request(method http.Method, url_str string) ? { // send_request_with_body sends an HTTP request with the given body. fn (mut d DockerConn) send_request_with_body(method http.Method, url_str string, content_type string, body string) ? { - url := urllib.parse('/$docker.api_version$url_str')? + url := urllib.parse('/$vdocker.api_version$url_str')? req := '$method $url.request_uri() HTTP/1.1\nHost: localhost\nContent-Type: $content_type\nContent-Length: $body.len\n\n$body\n\n' d.socket.write_string(req)? @@ -84,7 +77,7 @@ fn (mut d DockerConn) send_request_with_json(method http.Method, url_str stri fn (mut d DockerConn) read_response_head() ?http.Response { mut res := []u8{} - util.read_until_separator(mut d.reader, mut res, docker.http_separator)? + util.read_until_separator(mut d.reader, mut res, vdocker.http_separator)? return http.parse_response(res.bytestr()) } @@ -96,9 +89,9 @@ fn (mut d DockerConn) read_response_body(length int) ?string { return '' } - mut buf := []u8{len: docker.buf_len} + mut buf := []u8{len: vdocker.buf_len} mut c := 0 - mut builder := strings.new_builder(docker.buf_len) + mut builder := strings.new_builder(vdocker.buf_len) for builder.len < length { c = d.reader.read(mut buf) or { break } diff --git a/errors.v b/errors.v index 717f9fc..e5da55a 100644 --- a/errors.v +++ b/errors.v @@ -1,4 +1,4 @@ -module docker +module vdocker struct DockerError { status int [skip] diff --git a/images.v b/images.v index a7659dd..aeaa53f 100644 --- a/images.v +++ b/images.v @@ -1,4 +1,4 @@ -module docker +module vdocker import net.http { Method } import json @@ -10,7 +10,7 @@ pub: // pull_image pulls the given image:tag. pub fn (mut d DockerConn) pull_image(image string, tag string) ? { - d.send_request(Method.post, '/images/create?fromImage=$image&tag=$tag')? + d.send_request(Method.post, 'images/create?fromImage=$image&tag=$tag')? head := d.read_response_head()? if head.status_code != 200 { @@ -33,7 +33,7 @@ pub fn (mut d DockerConn) pull_image(image string, tag string) ? { // create_image_from_container creates a new image from a container. pub fn (mut d DockerConn) create_image_from_container(id string, repo string, tag string) ?Image { - d.send_request(Method.post, '/commit?container=$id&repo=$repo&tag=$tag')? + d.send_request(Method.post, 'commit?container=$id&repo=$repo&tag=$tag')? head, body := d.read_response()? if head.status_code != 201 { @@ -49,7 +49,7 @@ pub fn (mut d DockerConn) create_image_from_container(id string, repo string, ta // remove_image removes the image with the given id. pub fn (mut d DockerConn) remove_image(id string) ? { - d.send_request(Method.delete, '/images/$id')? + d.send_request(Method.delete, 'images/$id')? head, body := d.read_response()? if head.status_code != 200 { diff --git a/request.v b/request.v deleted file mode 100644 index 14dd468..0000000 --- a/request.v +++ /dev/null @@ -1,51 +0,0 @@ -module docker - -import net.http -import net.urllib -import io - -fn (mut d DockerConn) request(method http.Method, url_str string) { - d.method = method - d.url = url_str - d.params.clear() - d.content_type = '' - d.body = '' -} - -fn (mut d DockerConn) get(url_str string) { - d.request(http.Method.get, url_str) -} - -fn (mut d DockerConn) params(o T) { - $for field in T.fields { - v := o.$(field.name) - - if !isnil(v) { - d.params[field.name] = urllib.query_escape(v.str().replace("'", '"')) - } - } -} - -fn (mut d DockerConn) send() ? { - mut full_url := d.url - - if d.params.len > 0 { - params_str := d.params.keys().map('$it=${d.params[it]}').join('&') - full_url += '?$params_str' - } - - // This is to make sure we actually created a valid URL - parsed_url := urllib.parse(full_url)? - final_url := parsed_url.request_uri() - - req := if d.body == '' { - '$d.method $final_url HTTP/1.1\nHost: localhost\n\n' - } else { - '$d.method $final_url HTTP/1.1\nHost: localhost\nContent-Type: $d.content_type\nContent-Length: $d.body.len\n\n$d.body\n\n' - } - - d.socket.write_string(req)? - - // When starting a new request, the reader needs to be reset. - d.reader = io.new_buffered_reader(reader: d.socket) -} diff --git a/stream.v b/stream.v index 001f4b3..6c1d88f 100644 --- a/stream.v +++ b/stream.v @@ -1,4 +1,4 @@ -module docker +module vdocker import io import util diff --git a/types/container.v b/types/container.v deleted file mode 100644 index 795c3d4..0000000 --- a/types/container.v +++ /dev/null @@ -1,67 +0,0 @@ -module types - -pub struct Port { - ip string [json: IP] - private_port u16 [json: PrivatePort] - public_port u16 [json: PublicPort] - type_ string [json: Type] -} - -pub struct HostConfig { - network_mode string [json: NetworkMode] -} - -pub struct EndpointIpamConfig { - ipv4_address string [json: IPv4Address] - ipv6_address string [json: IPv6Address] - link_local_ips []string [json: LinkLocalIPs] -} - -pub struct EndpointSettings { - ipam_config EndpointIpamConfig [json: IPAMConfig] - links []string [json: Links] - aliases []string [json: Aliases] - network_id string [json: NetworkID] - endpoint_id string [json: EndpointID] - gateway string [json: Gateway] - ip_address string [json: IPAddress] - ip_prefix_len int [json: IPPrefixLen] - ipv6_gateway string [json: IPv6Gateway] - global_ipv6_address string [json: GlobalIPv6Address] - global_ipv6_prefix_len i64 [json: GlobalIPv6PrefixLen] - mac_address string [json: MacAddress] - driver_opts map[string]string [json: DriverOpts] -} - -pub struct NetworkSettings { - networks map[string]EndpointSettings [json: Networks] -} - -pub struct MountPoint { - type_ string [json: Type] - name string [json: Name] - source string [json: Source] - destination string [json: Destination] - driver string [json: Driver] - mode string [json: Mode] - rw bool [json: RW] - propagation string [json: Propagation] -} - -pub struct ContainerListItem { - id string [json: Id] - names []string [json: Names] - image string [json: Image] - image_id string [json: ImageID] - command string [json: Command] - created i64 [json: Created] - ports []Port [json: Ports] - size_rw i64 [json: SizeRw] - size_root_fs i64 [json: SizeRootFs] - labels map[string]string [json: Labels] - state string [json: State] - status string [json: Status] - host_config HostConfig [json: HostConfig] - network_settings NetworkSettings [json: NetworkSettings] - mounts []MountPoint [json: Mounts] -} diff --git a/v.mod b/v.mod index b36e97d..bc42cd7 100644 --- a/v.mod +++ b/v.mod @@ -1,5 +1,5 @@ Module { - name: 'docker' + name: 'vdocker' description: 'Library for interacting with the Docker HTTP API' version: '0.0.0' license: 'MIT' diff --git a/volumes.v b/volumes.v index 00db10a..9642198 100644 --- a/volumes.v +++ b/volumes.v @@ -1,4 +1,4 @@ -module docker +module vdocker import net.http { Method } import time