harbor icon indicating copy to clipboard operation
harbor copied to clipboard

R6 Class - Enhancement

Open The-Dub opened this issue 8 years ago • 4 comments

I was looking at the source code of harbor to figure out why splashr wasn't working and - I don't know if it's a good idea or not, but throwing it out there - I was wondering if it would be easier for debug & sanity check within functions to use R6 classes?

The structure for opening a docker would be something like boat <- harbor$new('NameOfTheDocker')

Other packages (let's say harbor) having dependency on harbor would also be R6 class being sub-class of the harbor class, for example:

splash <- R6Class('splash', 
inheritance = harbor::harbor, 
public = list(
initialize =  function(host = harbor::localhost) {
  harbor::docker_run(host,
                     image = "scrapinghub/splash",
                     detach = TRUE,
                     docker_opts = c("-p", "5023:5023",
                                     "-p", "8050:8050",
                                     "-p", "8051:8051"))
},
...
)

I forked the repo and will try to get a crack at it tonight, but if @hrbrmstr think it's a bad idea, I'll just let it go :) !

Cheers

The-Dub avatar Feb 16 '17 15:02 The-Dub

Definitely not against switching to R6 (I was initially just trying to "get'er done").

An S3 class is always the path of least resistance but right now I can see a few different flavors of harbor:

  • Localhost direct Docker instrumentation via the command-line
  • remote Docker instrumentation via ssh / command-line
  • local Docker instrumentation via the HTTP API
  • remote Docker instrumentation via ssh tunnel to HTTP API
  • direct remote Docker instrumentation via HTTP API (which shld only be used on private, non-internet-facing networks)

Those could be crammed into S3 but R6 might make sense. We'd just need to design the base class to support all that (and anything others can come up with).

hrbrmstr avatar Feb 16 '17 17:02 hrbrmstr

I'm learning about dockers, but I can clearly see why they are so powerful. I feel like localhost is the easiest, and probably should be implemented first, as a "solid base"

One problem might be being cross platform, to please the windows people...

The-Dub avatar Feb 16 '17 17:02 The-Dub

Some possible beginnings of underpinnings for querying the API directly below. Needs a source build of curl on macOS and those environment variables set.

library(curl)
library(jsonlite)
library(openssl)

docker_auth <- function(username=Sys.getenv("DOCKER_USERNAME"),
                        password=Sys.getenv("DOCKER_PASSWORD"),
                        email=Sys.getenv("DOCKER_EMAIL"),
                        server_address=Sys.getenv("DOCKER_REGISTRY"),
                        encode=TRUE) {

  toJSON(
    list(
      username=unbox(username),
      password=unbox(password),
      email=unbox(email),
      auth=unbox(""),
      serveraddress=unbox(server_address)
    )
  ) -> auth_json

  if (encode) auth_json <- openssl::base64_encode(auth_json)

  auth_json

}

docker_handle <- function(verbose=FALSE) {
  h <- curl::new_handle()
  h <- curl::handle_reset(h)
  h <- curl::handle_setopt(h, UNIX_SOCKET_PATH = "/var/run/docker.sock")
  h <- curl::handle_setopt(h, VERBOSE = verbose)
  h <- curl::handle_setheaders(h,
                               `Content-Type` = "application/json",
                               `X-Registry-Auth` = docker_auth())
  h
}

# Auth check ------------------------------------------------------------------------
h <- docker_handle(TRUE)
handle_setopt(h, copypostfields = docker_auth(encode=FALSE))
res <- curl_fetch_memory(url = "http://v1.26/auth", handle = h)
str(fromJSON(rawToChar(res$content)))

# Docker info -----------------------------------------------------------------------
h <- docker_handle()
res <- curl_fetch_memory(url = "http://v1.26/info", handle = h)
str(fromJSON(rawToChar(res$content)))

# Docker version --------------------------------------------------------------------
h <- docker_handle()
res <- curl_fetch_memory(url = "http://v1.26/version", handle = h)
str(fromJSON(rawToChar(res$content)))

# Docker ping -----------------------------------------------------------------------
h <- docker_handle()
res <- curl_fetch_memory(url = "http://v1.26/_ping", handle = h)
cat(rawToChar(res$content))

# Data usage ------------------------------------------------------------------------
h <- docker_handle()
res <- curl_fetch_memory(url = "http://v1.26/system/df", handle = h)
str(fromJSON(rawToChar(res$content)))

# List images -----------------------------------------------------------------------
h <- docker_handle()
res <- curl_fetch_memory(url = "http://v1.26/images/json", handle = h)
str(fromJSON(rawToChar(res$content)))

# Search images ---------------------------------------------------------------------
h <- docker_handle()
res <- curl_fetch_memory(url = "http://v1.26/images/search?term=alpine&limit=10", handle = h)
str(fromJSON(rawToChar(res$content)))

# Pull an image ---------------------------------------------------
h <- docker_handle(verbose = TRUE)
handle_setopt(h, copypostfields = '')
res <- curl_fetch_memory(url = "http://v1.26/images/create?fromImage=alpine&tag=latest", handle = h)
cat(rawToChar(res$content))

# List running containers -----------------------------------------------------------
h <- docker_handle()
res <- curl_fetch_memory(url = "http://v1.26/containers/json", handle = h)
str(fromJSON(rawToChar(res$content)))

# all: true/false
# limit: int
# size: true/false
# filters: json
h <- docker_handle()
res <- curl_fetch_memory(url = "http://v1.26/containers/json", handle = h)
str(fromJSON(rawToChar(res$content)))

# Inspect a container ---------------------------------------------------------------

# size: true/false
h <- docker_handle(verbose = TRUE)
res <- curl_fetch_memory(url = "http://v1.26/containers/b834259b9e9ed70cd00a43c9a539ab0601dab68a5966e531fea76ec91bc76940/json", handle = h)
str(fromJSON(rawToChar(res$content)))

# List container processes ----------------------------------------------------------

# ps_args: string
h <- docker_handle(verbose = TRUE)
res <- curl_fetch_memory(url = "http://v1.26/containers/b834259b9e9ed70cd00a43c9a539ab0601dab68a5966e531fea76ec91bc76940/top", handle = h)
str(fromJSON(rawToChar(res$content)))

# Get container logs ----------------------------------------------------------------

# follow: true/false
# stdout: t/f
# stderr: r/f
# since: int
# timestamps: t/f
# tail: string
h <- docker_handle(verbose = TRUE)
res <- curl_fetch_memory(url = "http://v1.26/containers/b834259b9e9ed70cd00a43c9a539ab0601dab68a5966e531fea76ec91bc76940/logs?stdout=true&stderr=true", handle = h)
cat(rawToChar(res$content[res$content > 0x09]))


# Run a container -------------------------------------------------------------------
h <- docker_handle()
handle_setopt(h, copypostfields = '{"Image": "alpine", "Cmd": ["echo", "hello world"]}')
res <- curl_fetch_memory(url = "http:/v1.26/containers/create", handle = h)
str(fromJSON(rawToChar(res$content)))

hrbrmstr avatar Feb 17 '17 18:02 hrbrmstr

Moving API discussion to #11

hrbrmstr avatar Feb 17 '17 20:02 hrbrmstr