fix(archive): make sure it works
+ 47
- 4
@@ -1 +0,0 @@
-{"message":"page not found"}

src/docker/api/api_client.cr
@@ -42,7 +42,11 @@ class Docker::Api::ApiClient
 
   {% for method in %w(get post put head delete patch options) %}
     # Builds and executes a GET/POST/... request on a unix socket.
-    def unix_{{method.id}}(path : String, headers : HTTP::Headers? = nil, body : String? = nil)
+    def unix_{{method.id}}(
+      path : String,
+      headers : HTTP::Headers? = nil,
+      body : HTTP::Client::BodyType? = nil
+    )
       headers ||= HTTP::Headers.new
       headers = headers.dup
 

...
@@ -95,11 +99,19 @@ class Docker::Api::ApiClient
         response
       end
 
+      # cleanup response body send over docker socket
       raw = res_str
         .gsub("10f1\r\n", "") # ?
+        .gsub("10f", "")      # ?
         .gsub("11\r\n", "")   # ?
         .gsub("11c4\r\n", "") # ?
         .gsub("0\r\n", "")    # ?
+        .gsub("1321\r\n", "") # ?
+        .gsub("1322\r\n", "") # ?
+        .gsub("13\r\n", "")   # ?
+        .gsub("14\r\n", "")   # ?
+        .gsub("1d\r\n", "")   # ?
+        .gsub("4f\r\n", "")   # ?
 
       # # Parse status line, headers and body
       head, body = raw.split("\r\n\r\n", 2)

src/docker/api/containers.cr
@@ -116,6 +116,30 @@ module Docker::Api::Containers
     nil
   end
 
+  # Exec commands inside a container.
+  def exec(id : String, command : Array(String))
+    # create the exec request
+    props = {
+      "AttachStdout": true,
+      "AttachStderr": true,
+      "Cmd": command,
+      "Env": {
+        "FOO": "foo",
+      } of String => String, # make it configurable
+    }
+
+    exec_res = post "/containers/#{id}/exec", body: props.to_jsonbody
+    exec_id = JSON.parse(exec_res.body).as_h["Id"]
+
+    props = {
+      "Detach": false,
+      "Tty": false,
+    }
+
+    start_exec_res = post "/containers/#{id}/exec/start", body: props.to_json
+    nil
+  end
+
   # Get logs from a container
   def logs(
     id : String,

...
@@ -140,10 +164,12 @@ module Docker::Api::Containers
   def put_archive(id : String, path : String, archive : Bytes)
     headers = HTTP::Headers.new
     headers["Content-Type"] = "application/x-tar"
+    headers["Content-Length"] = archive.size.to_s
     params = HTTP::Params.build do |param|
       param.add "path", path
     end
-    response = put "/containers/#{id}/archive?#{params}", headers, archive
+    body = Bytes.new(archive).to_slice
+    response = put "/containers/#{id}/archive?#{params}", headers, body
     response.body
   end
 

@@ -5,7 +5,7 @@ require "./api/models/container"
 class Docker::Archive
   include Docker::ApiClientWrapper
 
-  def initialize(@client : Docker::Api::ApiClient, id : String)
+  def initialize(@client : Docker::Api::ApiClient, @id : String)
   end
 
   # Method to get an archive from container

src/docker/container.cr
@@ -55,6 +55,12 @@ class Docker::Container
     Docker::Archive.new(client, id)
   end
 
+  # Run command inside the container.
+  def exec(command: Array(String))
+    client.exec id, command
+    self
+  end
+
   # Start this container.
   def start
     client.start id