Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.

Commit e60720c

Browse files
authored
Merge pull request #119 from bergwolf/local_volume
support initialize local volume mapping in hyper run
2 parents dd41717 + cff0e7e commit e60720c

File tree

15 files changed

+2231
-21
lines changed

15 files changed

+2231
-21
lines changed

api/client/fip.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,39 @@ func fipUsage() string {
160160
help += fmt.Sprintf("\nRun 'hyper fip COMMAND --help' for more information on a command.")
161161
return help
162162
}
163+
164+
// Allocate and associate a fip
165+
func (cli *DockerCli) associateNewFip(contID string) (string, error) {
166+
fips, err := cli.client.FipAllocate("1")
167+
if err != nil {
168+
return "", err
169+
}
170+
171+
for _, ip := range fips {
172+
err = cli.client.FipAssociate(ip, contID)
173+
if err != nil {
174+
go func() {
175+
cli.client.FipRelease(ip)
176+
}()
177+
return "", err
178+
}
179+
return ip, nil
180+
}
181+
182+
return "", fmt.Errorf("Server failed to create new fip")
183+
}
184+
185+
// Release a fip
186+
func (cli *DockerCli) releaseFip(ip string) error {
187+
return cli.client.FipRelease(ip)
188+
}
189+
190+
// Disassociate and release a fip
191+
func (cli *DockerCli) releaseContainerFip(contID string) error {
192+
ip, err := cli.client.FipDisassociate(contID)
193+
if err != nil {
194+
return err
195+
}
196+
197+
return cli.client.FipRelease(ip)
198+
}

api/client/run.go

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/hyperhq/hypercli/pkg/signal"
2121
"github.com/hyperhq/hypercli/pkg/stringid"
2222
runconfigopts "github.com/hyperhq/hypercli/runconfig/opts"
23+
"github.com/satori/go.uuid"
2324
)
2425

2526
type InitVolume struct {
@@ -121,13 +122,13 @@ func (cli *DockerCli) initSpecialVolumes(config *container.Config, hostConfig *c
121122
var (
122123
initConfig *container.Config
123124
initHostConfig *container.HostConfig
124-
execJobs []string
125-
execID string
125+
errCh chan error
126+
execCount uint32
127+
fip string
126128
)
127129

128130
initConfig = &container.Config{
129131
User: config.User,
130-
Env: config.Env,
131132
Image: INIT_VOLUME_IMAGE,
132133
StopSignal: config.StopSignal,
133134
}
@@ -143,6 +144,8 @@ func (cli *DockerCli) initSpecialVolumes(config *container.Config, hostConfig *c
143144
for _, vol := range initvols {
144145
initHostConfig.Binds = append(initHostConfig.Binds, vol.Name+":"+INIT_VOLUME_PATH+vol.Destination)
145146
}
147+
passwd := uuid.NewV1()
148+
initConfig.Env = append(config.Env, "ROOTPASSWORD="+passwd.String(), "LOCALROOT="+INIT_VOLUME_PATH)
146149

147150
createResponse, err := cli.createContainer(initConfig, initHostConfig, networkingConfig, hostConfig.ContainerIDFile, "")
148151
if err != nil {
@@ -154,12 +157,18 @@ func (cli *DockerCli) initSpecialVolumes(config *container.Config, hostConfig *c
154157
fmt.Fprintf(cli.err, "clean up init container failed: %s\n", rmErr.Error())
155158
}
156159
}
160+
if fip != "" {
161+
if rmErr := cli.releaseFip(fip); rmErr != nil {
162+
fmt.Fprintf(cli.err, "failed to clean up container fip %s: %s\n", fip, rmErr.Error())
163+
}
164+
}
157165
}()
158166

159167
if err = cli.client.ContainerStart(createResponse.ID); err != nil {
160168
return err
161169
}
162170

171+
errCh = make(chan error, len(initvols))
163172
for _, vol := range initvols {
164173
var cmd []string
165174
volType := checkSourceType(vol.Source)
@@ -170,36 +179,62 @@ func (cli *DockerCli) initSpecialVolumes(config *container.Config, hostConfig *c
170179
parts := strings.Split(vol.Source, "/")
171180
cmd = append(cmd, "wget", "--no-check-certificate", "--tries=5", "--mirror", "--no-host-directories", "--cut-dirs="+strconv.Itoa(len(parts)), vol.Source, "--directory-prefix="+INIT_VOLUME_PATH+vol.Destination)
172181
case "local":
173-
// TODO
182+
execCount++
183+
if fip == "" {
184+
fip, err = cli.associateNewFip(createResponse.ID)
185+
if err != nil {
186+
return err
187+
}
188+
}
189+
go func(vol *InitVolume) {
190+
err := cli.uploadLocalResource(vol.Source, INIT_VOLUME_PATH+vol.Destination, fip, "root", passwd.String())
191+
if err != nil {
192+
err = fmt.Errorf("Failed to upload %s: %s", vol.Source, err.Error())
193+
}
194+
errCh <- err
195+
}(vol)
174196
default:
175197
continue
176198
}
177199
if len(cmd) == 0 {
178200
continue
179201
}
180-
if execID, err = cli.ExecCmd(initConfig.User, createResponse.ID, cmd); err != nil {
181-
return err
182-
} else {
183-
execJobs = append(execJobs, execID)
184-
}
202+
203+
execCount++
204+
go func() {
205+
execID, err := cli.ExecCmd(initConfig.User, createResponse.ID, cmd)
206+
if err != nil {
207+
errCh <- err
208+
} else {
209+
errCh <- cli.WaitExec(execID)
210+
}
211+
}()
185212
}
186213

187214
// wait results
188-
for _, execID = range execJobs {
189-
if err = cli.WaitExec(execID); err != nil {
215+
for ; execCount > 0; execCount-- {
216+
err = <-errCh
217+
if err != nil {
190218
return err
191219
}
192220
}
193221

194-
// Need to sync before tearing down container because data might be still cached
195-
if len(execJobs) > 0 {
196-
syncCmd := []string{"sync"}
197-
if execID, err = cli.ExecCmd(initConfig.User, createResponse.ID, syncCmd); err != nil {
198-
return err
199-
}
200-
if err = cli.WaitExec(execID); err != nil {
222+
// release fip
223+
if fip != "" {
224+
if err = cli.releaseContainerFip(createResponse.ID); err != nil {
201225
return err
202226
}
227+
fip = ""
228+
}
229+
230+
// Need to sync before tearing down container because data might be still cached
231+
syncCmd := []string{"sync"}
232+
execID, err := cli.ExecCmd(initConfig.User, createResponse.ID, syncCmd)
233+
if err != nil {
234+
return err
235+
}
236+
if err = cli.WaitExec(execID); err != nil {
237+
return err
203238
}
204239

205240
_, err = cli.removeContainer(createResponse.ID, false, false, true)

api/client/utils.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ import (
1414
"time"
1515

1616
"github.com/Sirupsen/logrus"
17-
"github.com/hyperhq/hypercli/pkg/signal"
18-
"github.com/hyperhq/hypercli/pkg/term"
19-
"github.com/hyperhq/hypercli/registry"
2017
"github.com/docker/engine-api/client"
2118
"github.com/docker/engine-api/types"
2219
registrytypes "github.com/docker/engine-api/types/registry"
20+
"github.com/dutchcoders/goftp"
21+
"github.com/hyperhq/hypercli/pkg/signal"
22+
"github.com/hyperhq/hypercli/pkg/term"
23+
"github.com/hyperhq/hypercli/registry"
2324
)
2425

2526
func (cli *DockerCli) electAuthServer() string {
@@ -216,3 +217,32 @@ func (cli *DockerCli) resolveAuthConfig(authConfigs map[string]types.AuthConfig,
216217
// When all else fails, return an empty auth config
217218
return types.AuthConfig{}
218219
}
220+
221+
// uploadLocalResource upload a local file/directory to a container
222+
func (cli *DockerCli) uploadLocalResource(source, dest, serverIP, user, passwd string) error {
223+
if !strings.Contains(serverIP, ":") {
224+
serverIP += ":21"
225+
}
226+
ftp, err := goftp.Connect(serverIP)
227+
if err != nil {
228+
return err
229+
}
230+
231+
defer func() {
232+
ftp.Close()
233+
}()
234+
235+
if err = ftp.Login(user, passwd); err != nil {
236+
return err
237+
}
238+
239+
if err = ftp.Cwd(dest); err != nil {
240+
return err
241+
}
242+
243+
if err = ftp.Upload(source); err != nil {
244+
return err
245+
}
246+
247+
return nil
248+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2014
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
goftp
2+
=====
3+
4+
Golang FTP library with Walk support.
5+
6+
## Features
7+
8+
* AUTH TLS support
9+
* Walk
10+
11+
## Sample
12+
package main
13+
14+
import (
15+
"crypto/sha256"
16+
"crypto/tls"
17+
"fmt"
18+
"io"
19+
"os"
20+
21+
"github.com/dutchcoders/goftp"
22+
)
23+
24+
func main() {
25+
var err error
26+
var ftp *goftp.FTP
27+
28+
// For debug messages: goftp.ConnectDbg("ftp.server.com:21")
29+
if ftp, err = goftp.Connect("ftp.server.com:21"); err != nil {
30+
panic(err)
31+
}
32+
33+
defer ftp.Close()
34+
35+
config := tls.Config{
36+
InsecureSkipVerify: true,
37+
ClientAuth: tls.RequestClientCert,
38+
}
39+
40+
if err = ftp.AuthTLS(config); err != nil {
41+
panic(err)
42+
}
43+
44+
if err = ftp.Login("username", "password"); err != nil {
45+
panic(err)
46+
}
47+
48+
if err = ftp.Cwd("/"); err != nil {
49+
panic(err)
50+
}
51+
52+
var curpath string
53+
if curpath, err = ftp.Pwd(); err != nil {
54+
panic(err)
55+
}
56+
57+
fmt.Printf("Current path: %s", curpath)
58+
59+
var files []string
60+
if files, err = ftp.List(""); err != nil {
61+
panic(err)
62+
}
63+
64+
fmt.Println(files)
65+
66+
var file *os.File
67+
if file, err = os.Open("/tmp/test.txt"); err != nil {
68+
panic(err)
69+
}
70+
71+
if err := ftp.Stor("/test.txt", file); err != nil {
72+
panic(err)
73+
}
74+
75+
err = ftp.Walk("/", func(path string, info os.FileMode, err error) error {
76+
_, err = ftp.Retr(path, func(r io.Reader) error {
77+
var hasher = sha256.New()
78+
if _, err = io.Copy(hasher, r); err != nil {
79+
return err
80+
}
81+
82+
hash := fmt.Sprintf("%s %x", path, sha256.Sum256(nil))
83+
fmt.Println(hash)
84+
85+
return err
86+
})
87+
88+
return nil
89+
})
90+
}
91+
92+
## Contributions
93+
94+
Contributions are welcome.
95+
96+
* Sourav Datta: for his work on the anonymous user login and multiline return status.
97+
* Vincenzo La Spesa: for his work on resolving login issues with specific ftp servers
98+
99+
100+
## Creators
101+
102+
**Remco Verhoef**
103+
- <https://twitter.com/remco_verhoef>
104+
- <https://twitter.com/dutchcoders>
105+
106+
## Copyright and license
107+
108+
Code and documentation copyright 2011-2014 Remco Verhoef.
109+
Code released under [the MIT license](LICENSE).
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
23+
*/
24+
25+
// ftp client library with Walk and TLS support
26+
27+
package goftp

0 commit comments

Comments
 (0)