Comments (33)
Hi @gravis, sorry about the delay.
The testing server is intended to be used in the same place as an actual server, so you can point a Client instance to it. Something like:
server, err := testing.NewServer("127.0.0.1:0", nil)
// ...
client, err := docker.NewClient(server.URL())
// use the client
from go-dockerclient.
Ok, but how do you use the wait command then? The container is stuck
until timeout. :(
Thanks
from go-dockerclient.
You would need to call Stop + Wait. I think we have something like this in tsuru, please hold on.
from go-dockerclient.
Just confirmed: we have a gorountine that stops the container and automatically "unblocks" the WaitContainer call.
from go-dockerclient.
Ok, thanks. It would be nice if you could share some code here, I'm still very confused.
I'm trying to test a command (ie: entrypoint) inside a container, in pseudo code, it's something like:
CreateContainer
StartContainer
WaitContainer
CopyFilesFromContainer
RemoveContainer
If I run a go routine to stop the container, how can I have hands on the resulting files inside the container? AFAIU, stopping the container will just emulate a timeout :(
Thanks
from go-dockerclient.
I see. You will need to manually stop the container anyway, don't you? I mean, if methods weren't private in the testing server, how would you write your test?
Instead of using a goroutine, you could stop the container at any time, the time that you would access the testing server and mark the container as stopped, unleashing the WaitContainer call.
from go-dockerclient.
Currently, I'm creating a real http server, with methods like:
mux.HandleFunc(fmt.Sprintf("/containers/%s/attach", container_id), func(w http.ResponseWriter, r *http.Request) {
outStream := utils.NewStdWriter(w, utils.Stdout)
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
fmt.Fprint(outStream, requires_txt)
})
Maybe being able to pass my own handlers would be enough.
Otherwise, I would need:
- A func to get the list of running containers (I should have only one)-
- A func to stop the container (currently private func)
- A func to set the output of a container (attach a io.Reader to all new created containers?)
What do you think?
from go-dockerclient.
Hmm, this is interesting. Do you thing that making the server extensible, so you can specify the handler for an operation is enough?
What about the API? Something like:
Server.CustomHandler(path string, handler http.Handler)
Should the path be a regular expression or the actual path?
In your case, it would be:
server.CustomHandler(fmt.Sprintf("/containers/%s/attach", container_id), func(w http.ResponseWriter, r *http.Request) {
outStream := utils.NewStdWriter(w, utils.Stdout)
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
fmt.Fprint(outStream, requires_txt)
})
What do you think?
from go-dockerclient.
Sounds like a terrific idea. I still need a func to get the container_id
btw.
What would be more awesome is to pass something like chan *docker.Container
(buffered) to NewServer, and then send the container on the channel when created. I would be able to wait exactly the time needed, and get the container_id directly :)
But I think we're heading in the right direction, and I really appreciate your open mind :)
from go-dockerclient.
What about:
http://play.golang.org/p/7dLcZ5ksuW
:)
from go-dockerclient.
Nice snippet, cChan should be exported, right?
Also, the channel should be fed when the client calls CreateContainer, and not on NewServer.
What do you think? Sounds fair?
from go-dockerclient.
Sure, it was a proof of concept. I'm very glad you like it
Indeed, cChan should be exported, and the container sent on create, not on server creation :)
We mustn't forget to close the chan when server.Close() is called btw.
Thanks!
from go-dockerclient.
Sorry for the huge delay. I'm planning to do it, but can you confirm that this flow will be enough for your use case?
from go-dockerclient.
No problem at all. Yes, I think this would be really make it. If I find blocking issues, I will propose PRs anymay :)
Thanks a lot
from go-dockerclient.
Can you take a look at #113? Thanks!
from go-dockerclient.
I've just pushed the CustomHandler method, can you take a look? :) Is it good?
from go-dockerclient.
Damned, you're fast :)
Will take a look this week-end, I promise!
from go-dockerclient.
No hurry man :) I was wondering: should we add a method to remove the custom handler?
from go-dockerclient.
Sorry, I still need some time to test this. I'm fighting a nasty bug with AttachContainer, hitting 100% CPU when getting container logs, and blocking all my routines :(
from go-dockerclient.
No problem. Is it the testing server or the real server? Is the client or the server hitting 100% CPU? I may help debugging it, if you have a reproducer. :)
from go-dockerclient.
I have opened a ticket actually: #114
It's painfull to debug, because it occurs very randomly :(
from go-dockerclient.
@gravis thanks for reporting it!
from go-dockerclient.
I'm wondering if it's the good approach now. I have started to replace my fake docker with testing.DockerServer, and ended up with copying/pasting the content of https://github.com/fsouza/go-dockerclient/blob/master/testing/server.go#L397, just to be able to replace the 2 last lines...
There's probably something else to explore. Maybe a CustomAttachOutput
, instead of overriding the whole container method?
from go-dockerclient.
@gravis what about something like SetContainerOutput
?
from go-dockerclient.
sounds good! Sorry for changing target like that. It's only when you have hands in the code that you realize how the API should behave... :(
from go-dockerclient.
I also have some files I need to write in the container, I don't think there a method to add files in a container ? If not, I will probably need also something like: AddFileToContainer(r io.Reader, path string) error
from go-dockerclient.
@gravis how would you access these files?
Currently, "go-dockerclient" doesn't support copying files from the container. Wouldn't you need a CopyFiles
method as well?
from go-dockerclient.
From the container? You mean, TO the container, right? If it is TO the container, yes, it will be needed :)
from go-dockerclient.
Sorry, I meant from the container, but I think I'm misunderstanding your use case.
Will you insert files in the container in the testing server? What's the purpose? I mean, the test code would look like:
runTheServer()
insertFileInTheContainer()
callTheProductionCode()
What does the production code do?
from go-dockerclient.
Ok, to sum up. We have containers to run isolated processes. Theses commands will generate some output (container logs), and some files to be copied from the container, and sent to another API.
To be able to test, I currently create a fake server (see below). It would be an improvement to use something closer to docker, like the testing server.
requires_txt := "Flask==0.8\nJinja2==2.6"
mux := http.NewServeMux()
// CreateContainer stub
container_id := "5fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
mux.HandleFunc(fmt.Sprintf("/containers/create"), func(w http.ResponseWriter, r *http.Request) {
jsonContainer := fmt.Sprintf(`{
"Id": "%s",
"Warnings": []
}`, container_id)
fmt.Fprint(w, jsonContainer)
})
// StartContainer stub
mux.HandleFunc(fmt.Sprintf("/containers/%s/start", container_id), func(w http.ResponseWriter, r *http.Request) {})
// WaitContainer stub
mux.HandleFunc(fmt.Sprintf("/containers/%s/wait", container_id), func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{"StatusCode": 0}`)
})
mux.HandleFunc(fmt.Sprintf("/containers/%s/attach", container_id), func(w http.ResponseWriter, r *http.Request) {
outStream := utils.NewStdWriter(w, utils.Stdout)
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
fmt.Fprint(outStream, requires_txt)
})
// CopyFromContainer stub
mux.HandleFunc(fmt.Sprintf("/containers/%s/copy", container_id), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/octet-stream")
// Create a buffer to write our archive to.
buf := new(bytes.Buffer)
// Create a new tar archive.
tw := tar.NewWriter(buf)
// Add some files to the archive.
var files = []struct {
Name, Body string
}{
{"requires.txt", requires_txt},
}
for _, file := range files {
hdr := &tar.Header{
Name: file.Name,
Size: int64(len(file.Body)),
}
if err := tw.WriteHeader(hdr); err != nil {
log.Fatal(err)
}
if _, err := tw.Write([]byte(file.Body)); err != nil {
log.Fatal(err)
}
}
// Make sure to check the error on Close.
if err := tw.Close(); err != nil {
log.Fatal(err)
}
if _, err := io.Copy(w, buf); err != nil {
// return err
}
})
server := httptest.NewServer(mux)
from go-dockerclient.
I understand now. In order to insert files into the container or customise the output, the container would have to exist, so you'd need to be able to call the methods SetContainerOutput
and AddFileToContainer
after the CreateContainer call, but before the Logs/Attach and CopyFromContainer calls.
Am I understanding it right? I think this is a scenario that is quite hard to test.
from go-dockerclient.
You're 100% right :)
from go-dockerclient.
I don't think you would be able to guarantee such order. You'd need some mechanism to "pre-register" the container, and have CreateContainer returning that container. Something like:
container, err := server.PrepareContainerForCreation()
server.SetContainerOutput(container, "something")
server.AddFileToTheContainer(container, "/filename", "file content")
server.AddFileToTheContainer(container, "/etc/filename", "file content")
server.AddFileToTheContainer(container, "/tmp/filename", "file content")
<call production code>
<do assertions>
Then the production code will call CreateContainer, StartContainer, WaitContainer, AttachToContainer and CopyFromContainer, using the container returned by CreateContainer, that is the container previously prepared for creation. This would enable us to prepare the behaviour of a container before creating it. Also, as far as I can tell, we would not need the custom handler anymore.
What do you think?
from go-dockerclient.
Related Issues (20)
- Can auth and pull image locally, but not on dev servers HOT 1
- How to use the detach option when calling CreateContainer? HOT 1
- Add support SSH protocol for remote docker
- Please add Internal property into ContainerNetwork HOT 1
- With the Latest Docker Engine v25.x the Version Selection Magic Based on the Call Option 'ver` Tags Results in Failing Calls HOT 2
- New release HOT 3
- Looking for an example of Attach. HOT 5
- Error message may leak credentials used for mounting HOT 15
- RemoveEventListener cause connection leak HOT 6
- How to get the value of NAMES field? HOT 1
- Missing some fields to support Stats API on Docker host uses cgroup2
- What would be the best way to specify version of docker api, so that go-dockerclient can adjust requests and response expectations accordingly? HOT 4
- Error trying to run ddev start after configure drupal 9 on windows HOT 3
- How to run a docker container with GPU support? HOT 1
- How to build an image with specific Tag? HOT 1
- Get error if call func updateService HOT 2
- The module name change issues HOT 5
- EndpointIPAMConfig: Unable to Unmarshal using yaml HOT 3
- About the "Remote" arg in the BuildImageOptions may cause the io error HOT 1
- Wrong error propagation in context HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from go-dockerclient.