Skip to content

Commit f9aa5ef

Browse files
authored
Merge pull request #90 from Azure/dev
v0.6.09
2 parents aad0dc9 + c1235af commit f9aa5ef

14 files changed

+313
-105
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ _test
99
_build/linux_amd64
1010
_build/windows_amd64
1111
_wd
12+
_old
1213
.vscode
1314

1415
# Architecture specific extensions/prefixes

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Sources and targets are decoupled, this design enables the composition of variou
2929
Download, extract and set permissions:
3030

3131
```bash
32-
wget -O bp_linux.tar.gz https://github.com/Azure/blobporter/releases/download/v0.6.07/bp_linux.tar.gz
32+
wget -O bp_linux.tar.gz https://github.com/Azure/blobporter/releases/download/v0.6.09/bp_linux.tar.gz
3333
tar -xvf bp_linux.tar.gz linux_amd64/blobporter
3434
chmod +x ~/linux_amd64/blobporter
3535
cd ~/linux_amd64
@@ -46,7 +46,7 @@ export ACCOUNT_KEY=<STORAGE_ACCOUNT_KEY>
4646
4747
### Windows
4848

49-
Download [BlobPorter.exe](https://github.com/Azure/blobporter/releases/download/v0.6.07/bp_windows.zip)
49+
Download [BlobPorter.exe](https://github.com/Azure/blobporter/releases/download/v0.6.09/bp_windows.zip)
5050

5151
Set environment variables (if using the command prompt):
5252

@@ -208,6 +208,8 @@ By default files are downloaded to the same directory where you are running blob
208208

209209
- `i`, `--remove_directories` *bool* if set blobs are downloaded or uploaded without keeping the directory structure of the source. Not applicable when the source is a HTTP endpoint.
210210

211+
- `o`, `--read_token_exp` *int* Expiration in minutes of the read-only access token that will be generated to read from S3 or Azure Blob sources. Default value: 360.
212+
211213
## Performance Considerations
212214

213215
By default, BlobPorter creates 5 readers and 8 workers for each core on the computer. You can overwrite these values by using the options -r (number of readers) and -g (number of workers). When overriding these options there are few considerations:

_build/release0609.zip

5.05 MB
Binary file not shown.

args.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"runtime"
99
"strings"
1010

11+
"github.com/Azure/blobporter/internal"
1112
"github.com/Azure/blobporter/sources"
1213
"github.com/Azure/blobporter/targets"
1314
"github.com/Azure/blobporter/transfer"
@@ -31,9 +32,10 @@ const numOfWorkersFactor = 8
3132
const numOfReadersFactor = 5
3233
const defaultNumberOfFilesInBatch = 500
3334
const defaultNumberOfHandlesPerFile = 2
34-
const defaultHTTPClientTimeout = 30
35+
const defaultHTTPClientTimeout = 60
3536
const defaultBlockSizeStr = "8MB"
3637
const defaultDedupeLevelStr = "None"
38+
const defaultReadTokenExp = 360
3739

3840
//sets the parameters by parsing and validating the arguments
3941
type paramParserValidator struct {
@@ -67,6 +69,7 @@ type arguments struct {
6769
exactNameMatch bool
6870
removeDirStructure bool
6971
hTTPClientTimeout int
72+
readTokenExp int
7073
numberOfHandlesPerFile int //numberOfHandlesPerFile = defaultNumberOfHandlesPerFile
7174
numberOfFilesInBatch int //numberOfFilesInBatch = defaultNumberOfFilesInBatch
7275
}
@@ -109,6 +112,7 @@ type blobParams struct {
109112
container string
110113
prefixes []string
111114
baseBlobURL string
115+
sasExpMin int
112116
}
113117

114118
func (b blobParams) isSourceAuthAndContainerInfoSet() bool {
@@ -134,14 +138,16 @@ func newParamParserValidator() paramParserValidator {
134138
numberOfWorkers: defaultNumberOfWorkers,
135139
blockSizeStr: defaultBlockSizeStr,
136140
dedupeLevelOptStr: defaultDedupeLevelStr,
141+
readTokenExp: defaultReadTokenExp,
137142
transferDefStr: string(transfer.FileToBlock),
138143
numberOfHandlesPerFile: defaultNumberOfHandlesPerFile,
139144
hTTPClientTimeout: defaultHTTPClientTimeout,
140145
numberOfFilesInBatch: defaultNumberOfFilesInBatch}
141146
params := &validatedParameters{
142147
s3Source: s3Source{
143-
preSignedExpMin: defaulPreSignedExpMins},
144-
blobSource: blobParams{},
148+
preSignedExpMin: defaultReadTokenExp},
149+
blobSource: blobParams{
150+
sasExpMin: defaultReadTokenExp},
145151
blobTarget: blobParams{}}
146152

147153
p := paramParserValidator{args: args, params: params}
@@ -256,6 +262,7 @@ func (p *paramParserValidator) pvgQuietMode() error {
256262
p.params.quietMode = p.args.quietMode
257263
return nil
258264
}
265+
259266
func (p *paramParserValidator) pvgCalculateReadersAndWorkers() error {
260267

261268
if p.args.numberOfWorkers <= 0 {
@@ -289,10 +296,10 @@ func (p *paramParserValidator) pvgBatchLimits() error {
289296
}
290297
func (p *paramParserValidator) pvgHTTPTimeOut() error {
291298
if p.args.hTTPClientTimeout < defaultHTTPClientTimeout {
292-
fmt.Printf("Warning! The storage HTTP client timeout is too low (<30). Setting value to default (%v)s \n", defaultHTTPClientTimeout)
299+
fmt.Printf("Warning! The HTTP timeout is too low (<30). Setting value to default (%v)s \n", defaultHTTPClientTimeout)
293300
p.args.hTTPClientTimeout = defaultHTTPClientTimeout
294301
}
295-
util.HTTPClientTimeout = p.args.hTTPClientTimeout
302+
internal.HTTPClientTimeout = p.args.hTTPClientTimeout
296303
return nil
297304
}
298305
func (p *paramParserValidator) pvgDupCheck() error {
@@ -431,6 +438,12 @@ func (p *paramParserValidator) pvSourceInfoForBlobIsReq() error {
431438

432439
p.params.blobSource.prefixes = p.args.blobNames
433440

441+
if p.args.readTokenExp < 1 {
442+
return fmt.Errorf("Invalid read token expiration value. Minimum is 1 (1m)")
443+
}
444+
445+
p.params.blobSource.sasExpMin = p.args.readTokenExp
446+
434447
if p.params.blobSource.isSourceAuthAndContainerInfoSet() {
435448
return nil
436449
}
@@ -477,6 +490,12 @@ func (p *paramParserValidator) pvSourceInfoForBlobIsReq() error {
477490
return fmt.Errorf("The source storage acccount key (env variable: %v) is required for this transfer type", sourceAuthorizationEnvVar)
478491
}
479492

493+
if p.args.readTokenExp < 1 {
494+
return fmt.Errorf("Invalid read token expiration value. Minimum is 1 (1m)")
495+
}
496+
497+
p.params.blobSource.sasExpMin = p.args.readTokenExp
498+
480499
return nil
481500
}
482501

@@ -519,6 +538,12 @@ func (p *paramParserValidator) pvSourceInfoForS3IsReq() error {
519538
return fmt.Errorf("The S3 secret key is required for this transfer type. Environment variable name:%v", s3SecretKeyEnvVar)
520539
}
521540

541+
if p.args.readTokenExp < 1 {
542+
return fmt.Errorf("Invalid read token expiration value. Minimum is 1 (1m)")
543+
}
544+
545+
p.params.s3Source.preSignedExpMin = p.args.readTokenExp
546+
522547
return nil
523548
}
524549

args_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,31 @@ func TestBasicUploadWithAlias(t *testing.T) {
4040
assert.Equal(t, val.args.sourceURIs[0], val.params.sourceURIs[0], "source is missing")
4141
assert.Equal(t, val.args.blobNames[0], val.params.targetAliases[0], "target alias is missing")
4242
}
43+
func TestReadTokenExpForBlobSource(t *testing.T) {
44+
val := newParamParserValidator()
45+
val.args.blobNames = []string{"data"}
46+
val.args.storageAccountName = "myaccount"
47+
val.args.storageAccountKey = "mykey"
48+
val.args.containerName = "mycont"
49+
val.args.transferDefStr = "blob-file"
50+
51+
err := val.parseAndValidate()
52+
assert.NoError(t, err, "un expected error, all params should be set")
53+
assert.Equal(t, defaultReadTokenExp, val.params.blobSource.sasExpMin, "expiration time is not the default")
54+
55+
val = newParamParserValidator()
56+
val.args.blobNames = []string{"data"}
57+
val.args.storageAccountName = "myaccount"
58+
val.args.storageAccountKey = "mykey"
59+
val.args.containerName = "mycont"
60+
val.args.transferDefStr = "blob-file"
61+
val.args.readTokenExp = 10
62+
63+
err = val.parseAndValidate()
64+
assert.NoError(t, err, "un expected error, all params should be set")
65+
assert.Equal(t, val.args.readTokenExp, val.params.blobSource.sasExpMin, "expiration time is not the expected value")
66+
67+
}
4368
func TestBasicUploaBlockSizeLimits(t *testing.T) {
4469
val := newParamParserValidator()
4570
val.args.sourceURIs = []string{"data"}
@@ -154,4 +179,92 @@ func TestLongOptionDownload(t *testing.T) {
154179
assert.Equal(t, tempval, val.params.blobSource.accountKey, "account key is not set")
155180
assert.Equal(t, c, val.params.blobSource.container, "container is not set")
156181
assert.Equal(t, b, val.params.blobSource.prefixes[0], "blobname is missing")
182+
assert.Equal(t, val.args.readTokenExp, val.params.blobSource.sasExpMin, "expiration time is not the expected value")
183+
157184
}
185+
186+
func TestS3Transfer(t *testing.T) {
187+
val := newParamParserValidator()
188+
url := "mys3.myurl.com"
189+
bucket := "bucket"
190+
val.args.sourceURIs = []string{fmt.Sprintf("s3://%v/%v", url, bucket)}
191+
val.args.storageAccountName = "myaccount"
192+
val.args.storageAccountKey = "mykey"
193+
val.args.containerName = "mycont"
194+
val.args.transferDefStr = "s3-blockblob"
195+
196+
back := os.Getenv(s3AccessKeyEnvVar)
197+
198+
s3access := back
199+
if s3access == "" {
200+
s3access = "TEST"
201+
}
202+
os.Setenv(s3AccessKeyEnvVar, s3access)
203+
204+
defer os.Setenv(s3AccessKeyEnvVar, back)
205+
206+
back = os.Getenv(s3SecretKeyEnvVar)
207+
208+
s3key := back
209+
if s3key == "" {
210+
s3key = "TEST"
211+
}
212+
os.Setenv(s3SecretKeyEnvVar, s3access)
213+
214+
defer os.Setenv(s3SecretKeyEnvVar, back)
215+
216+
err := val.parseAndValidate()
217+
assert.NoError(t, err, "unexpected error, all params should be set")
218+
assert.Equal(t, val.args.storageAccountName, val.params.blobTarget.accountName, "account name is not set")
219+
assert.Equal(t, val.args.storageAccountKey, val.params.blobTarget.accountKey, "account key is not set")
220+
assert.Equal(t, val.args.containerName, val.params.blobTarget.container, "container is not set")
221+
assert.Equal(t, url, val.params.s3Source.endpoint, "url/endpoint is invalid")
222+
assert.Equal(t, bucket, val.params.s3Source.bucket, "bucket is invalid")
223+
assert.Equal(t, s3access, val.params.s3Source.accessKey, "access key is invalid")
224+
assert.Equal(t, s3key, val.params.s3Source.secretKey, "key is invalid")
225+
assert.Equal(t, val.args.readTokenExp, val.params.s3Source.preSignedExpMin, "exp time invalid")
226+
}
227+
228+
func TestS3TransferWithCustomExp(t *testing.T) {
229+
val := newParamParserValidator()
230+
url := "mys3.myurl.com"
231+
bucket := "bucket"
232+
val.args.sourceURIs = []string{fmt.Sprintf("s3://%v/%v", url, bucket)}
233+
val.args.storageAccountName = "myaccount"
234+
val.args.storageAccountKey = "mykey"
235+
val.args.containerName = "mycont"
236+
val.args.transferDefStr = "s3-blockblob"
237+
val.args.readTokenExp = 10
238+
239+
back := os.Getenv(s3AccessKeyEnvVar)
240+
241+
s3access := back
242+
if s3access == "" {
243+
s3access = "TEST"
244+
}
245+
os.Setenv(s3AccessKeyEnvVar, s3access)
246+
247+
defer os.Setenv(s3AccessKeyEnvVar, back)
248+
249+
back = os.Getenv(s3SecretKeyEnvVar)
250+
251+
s3key := back
252+
if s3key == "" {
253+
s3key = "TEST"
254+
}
255+
os.Setenv(s3SecretKeyEnvVar, s3access)
256+
257+
defer os.Setenv(s3SecretKeyEnvVar, back)
258+
259+
err := val.parseAndValidate()
260+
assert.NoError(t, err, "unexpected error, all params should be set")
261+
assert.Equal(t, val.args.storageAccountName, val.params.blobTarget.accountName, "account name is not set")
262+
assert.Equal(t, val.args.storageAccountKey, val.params.blobTarget.accountKey, "account key is not set")
263+
assert.Equal(t, val.args.containerName, val.params.blobTarget.container, "container is not set")
264+
assert.Equal(t, url, val.params.s3Source.endpoint, "url/endpoint is invalid")
265+
assert.Equal(t, bucket, val.params.s3Source.bucket, "bucket is invalid")
266+
assert.Equal(t, s3access, val.params.s3Source.accessKey, "access key is invalid")
267+
assert.Equal(t, s3key, val.params.s3Source.secretKey, "key is invalid")
268+
assert.Equal(t, val.args.readTokenExp, val.params.s3Source.preSignedExpMin, "exp time invalid")
269+
}
270+

blobporter.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,19 @@ import (
1313
"github.com/Azure/blobporter/pipeline"
1414
"github.com/Azure/blobporter/transfer"
1515
"github.com/Azure/blobporter/util"
16+
"github.com/Azure/blobporter/internal"
1617
)
1718

18-
const programVersion = "0.6.07"
1919

2020
var argsUtil paramParserValidator
2121

2222
func init() {
2323

2424
//Show blobporter banner
25-
fmt.Printf("BlobPorter \nCopyright (c) Microsoft Corporation. \nVersion: %v\n---------------\n", programVersion)
25+
fmt.Printf("BlobPorter \nCopyright (c) Microsoft Corporation. \nVersion: %v\n---------------\n", internal.ProgramVersion)
2626

2727
argsUtil = newParamParserValidator()
2828

29-
// set user agent info
30-
util.SetUserAgentInfo(programVersion)
31-
3229
const (
3330
fileMsg = "Source URL, file or files (e.g. /data/*.gz) to upload."
3431
nameMsg = "Blob name (e.g. myblob.txt) or prefix for download scenarios."
@@ -48,6 +45,7 @@ func init() {
4845
removeDirStructureMsg = "If set the directory structure from the source is not kept.\n\tNot applicable when the source is a HTTP endpoint."
4946
numberOfHandlersPerFileMsg = "Number of open handles for concurrent reads and writes per file."
5047
numberOfFilesInBatchMsg = "Maximum number of files in a transfer.\n\tIf the number is exceeded new transfers are created"
48+
readTokenExpMsg = "Expiration in minutes of the read-only access token that will be generated to read from S3 or Azure Blob sources."
5149
)
5250

5351
flag.Usage = func() {
@@ -69,7 +67,7 @@ func init() {
6967
util.PrintUsageDefaults("i", "remove_directories", "false", removeDirStructureMsg)
7068
util.PrintUsageDefaults("h", "handles_per_file", strconv.Itoa(argsUtil.args.numberOfHandlesPerFile), numberOfHandlersPerFileMsg)
7169
util.PrintUsageDefaults("x", "files_per_transfer", strconv.Itoa(argsUtil.args.numberOfFilesInBatch), numberOfFilesInBatchMsg)
72-
70+
util.PrintUsageDefaults("o", "read_token_exp", strconv.Itoa(defaultReadTokenExp), readTokenExpMsg)
7371
}
7472

7573
util.StringListVarAlias(&argsUtil.args.sourceURIs, "f", "source_file", "", fileMsg)
@@ -90,6 +88,8 @@ func init() {
9088
util.BoolVarAlias(&argsUtil.args.removeDirStructure, "i", "remove_directories", false, removeDirStructureMsg)
9189
util.IntVarAlias(&argsUtil.args.numberOfHandlesPerFile, "h", "handles_per_file", defaultNumberOfHandlesPerFile, numberOfHandlersPerFileMsg)
9290
util.IntVarAlias(&argsUtil.args.numberOfFilesInBatch, "x", "files_per_transfer", defaultNumberOfFilesInBatch, numberOfFilesInBatchMsg)
91+
util.IntVarAlias(&argsUtil.args.readTokenExp, "o", "read_token_exp", defaultReadTokenExp, readTokenExpMsg)
92+
9393
}
9494

9595
var dataTransferred uint64

0 commit comments

Comments
 (0)