From f92f73b0ffb93544625a721dcacab5c80625bce0 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Sat, 18 Jun 2022 20:58:53 +0200 Subject: [PATCH 1/6] chore: added Makefile & ci linting --- .gitignore | 2 ++ .woodpecker/.lint.yml | 13 +++++++++++++ Makefile | 31 +++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 .woodpecker/.lint.yml create mode 100644 Makefile diff --git a/.gitignore b/.gitignore index 140f8cf..936332c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *.so + +_docs/ diff --git a/.woodpecker/.lint.yml b/.woodpecker/.lint.yml new file mode 100644 index 0000000..31df08c --- /dev/null +++ b/.woodpecker/.lint.yml @@ -0,0 +1,13 @@ +branches: + exclude: [ main ] + +platform: 'linux/amd64' + +pipeline: + lint: + image: 'chewingbever/vlang:latest' + pull: true + commands: + - make lint + when: + event: [ push ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..81b65fc --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +# =====CONFIG===== +V_PATH ?= v +V := $(V_PATH) -showcc + +all: vdocker + + +# =====COMPILATION===== +.PHONY: vdocker +vdocker: + $(V) -g -shared . + + +# =====DOCS===== +.PHONY: api-docs +api-docs: + rm -rf '_docs' + v doc -f html -m -readme . + + +# =====OTHER===== +.PHONY: lint +lint: + $(V) fmt -verify . + $(V) vet -W . + $(V_PATH) missdoc -p . + @ [ $$($(V_PATH) missdoc -p . | wc -l) = 0 ] + +.PHONY: fmt +fmt: + $(V) fmt -w . From 843db9e3ec1eaa629ce3826f12482b9ce9ce9dad Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Sat, 18 Jun 2022 22:17:52 +0200 Subject: [PATCH 2/6] chore: added roadmap; started volume_list --- ROADMAP.md | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++ docker.v | 16 +++--- volumes.v | 33 +++++++++++++ 3 files changed, 184 insertions(+), 8 deletions(-) create mode 100644 ROADMAP.md create mode 100644 volumes.v diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..69f4048 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,143 @@ +# Roadmap + +This file keeps track of which parts of the Docker Engine API v1.41 are +currently supported. Note that in-development support is not listed here, so as +long as the full functionality isn't supported, it won't be noted. + +This list was taking from the [API +reference](https://docs.docker.com/engine/api/v1.41/). + +* Containers + - [ ] List containers + - [ ] Create a container + - [ ] Inspect a container + - [ ] List processes running inside a container + - [ ] Get container logs + - [ ] Get changes on a container’s filesystem + - [ ] Export a container + - [ ] Get container stats based on resource usage + - [ ] Resize a container TTY + - [ ] Start a container + - [ ] Stop a container + - [ ] Restart a container + - [ ] Kill a container + - [ ] Update a container + - [ ] Rename a container + - [ ] Pause a container + - [ ] Unpause a container + - [ ] Attach to a container + - [ ] Attach to a container via a websocket + - [ ] Wait for a container + - [ ] Remove a container + - [ ] Get information about files in a container + - [ ] Get an archive of a filesystem resource in a container + - [ ] Extract an archive of files or folders to a directory in a container + - [ ] Delete stopped containers + +* Images + - [ ] List images + - [ ] Build an image + - [ ] Delete builder cache + - [ ] Create an image + - [ ] Inspect an image + - [ ] Get the history of an image + - [ ] Push an image + - [ ] Tag an image + - [ ] Remove an image + - [ ] Search images + - [ ] Delete unused images + - [ ] Create a new image from a container + - [ ] Export an image + - [ ] Export several images + - [ ] Import images + +* Networks + - [ ] List networks + - [ ] Inspect a network + - [ ] Remove a network + - [ ] Create a network + - [ ] Connect a container to a network + - [ ] Disconnect a container from a network + - [ ] Delete unused networks + +* Volumes + - [ ] List volumes + - [ ] Create a volume + - [ ] Inspect a volume + - [ ] Remove a volume + - [ ] Delete unused volumes + +* Exec + - [ ] Create an exec instance + - [ ] Start an exec instance + - [ ] Resize an exec instance + - [ ] Inspect an exec instance + +* Swarm + - [ ] Inspect swarm + - [ ] Initialize a new swarm + - [ ] Join an existing swarm + - [ ] Leave a swarm + - [ ] Update a swarm + - [ ] Get the unlock key + - [ ] Unlock a locked manager + +* Nodes + - [ ] List nodes + - [ ] Inspect a node + - [ ] Delete a node + - [ ] Update a node + +* Services + - [ ] List services + - [ ] Create a service + - [ ] Inspect a service + - [ ] Delete a service + - [ ] Update a service + - [ ] Get service logs + +* Tasks + - [ ] List tasks + - [ ] Inspect a task + - [ ] Get task logs + +* Secrets + - [ ] List secrets + - [ ] Create a secret + - [ ] Inspect a secret + - [ ] Delete a secret + - [ ] Update a secret + +* Configs + - [ ] List configs + - [ ] Create a config + - [ ] Inspect a config + - [ ] Delete a config + - [ ] Update a config + +* Plugins + - [ ] List plugins + - [ ] Get plugin privileges + - [ ] Install a plugin + - [ ] Inspect a plugin + - [ ] Remove a plugin + - [ ] Enable a plugin + - [ ] Disable a plugin + - [ ] Upgrade a plugin + - [ ] Create a plugin + - [ ] Push a plugin + - [ ] Configure a plugin + +* System + - [ ] Check auth configuration + - [ ] Get system information + - [ ] Get version + - [ ] Ping + - [ ] Monitor events + - [ ] Get data usage information + +* Distribution + - [ ] Get image information from the registry + +* Session + - [ ] Initialize interactive session diff --git a/docker.v b/docker.v index f4bcf23..1784599 100644 --- a/docker.v +++ b/docker.v @@ -39,7 +39,7 @@ pub fn (mut d DockerConn) close() ? { } // send_request sends an HTTP request without body. -pub fn (mut d DockerConn) send_request(method http.Method, url urllib.URL) ? { +fn (mut d DockerConn) send_request(method http.Method, url urllib.URL) ? { req := '$method $url.request_uri() HTTP/1.1\nHost: localhost\n\n' d.socket.write_string(req)? @@ -49,7 +49,7 @@ pub fn (mut d DockerConn) send_request(method http.Method, url urllib.URL) ? { } // send_request_with_body sends an HTTP request with the given body. -pub fn (mut d DockerConn) send_request_with_body(method http.Method, url urllib.URL, content_type string, body string) ? { +fn (mut d DockerConn) send_request_with_body(method http.Method, url urllib.URL, content_type string, body string) ? { 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)? @@ -60,7 +60,7 @@ pub fn (mut d DockerConn) send_request_with_body(method http.Method, url urllib. // send_request_with_json is a convenience wrapper around // send_request_with_body that encodes the input as JSON. -pub fn (mut d DockerConn) send_request_with_json(method http.Method, url urllib.URL, data &T) ? { +fn (mut d DockerConn) send_request_with_json(method http.Method, url urllib.URL, data &T) ? { body := json.encode(data) return d.send_request_with_body(method, url, 'application/json', body) @@ -70,7 +70,7 @@ pub fn (mut d DockerConn) send_request_with_json(method http.Method, url urll // '\r\n\r\n', after which it parses the response as an HTTP response. // Importantly, this function never consumes the reader past the HTTP // separator, so the body can be read fully later on. -pub fn (mut d DockerConn) read_response_head() ?http.Response { +fn (mut d DockerConn) read_response_head() ?http.Response { mut res := []u8{} util.read_until_separator(mut d.reader, mut res, vdocker.http_separator)? @@ -80,7 +80,7 @@ pub fn (mut d DockerConn) read_response_head() ?http.Response { // read_response_body reads `length` bytes from the stream. It can be used when // the response encoding isn't chunked to fully read it. -pub fn (mut d DockerConn) read_response_body(length int) ?string { +fn (mut d DockerConn) read_response_body(length int) ?string { if length == 0 { return '' } @@ -101,7 +101,7 @@ pub fn (mut d DockerConn) read_response_body(length int) ?string { // read_response is a convenience function which always consumes the entire // response & returns it. It should only be used when we're certain that the // result isn't too large. -pub fn (mut d DockerConn) read_response() ?(http.Response, string) { +fn (mut d DockerConn) read_response() ?(http.Response, string) { head := d.read_response_head()? if head.header.get(http.CommonHeader.transfer_encoding) or { '' } == 'chunked' { @@ -121,7 +121,7 @@ pub fn (mut d DockerConn) read_response() ?(http.Response, string) { // get_chunked_response_reader returns a ChunkedResponseReader using the socket // as reader. -pub fn (mut d DockerConn) get_chunked_response_reader() &ChunkedResponseReader { +fn (mut d DockerConn) get_chunked_response_reader() &ChunkedResponseReader { r := new_chunked_response_reader(d.reader) return r @@ -129,7 +129,7 @@ pub fn (mut d DockerConn) get_chunked_response_reader() &ChunkedResponseReader { // get_stream_format_reader returns a StreamFormatReader using the socket as // reader. -pub fn (mut d DockerConn) get_stream_format_reader() &StreamFormatReader { +fn (mut d DockerConn) get_stream_format_reader() &StreamFormatReader { r := new_chunked_response_reader(d.reader) r2 := new_stream_format_reader(r) diff --git a/volumes.v b/volumes.v new file mode 100644 index 0000000..ae97db1 --- /dev/null +++ b/volumes.v @@ -0,0 +1,33 @@ +module vdocker + +import net.http { Method } +import net.urllib +import json +import time + +struct Volume { + name string [json: Name] + driver string [json: Driver] + mountpoint string [json: Mountpoint] + created_at time.Time [json: CreatedAt] +} + +struct VolumeListResponse { + volumes []Volume [json: Volumes] + warnings []string [json: Warnings] +} + +pub fn (mut d DockerConn) volume_list() ?VolumeListResponse { + d.send_request(Method.get, urllib.parse('/v1.41/volumes')?)? + head, body := d.read_response()? + + if head.status_code != 200 { + data := json.decode(DockerError, body)? + + return error(data.message) + } + + data := json.decode(VolumeListResponse, body)? + + return data +} From 26357f47b5d444c09cdaaa58bf14bd6b47bb0141 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Sat, 18 Jun 2022 22:48:09 +0200 Subject: [PATCH 3/6] feat: fully implemented volume_list --- ROADMAP.md | 2 +- volumes.v | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 69f4048..68b953f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -61,7 +61,7 @@ reference](https://docs.docker.com/engine/api/v1.41/). - [ ] Delete unused networks * Volumes - - [ ] List volumes + - [*] List volumes - [ ] Create a volume - [ ] Inspect a volume - [ ] Remove a volume diff --git a/volumes.v b/volumes.v index ae97db1..1ef10b0 100644 --- a/volumes.v +++ b/volumes.v @@ -5,11 +5,23 @@ import net.urllib import json import time +struct UsageData { + size int [json: Size] + ref_count int [json: RefCount] +} + struct Volume { - name string [json: Name] - driver string [json: Driver] - mountpoint string [json: Mountpoint] - created_at time.Time [json: CreatedAt] + created_at_str string [json: CreatedAt] +pub mut: + name string [json: Name] + driver string [json: Driver] + mountpoint string [json: Mountpoint] + created_at time.Time [skip] + status map[string]string [json: Status] + labels map[string]string [json: Labels] + scope string [json: Scope] + options map[string]string [json: Options] + usage_data UsageData [json: UsageData] } struct VolumeListResponse { @@ -27,7 +39,11 @@ pub fn (mut d DockerConn) volume_list() ?VolumeListResponse { return error(data.message) } - data := json.decode(VolumeListResponse, body)? + mut data := json.decode(VolumeListResponse, body)? + + for mut vol in data.volumes { + vol.created_at = time.parse_rfc3339(vol.created_at_str)? + } return data } From 3bda79f7ce3a412a0cfc099361cc02afe0ae1a05 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 21 Jun 2022 15:47:42 +0200 Subject: [PATCH 4/6] refactor: simplified api call functions --- containers.v | 19 +++++++++++-------- docker.v | 33 +++++++++++++++++++++++++++++---- errors.v | 21 +++++++++++++++++++++ images.v | 7 +++---- volumes.v | 15 +++------------ 5 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 errors.v diff --git a/containers.v b/containers.v index 886c739..0abedff 100644 --- a/containers.v +++ b/containers.v @@ -1,12 +1,15 @@ module vdocker import json -import net.urllib import time import net.http { Method } -struct DockerError { - message string +pub struct ContainerListItem { + id string [json: Id] + names []string [json: Names] + image string [json: Image] + image_id string [json: ImageID] + command string [json: Command] } pub struct NewContainer { @@ -26,7 +29,7 @@ pub: // create_container creates a new container with the given config. pub fn (mut d DockerConn) create_container(c NewContainer) ?CreatedContainer { - d.send_request_with_json(Method.post, urllib.parse('/v1.41/containers/create')?, c)? + d.send_request_with_json(Method.post, '/containers/create', c)? head, res := d.read_response()? if head.status_code != 201 { @@ -42,7 +45,7 @@ pub fn (mut d DockerConn) create_container(c NewContainer) ?CreatedContainer { // start_container starts the container with the given id. pub fn (mut d DockerConn) start_container(id string) ? { - d.send_request(Method.post, urllib.parse('/v1.41/containers/$id/start')?)? + d.send_request(Method.post, 'containers/$id/start')? head, body := d.read_response()? if head.status_code != 204 { @@ -72,7 +75,7 @@ pub mut: // inspect_container returns detailed information for a given container. pub fn (mut d DockerConn) inspect_container(id string) ?ContainerInspect { - d.send_request(Method.get, urllib.parse('/v1.41/containers/$id/json')?)? + d.send_request(Method.get, 'containers/$id/json')? head, body := d.read_response()? if head.status_code != 200 { @@ -95,7 +98,7 @@ pub fn (mut d DockerConn) inspect_container(id string) ?ContainerInspect { // remove_container removes the container with the given id. pub fn (mut d DockerConn) remove_container(id string) ? { - d.send_request(Method.delete, urllib.parse('/v1.41/containers/$id')?)? + d.send_request(Method.delete, 'containers/$id')? head, body := d.read_response()? if head.status_code != 204 { @@ -108,7 +111,7 @@ pub fn (mut d DockerConn) remove_container(id string) ? { // get_container_logs returns a reader object allowing access to the // container's logs. pub fn (mut d DockerConn) get_container_logs(id string) ?&StreamFormatReader { - d.send_request(Method.get, urllib.parse('/v1.41/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 1784599..4920203 100644 --- a/docker.v +++ b/docker.v @@ -7,12 +7,15 @@ import strings import net.urllib import json import util +import time const ( socket = '/var/run/docker.sock' buf_len = 10 * 1024 http_separator = [u8(`\r`), `\n`, `\r`, `\n`] http_chunk_separator = [u8(`\r`), `\n`] + timestamp_attr = 'timestamp' + api_version = 'v1.41' ) pub struct DockerConn { @@ -39,7 +42,8 @@ pub fn (mut d DockerConn) close() ? { } // send_request sends an HTTP request without body. -fn (mut d DockerConn) send_request(method http.Method, url urllib.URL) ? { +fn (mut d DockerConn) send_request(method http.Method, url_str string) ? { + url := urllib.parse('/$api_version$url_str')? req := '$method $url.request_uri() HTTP/1.1\nHost: localhost\n\n' d.socket.write_string(req)? @@ -49,7 +53,8 @@ fn (mut d DockerConn) send_request(method http.Method, url urllib.URL) ? { } // send_request_with_body sends an HTTP request with the given body. -fn (mut d DockerConn) send_request_with_body(method http.Method, url urllib.URL, content_type string, body string) ? { +fn (mut d DockerConn) send_request_with_body(method http.Method, url_str string, content_type string, body string) ? { + url := urllib.parse('/$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)? @@ -60,10 +65,10 @@ fn (mut d DockerConn) send_request_with_body(method http.Method, url urllib.URL, // send_request_with_json is a convenience wrapper around // send_request_with_body that encodes the input as JSON. -fn (mut d DockerConn) send_request_with_json(method http.Method, url urllib.URL, data &T) ? { +fn (mut d DockerConn) send_request_with_json(method http.Method, url_str string, data &T) ? { body := json.encode(data) - return d.send_request_with_body(method, url, 'application/json', body) + return d.send_request_with_body(method, url_str, 'application/json', body) } // read_response_head consumes the socket's contents until it encounters @@ -119,6 +124,26 @@ fn (mut d DockerConn) read_response() ?(http.Response, string) { return head, res } +fn (mut d DockerConn) read_json_response() ?T { + head, body := d.read_response()? + + if head.status_code < 200 || head.status_code > 300 { + data := json.decode(DockerError, body)? + + return docker_error(head.status_code, data.message) + } + + mut data := json.decode(T, body)? + + /* $for field in T.fields { */ + /* $if field.typ is time.Time { */ + /* data.$(field.name) = time.parse_rfc3339(data.$(field.name + '_str'))? */ + /* } */ + /* } */ + + return data +} + // get_chunked_response_reader returns a ChunkedResponseReader using the socket // as reader. fn (mut d DockerConn) get_chunked_response_reader() &ChunkedResponseReader { diff --git a/errors.v b/errors.v new file mode 100644 index 0000000..ff24028 --- /dev/null +++ b/errors.v @@ -0,0 +1,21 @@ +module vdocker + +struct DockerError { + status int [skip] + message string +} + +fn (err DockerError) code() int { + return err.status +} + +fn (err DockerError) msg() string { + return err.message +} + +fn docker_error(status int, message string) IError { + return IError(DockerError{ + status: status + message: message + }) +} diff --git a/images.v b/images.v index 945951d..aeaa53f 100644 --- a/images.v +++ b/images.v @@ -1,7 +1,6 @@ module vdocker import net.http { Method } -import net.urllib import json struct Image { @@ -11,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, urllib.parse('/v1.41/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 { @@ -34,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, urllib.parse('/v1.41/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 { @@ -50,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, urllib.parse('/v1.41/images/$id')?)? + d.send_request(Method.delete, 'images/$id')? head, body := d.read_response()? if head.status_code != 200 { diff --git a/volumes.v b/volumes.v index 1ef10b0..b0c6a04 100644 --- a/volumes.v +++ b/volumes.v @@ -1,8 +1,6 @@ module vdocker import net.http { Method } -import net.urllib -import json import time struct UsageData { @@ -13,10 +11,10 @@ struct UsageData { struct Volume { created_at_str string [json: CreatedAt] pub mut: + created_at time.Time [skip] name string [json: Name] driver string [json: Driver] mountpoint string [json: Mountpoint] - created_at time.Time [skip] status map[string]string [json: Status] labels map[string]string [json: Labels] scope string [json: Scope] @@ -30,16 +28,9 @@ struct VolumeListResponse { } pub fn (mut d DockerConn) volume_list() ?VolumeListResponse { - d.send_request(Method.get, urllib.parse('/v1.41/volumes')?)? - head, body := d.read_response()? + d.send_request(Method.get, '/volumes')? - if head.status_code != 200 { - data := json.decode(DockerError, body)? - - return error(data.message) - } - - mut data := json.decode(VolumeListResponse, body)? + mut data := d.read_json_response()? for mut vol in data.volumes { vol.created_at = time.parse_rfc3339(vol.created_at_str)? From 4fe19d8f6a84fb62aa44bc597c9d7be9ea134085 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 21 Jun 2022 20:28:25 +0200 Subject: [PATCH 5/6] feat: implemented container_list --- ROADMAP.md | 4 +-- containers.v | 76 ++++++++++++++++++++++++++++++++++++++++++++++++---- docker.v | 30 ++++++++++----------- errors.v | 14 +++++----- volumes.v | 10 ++++++- 5 files changed, 104 insertions(+), 30 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 68b953f..52e22a2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -8,7 +8,7 @@ This list was taking from the [API reference](https://docs.docker.com/engine/api/v1.41/). * Containers - - [ ] List containers + - [x] List containers - [ ] Create a container - [ ] Inspect a container - [ ] List processes running inside a container @@ -61,7 +61,7 @@ reference](https://docs.docker.com/engine/api/v1.41/). - [ ] Delete unused networks * Volumes - - [*] List volumes + - [x] List volumes - [ ] Create a volume - [ ] Inspect a volume - [ ] Remove a volume diff --git a/containers.v b/containers.v index 0abedff..9991e75 100644 --- a/containers.v +++ b/containers.v @@ -4,12 +4,78 @@ import json import time import net.http { Method } +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] + 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 { diff --git a/docker.v b/docker.v index 4920203..9eaa1a9 100644 --- a/docker.v +++ b/docker.v @@ -14,8 +14,8 @@ const ( buf_len = 10 * 1024 http_separator = [u8(`\r`), `\n`, `\r`, `\n`] http_chunk_separator = [u8(`\r`), `\n`] - timestamp_attr = 'timestamp' - api_version = 'v1.41' + timestamp_attr = 'timestamp' + api_version = 'v1.41' ) pub struct DockerConn { @@ -43,7 +43,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('/$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)? @@ -54,7 +54,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('/$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)? @@ -127,21 +127,21 @@ fn (mut d DockerConn) read_response() ?(http.Response, string) { fn (mut d DockerConn) read_json_response() ?T { head, body := d.read_response()? - if head.status_code < 200 || head.status_code > 300 { - data := json.decode(DockerError, body)? + if head.status_code < 200 || head.status_code > 300 { + data := json.decode(DockerError, body)? - return docker_error(head.status_code, data.message) - } + return docker_error(head.status_code, data.message) + } - mut data := json.decode(T, body)? + mut data := json.decode(T, body)? - /* $for field in T.fields { */ - /* $if field.typ is time.Time { */ - /* data.$(field.name) = time.parse_rfc3339(data.$(field.name + '_str'))? */ - /* } */ - /* } */ + //$for field in T.fields { + //$if field.typ is time.Time { + // data.$(field.name) = time.parse_rfc3339(data.$(field.name + '_str'))? + //} + //} - return data + return data } // get_chunked_response_reader returns a ChunkedResponseReader using the socket diff --git a/errors.v b/errors.v index ff24028..e5da55a 100644 --- a/errors.v +++ b/errors.v @@ -1,21 +1,21 @@ module vdocker struct DockerError { - status int [skip] + status int [skip] message string } fn (err DockerError) code() int { - return err.status + return err.status } fn (err DockerError) msg() string { - return err.message + return err.message } fn docker_error(status int, message string) IError { - return IError(DockerError{ - status: status - message: message - }) + return IError(DockerError{ + status: status + message: message + }) } diff --git a/volumes.v b/volumes.v index b0c6a04..9642198 100644 --- a/volumes.v +++ b/volumes.v @@ -22,6 +22,14 @@ pub mut: usage_data UsageData [json: UsageData] } +[params] +pub struct VolumeListFilter { + dangling bool + driver string + labels []string + name string +} + struct VolumeListResponse { volumes []Volume [json: Volumes] warnings []string [json: Warnings] @@ -30,7 +38,7 @@ struct VolumeListResponse { pub fn (mut d DockerConn) volume_list() ?VolumeListResponse { d.send_request(Method.get, '/volumes')? - mut data := d.read_json_response()? + mut data := d.read_json_response()? for mut vol in data.volumes { vol.created_at = time.parse_rfc3339(vol.created_at_str)? From 959afd37e5169f08cb3257b7799d81749bfc7a5c Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Wed, 22 Jun 2022 08:17:58 +0200 Subject: [PATCH 6/6] refactor: renamed existing container functions to fit style --- Makefile | 3 --- containers.v | 17 ++++++----------- docker.v | 1 - 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 81b65fc..b25f105 100644 --- a/Makefile +++ b/Makefile @@ -22,9 +22,6 @@ api-docs: .PHONY: lint lint: $(V) fmt -verify . - $(V) vet -W . - $(V_PATH) missdoc -p . - @ [ $$($(V_PATH) missdoc -p . | wc -l) = 0 ] .PHONY: fmt fmt: diff --git a/containers.v b/containers.v index 9991e75..0aee8f4 100644 --- a/containers.v +++ b/containers.v @@ -61,7 +61,7 @@ pub struct ContainerListItem { created i64 [json: Created] ports []Port [json: Ports] size_rw i64 [json: SizeRw] - size_root_fs i64 [json: sizeRootFs] + size_root_fs i64 [json: SizeRootFs] labels map[string]string [json: Labels] state string [json: State] status string [json: Status] @@ -93,8 +93,7 @@ pub: warnings []string [json: Warnings] } -// create_container creates a new container with the given config. -pub fn (mut d DockerConn) create_container(c NewContainer) ?CreatedContainer { +pub fn (mut d DockerConn) container_create(c NewContainer) ?CreatedContainer { d.send_request_with_json(Method.post, '/containers/create', c)? head, res := d.read_response()? @@ -110,7 +109,7 @@ pub fn (mut d DockerConn) create_container(c NewContainer) ?CreatedContainer { } // start_container starts the container with the given id. -pub fn (mut d DockerConn) start_container(id string) ? { +pub fn (mut d DockerConn) container_start(id string) ? { d.send_request(Method.post, 'containers/$id/start')? head, body := d.read_response()? @@ -139,8 +138,7 @@ pub mut: end_time time.Time [skip] } -// inspect_container returns detailed information for a given container. -pub fn (mut d DockerConn) inspect_container(id string) ?ContainerInspect { +pub fn (mut d DockerConn) container_inspect(id string) ?ContainerInspect { d.send_request(Method.get, 'containers/$id/json')? head, body := d.read_response()? @@ -162,8 +160,7 @@ pub fn (mut d DockerConn) inspect_container(id string) ?ContainerInspect { return data } -// remove_container removes the container with the given id. -pub fn (mut d DockerConn) remove_container(id string) ? { +pub fn (mut d DockerConn) container_remove(id string) ? { d.send_request(Method.delete, 'containers/$id')? head, body := d.read_response()? @@ -174,9 +171,7 @@ pub fn (mut d DockerConn) remove_container(id string) ? { } } -// get_container_logs returns a reader object allowing access to the -// container's logs. -pub fn (mut d DockerConn) get_container_logs(id string) ?&StreamFormatReader { +pub fn (mut d DockerConn) container_get_logs(id string) ?&StreamFormatReader { d.send_request(Method.get, 'containers/$id/logs?stdout=true&stderr=true')? head := d.read_response_head()? diff --git a/docker.v b/docker.v index 9eaa1a9..a171a2e 100644 --- a/docker.v +++ b/docker.v @@ -7,7 +7,6 @@ import strings import net.urllib import json import util -import time const ( socket = '/var/run/docker.sock'