-
Notifications
You must be signed in to change notification settings - Fork 100
/
probe.go
973 lines (787 loc) · 30.7 KB
/
probe.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
package lib
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
oss "github.com/aliyun/aliyun-oss-go-sdk/oss"
uuid "github.com/satori/go.uuid"
)
const (
objectPrefex string = "oss-test-probe-"
)
const (
normalMode string = "normal"
appendMode = "append"
multipartMode = "multipart"
)
var specChineseProbe = SpecText{
synopsisText: "网络探测,用于对oss上传或者下载的网络链路进行探测,并输出探测报告",
paramText: "file_name [options]",
syntaxText: `
ossutil probe --download --url http_url [--addr=domain_name] [file_name]
ossutil probe --download --bucketname bucket-name [--object=object_name] [--addr=domain_name] [file_name]
ossutil probe --upload [file_name] --bucketname bucket-name [--object=object_name] [--addr=domain_name]
`,
detailHelpText: `
下载探测(--download表示)分两种情况
1、利用--url直接输入一个url网络地址,工具会下载该链接地址到本地
2、利用--bucketname指定某个bucket下载
如果输入--object,则下载指定bucket的指定object
如果不输入--object,工具生成一个临时文件上传到oss,再将其下载下来,探测结束后将临时文件和临时object删除
上传探测(--upload表示)
1、如果输入文件参数file_name,则将该文件上传到指定的bucket
如果不输入文件参数file_name,则工具生成一个临时文件上传到bucket,探测结束后再将临时文件删除
2、如果输入--object,则上传到oss中对象名称为object_name,如果该object已经存在,会提示是否覆盖
如果不输入--object,则上传到oss中object名称是随机生成的,探测结束后会将该临时object删除
上述命令中,file_name是参数,下载探测表示下载文件保存的目录名或者文件名,上传探测表示文件名
--url选项
表示一个网络地址,ossutil会下载该地址
--bucketname
oss中bucket的名称
--object
oss中object的名称
--addr选项
需要网络探测的域名,工具会对该域名进行ping等操作,默认值为www.aliyun.com
--upmode选项
表示上传模式,缺省值为normal,取值为:normal|append|multipart,分别表示正常上传、追加上传、分块上传
用法:
该命令有三种用法:
1) ossutil probe --download --url http_url [--addr=domain_name] [file_name]
该用法下载http_url地址到本地文件系统中,并输出探测报告;如果不输入file_name,则下载文
件保存在当前目录下,文件名由工具自动判断;如果输入file_name,则file_name为文件名或者目录名,
下载的文件名为file_name或者保存在file_name目录下。
如果输入--addr,工具会探测domain_name, 默认探测 www.aliyun.com
2) ossutil probe --download --bucketname bucket-name [--object=object_name] [--addr=domain_name] [file_name]
该用法下载bucket中的object,并输出探测报告;指定--object则会下载bucket-name中
的object_name;不指定--object,则工具会生成一个临时文件上传到oss后再将其下载,下载结束后
会将临时文件和临时object删除
如果输入--addr,工具会探测domain_name, 默认探测 www.aliyun.com
3) ossutil probe --upload [file_name] --bucketname bucket-name [--object=object_name] [--addr=domain_name]
该用法是上传探测,会输出探测报告;如果指定file_name,则将该file_name文件上传到oss;不指定
file_name,则工具会生成一个临时文件上传,探测结束后将临时文件删除;如果输入--object,则oss
中object名称为object_name;如果不输入--object,则oss中object名称为工具自动生成,探测结束
后会将该临时object删除
如果输入--addr,工具会探测domain_name, 默认探测 www.aliyun.com
`,
sampleText: `
1) 下载指定url
ossutil probe --download --url "http://bucket-name.oss-cn-shenzhen.aliyuncs.com/object_name"
2) 下载指定Url到指定文件
ossutil probe --download --url "http://bucket-name.oss-cn-shenzhen.aliyuncs.com/object_name" file_name
3) 下载指定url到指定文件、并检测指定地址网络状况
ossutil probe --download --url "http://bucket-name.oss-cn-shenzhen.aliyuncs.com/object_name" file_name --addr www.aliyun.com
4) 下载bucket临时文件
ossutil probe --download --bucketname bucket-name
5) 下载bucket指定文件
ossutil probe --download --bucketname bucket-name --object object_name
6) 下载bucket指定的文件并保存到本地指定文件
ossutil probe --download --bucketname bucket-name --object object_name file_name
7) 下载bucket指定文件并保存到本地指定文件,并检测指定地址网络状况
ossutil probe --download --bucketname bucket-name --object object_name file_name --addr www.aliyun.com
8) 上传临时文件,以normal方式上传
ossutil probe --upload --bucketname bucket-name --upmode normal
9) 上传临时文件,以append方式上传
ossutil probe --upload --bucketname bucket-name --upmode append
10) 上传临时文件,以multipart方式上传
ossutil probe --upload --bucketname bucket-name --upmode multipart
11) 上传指定文件到指定object
ossutil probe --upload file_name --bucketname bucket-name --object object_name
12) 上传指定文件到指定object,并检测addr地址
ossutil probe --upload file_name --bucketname bucket-name --object object_name --addr www.aliyun.com
`,
}
var specEnglishProbe = SpecText{
synopsisText: "Detects oss upload or download network links and outputs reports ",
paramText: "file_name [options]",
syntaxText: `
ossutil probe --download --url http_url [--addr=domain_name] [file_name]
ossutil probe --download --bucketname bucket-name [--object=object_name] [--addr=domain_name] [file_name]
ossutil probe --upload [file_name] --bucketname bucket-name [--object=object_name] [--addr=domain_name]
`,
detailHelpText: `
Download probe (--download) has two usages
1、Use --url to input a url, ossutil will download the link
2、Use --bucketname to download the specified bucket's object
If input --object, downloads the specified object of the specified bucket.
If do not input --object, ossutil creates a temporary file to upload to oss, then downloads it, and deletes the temporary file and temporary object after the probe ends.
Upload probe (--upload)
1、If input parameter file_name, the specified file is uploaded to the specified bucket.
If do not input parameter file_name, ossutil creates a temporary file to upload, and then deletes the temporary file after the probe ends.
2、If input --object, the object name is specified,if the object already exists, you will be prompted to overwrite or not.
If do not input --object, the object name is randomly generated, and the temporary object will be deleted after the probe ends.
In the above commands, file_name is a parameter which may be a directory name or a file name in the case of download probe, and must be a exist file name in the case of upload probe
--url option
Specifies a network address which will be downloaded by ossutil
--bucketname option
Specifies a bucket name in oss
--object option
Specifies a object name in oss bucket
--addr option
Specifies a domain name which will be probed by ossutil,the default value is www.aliyun.com
--upmode option
specifies the upload mode,default value is normal,value is:normal|append|multipart
Usage:
There are three usages for this command:
1) ossutil probe --download --url http_url [--addr=domain_name] [file_name]
The command downloads the http_url address to the local file system and outputs
probe report; if you do not input file_name, the downloaded file is saved in the
current directory and the file name is determined by ossutil; if file_name is inputed,
The downloaded file is named file_name.
If you input --addr, ossutil will probe the domain_name,default probe www.aliyun.com
2) ossutil probe --download --bucketname bucket-name [--object=object_name] [--addr=domain_name] [file_namefile_name]
The command downloads object in the specified bucket and outputs probe report;
if you input --object,ossutil downloads the specified object; if you don't input --object
,ossutil creates a temporary file to upload and then downloads it; after probe end,temporary
file and temporary object will all be deleted
If you input --addr, ossutil will probe the domain_name,default probe www.aliyun.com
3) ossutil probe --upload [file_name] --bucketname bucket-name [--object=object_name] [--addr=domain_name]
The command uploads a file to oss and outputs probe report; if you input file_name,
the file named file_name is uploaded; if you don't input file_name,ossutil creates a temporary
file to upload and delete it after the probe ends; if you input --object, the uploaded object
is named object_name; if you don't input --object, the uploaded object's name is determined by
ossutil, and after probe end,the temporary object will be deleted
If you input --addr, ossutil will probe the domain_name,default probe www.aliyun.com
`,
sampleText: `
1) downloads specified url
ossutil probe --download --url "http://bucket-name.oss-cn-shenzhen.aliyuncs.com/object_name"
2) downloads specified url to specified file
ossutil probe --download --url "http://bucket-name.oss-cn-shenzhen.aliyuncs.com/object_name" file_name
3) downloads specified url to specified file,and ping domain
ossutil probe --download --url "http://bucket-name.oss-cn-shenzhen.aliyuncs.com/object_name" file_name --addr www.aliyun.com
4) downloads temporary file from specified bucket
ossutil probe --download --bucketname bucket-name
5) downloads specified object from specified bucket
ossutil probe --download --bucketname bucket-name --object object_name
6) downloads specified object from specified bucket to specified file
ossutil probe --download --bucketname bucket-name --object object_name file_name
7) downloads specified object from specified bucket to specified file,and probe domain
ossutil probe --download --bucketname bucket-name --object object_name file_name --addr www.aliyun.com
8) uploads a temporary file with normal mode
ossutil probe --upload --bucketname bucket-name --upmode normal
9) uploads a temporary file with append mode
ossutil probe --upload --bucketname bucket-name --upmode append
10) uploads a temporary file with multipart mode
ossutil probe --upload --bucketname bucket-name --upmode multipart
11) uploads specified file to specified object
ossutil probe --upload file_name --bucketname bucket-name --object object_name
12) uploads specified file to specified object, and probe domain
ossutil probe --upload file_name --bucketname bucket-name --object object_name --addr www.aliyun.com
`,
}
type probeOptionType struct {
disableNetDetect bool
opUpload bool
opDownload bool
fromUrl string
bucketName string
objectName string
netAddr string
upMode string
logFile *os.File
logName string
dlFileSize int64
dlFilePath string
ulObject string
}
type ProbeCommand struct {
command Command
pbOption probeOptionType
}
var probeCommand = ProbeCommand{
command: Command{
name: "probe",
nameAlias: []string{"probe"},
minArgc: 0,
maxArgc: MaxInt,
specChinese: specChineseProbe,
specEnglish: specEnglishProbe,
group: GroupTypeNormalCommand,
validOptionNames: []string{
OptionConfigFile,
OptionEndpoint,
OptionAccessKeyID,
OptionAccessKeySecret,
OptionUpload,
OptionDownload,
OptionUrl,
OptionBucketName,
OptionObject,
OptionAddr,
OptionUpMode,
OptionLogLevel,
},
},
}
// function for FormatHelper interface
func (pc *ProbeCommand) formatHelpForWhole() string {
return pc.command.formatHelpForWhole()
}
func (pc *ProbeCommand) formatIndependHelp() string {
return pc.command.formatIndependHelp()
}
// Init simulate inheritance, and polymorphism
func (pc *ProbeCommand) Init(args []string, options OptionMapType) error {
err := pc.command.Init(args, options, pc)
if err == nil {
return nil
}
errStr := err.Error()
if strings.Contains(errStr, "Read config file error") && isNotNeedConigFile(options) {
return nil
}
return err
}
func isNotNeedConigFile(options OptionMapType) bool {
isDownload, _ := GetBool(OptionDownload, options)
fromUrl, _ := GetString(OptionUrl, options)
if isDownload && fromUrl != "" {
return true
}
return false
}
// RunCommand simulate inheritance, and polymorphism
func (pc *ProbeCommand) RunCommand() error {
var err error
pc.pbOption.opUpload, _ = GetBool(OptionUpload, pc.command.options)
pc.pbOption.opDownload, _ = GetBool(OptionDownload, pc.command.options)
pc.pbOption.fromUrl, _ = GetString(OptionUrl, pc.command.options)
pc.pbOption.bucketName, _ = GetString(OptionBucketName, pc.command.options)
pc.pbOption.objectName, _ = GetString(OptionObject, pc.command.options)
pc.pbOption.netAddr, _ = GetString(OptionAddr, pc.command.options)
pc.pbOption.upMode, _ = GetString(OptionUpMode, pc.command.options)
pc.pbOption.logFile, pc.pbOption.logName, err = logFileMake()
if err != nil {
return fmt.Errorf("probe logFileMake error,%s", err.Error())
}
defer pc.pbOption.logFile.Close()
pc.pbOption.logFile.WriteString("************************* system information *************************\n")
pc.pbOption.logFile.WriteString(fmt.Sprintf("operating system:%s_%s\n", runtime.GOOS, runtime.GOARCH))
pc.pbOption.logFile.WriteString(fmt.Sprintf("operating time:%s\n", time.Now().Format("2006-01-02 15:04:05")))
if pc.pbOption.opUpload && pc.pbOption.opDownload {
err = fmt.Errorf("error,upload and download are both true")
} else if !pc.pbOption.opUpload && !pc.pbOption.opDownload {
err = fmt.Errorf("error,upload and download are both false")
} else if !pc.pbOption.opUpload && pc.pbOption.opDownload {
err = pc.probeDownload()
} else {
err = pc.probeUpload()
}
return err
}
func (pc *ProbeCommand) probeDownload() error {
var err error
pingPath := ""
if pc.pbOption.fromUrl != "" {
pingPath, _, err = urlCheck(pc.pbOption.fromUrl)
if err != nil {
return fmt.Errorf("probeDownloadWithHttpUrl error,%s", err.Error())
}
} else {
if pc.pbOption.bucketName == "" {
return fmt.Errorf("probeDownloadWithParameter error,bucketName is not exist")
}
endPoint, _ := pc.command.getEndpoint(pc.pbOption.bucketName)
if endPoint == "" {
return fmt.Errorf("probeDownloadWithParameter error,endpoint is not exist")
}
pSlice := strings.Split(endPoint, "//")
if len(pSlice) == 1 {
endPoint = pSlice[0]
} else {
endPoint = pSlice[1]
}
pingPath = endPoint
}
fmt.Printf("begin parse parameters and prepare object...[√]\n")
fmt.Printf("begin network detection...")
pc.ossNetDetection(pingPath)
fmt.Printf("\rbegin network detection...[√]\n")
startT := time.Now()
if pc.pbOption.fromUrl != "" {
err = pc.downloadWithHttpUrl()
} else {
err = pc.probeDownloadWithParameter()
}
endT := time.Now()
var logBuff bytes.Buffer
if err == nil {
fmt.Printf("\rbegin download file...[√]\n")
logBuff.WriteString("\n************************* download result *************************\n")
logBuff.WriteString("download file:success\n")
logBuff.WriteString(fmt.Sprintf("download file size:%d(byte)\n", pc.pbOption.dlFileSize))
logBuff.WriteString(fmt.Sprintf("download time consuming:%d(ms)\n", endT.UnixNano()/1000/1000-startT.UnixNano()/1000/1000))
logBuff.WriteString("(only the time consumed by probe command)\n\n")
if pc.pbOption.dlFilePath != "" {
logBuff.WriteString(fmt.Sprintf("download file is %s\n", pc.pbOption.dlFilePath))
}
} else {
fmt.Printf("\rbegin download file...[x]\n\n")
logBuff.WriteString("\n************************* download result *************************\n")
logBuff.WriteString("download file:failure\n")
logBuff.WriteString("\n************************* error message *************************\n")
logBuff.WriteString(fmt.Sprintf("%s\n", err.Error()))
}
fmt.Printf("%s", logBuff.String())
pc.pbOption.logFile.WriteString(logBuff.String())
fmt.Printf("\n************************* report log info*************************\n")
fmt.Printf("report log file:%s\n\n", pc.pbOption.logName)
return err
}
// the only arg in this command is input or output file name
func (pc *ProbeCommand) getFileNameArg() (fileName string, err error) {
if len(pc.command.args) == 0 {
return "", nil
}
fileName = pc.command.args[0]
fileURL, err := StorageURLFromString(fileName, "")
if err != nil {
return "", fmt.Errorf("StorageURLFromString error:%s", err.Error())
}
if !fileURL.IsFileURL() {
return "", fmt.Errorf("not a local file name:%s", fileURL.ToString())
}
return
}
func (pc *ProbeCommand) downloadWithHttpUrl() error {
_, srcName, err := urlCheck(pc.pbOption.fromUrl)
if err != nil {
return fmt.Errorf("downloadWithHttpUrl urlCheck error,%s", err.Error())
}
fileName, err := pc.getFileNameArg()
if err != nil {
return fmt.Errorf("downloadWithHttpUrl getFileNameArg error,%s", err.Error())
}
downloadFileName, err := prepareLocalFileName(srcName, fileName)
if err != nil {
return fmt.Errorf("downloadWithHttpUrl prepareLocalFileName error,%s", err.Error())
}
sizeStat, err := os.Stat(downloadFileName)
if err == nil {
bConitnue := confirm(downloadFileName)
if !bConitnue {
return nil
}
}
res, err := http.Get(pc.pbOption.fromUrl)
if err != nil {
return fmt.Errorf("downloadWithHttpUrl http.Get error,%s", err.Error())
}
defer res.Body.Close()
pc.pbOption.logFile.WriteString("\n************************* response info*************************\n")
pc.pbOption.logFile.WriteString(fmt.Sprintf("status code:%s\n", res.Status))
res.Header.Write(pc.pbOption.logFile)
if res.StatusCode != 200 {
return fmt.Errorf("http status code:%s", res.Status)
}
fileRecord, err := os.Create(downloadFileName)
if err != nil {
return fmt.Errorf("downloadWithHttpUrl http.Get error,%s", err.Error())
}
io.Copy(fileRecord, res.Body)
sizeStat, err = fileRecord.Stat()
fileRecord.Close()
if err != nil {
return fmt.Errorf("downloadWithHttpUrl fileRecord.Stat error,%s", err.Error())
}
pc.pbOption.dlFileSize = sizeStat.Size()
pc.pbOption.dlFilePath = downloadFileName
return nil
}
func (pc *ProbeCommand) probeDownloadWithParameter() error {
var err error
var srcURL CloudURL
var bDeleteObject = false
srcURL.bucket = pc.pbOption.bucketName
if pc.pbOption.objectName == "" {
uniqId, _ := uuid.NewV4()
uniqKey := uniqId.String()
objectName := objectPrefex + uniqKey
err := pc.prepareRandomObject(objectName)
if err != nil {
return fmt.Errorf("prepareRandomObject error,%s", err.Error())
}
srcURL.object = objectName
bDeleteObject = true
} else {
srcURL.object = pc.pbOption.objectName
}
srcURL.urlStr = srcURL.ToString()
err = pc.probeDownloadObject(srcURL, bDeleteObject)
return err
}
func (pc *ProbeCommand) probeDownloadObject(srcURL CloudURL, bDeleteObject bool) error {
fileName, err := pc.getFileNameArg()
if err != nil {
return fmt.Errorf("probeDownloadObject error,%s", err.Error())
}
downloadFileName, err := prepareLocalFileName(srcURL.object, fileName)
if err != nil {
return fmt.Errorf("probeDownloadObject error,%s", err.Error())
} else {
_, err := os.Stat(downloadFileName)
if err == nil {
bConitnue := confirm(downloadFileName)
if !bConitnue {
return nil
}
}
}
bucket, err := pc.command.ossBucket(srcURL.bucket)
if err != nil {
return fmt.Errorf("bucket:%s,probeDownloadObject error,%s", srcURL.bucket, err.Error())
}
err = bucket.GetObjectToFile(srcURL.object, downloadFileName)
if err != nil {
return fmt.Errorf("bucket:%s,GetObjectToFile error,%s", srcURL.bucket, err.Error())
}
sizeStat, err := os.Stat(downloadFileName)
if err != nil {
return fmt.Errorf("GetObjectToFile error,%s", err.Error())
}
pc.pbOption.dlFileSize = sizeStat.Size()
pc.pbOption.dlFilePath = downloadFileName
if bDeleteObject {
pc.deleteObject(srcURL.object)
}
return nil
}
func (pc *ProbeCommand) prepareRandomObject(objectName string) (err error) {
//judge objectName exist or not
bucket, err := pc.command.ossBucket(pc.pbOption.bucketName)
if err != nil {
return err
}
isExist, err := bucket.IsObjectExist(objectName)
if err != nil {
return err
}
if isExist {
return fmt.Errorf("random object %s exist,please try again", objectName)
}
// put up object
var textBuffer bytes.Buffer
for i := 0; i < 10240; i++ {
textBuffer.WriteString("testossprobe")
}
err = bucket.PutObject(objectName, strings.NewReader(textBuffer.String()))
if err != nil {
return err
}
return nil
}
func (pc *ProbeCommand) deleteObject(objectName string) error {
retryTimes, _ := GetInt(OptionRetryTimes, pc.command.options)
for i := 1; ; i++ {
bucket, err := pc.command.ossBucket(pc.pbOption.bucketName)
if err == nil {
err = bucket.DeleteObject(objectName)
if err == nil {
return nil
}
}
_, noNeedRetry := err.(oss.ServiceError)
if int64(i) >= retryTimes || noNeedRetry {
return err
}
// wait 1 second
time.Sleep(time.Duration(1) * time.Second)
}
}
func (pc *ProbeCommand) ossNetDetection(pingPath string) {
if pc.pbOption.disableNetDetect {
return // for test:reduce test time
}
var netAddr = "www.aliyun.com"
if pc.pbOption.netAddr != "" {
netAddr = pc.pbOption.netAddr
}
if runtime.GOOS == "windows" {
pingProcess(pc.pbOption.logFile, "ping", netAddr)
pingProcess(pc.pbOption.logFile, "ping", pingPath)
pingProcess(pc.pbOption.logFile, "tracert", pingPath)
pingProcess(pc.pbOption.logFile, "nslookup", pingPath)
} else {
// linux or mac
pingProcess(pc.pbOption.logFile, "ping", netAddr, "-c", "4")
pingProcess(pc.pbOption.logFile, "ping", pingPath, "-c", "4")
pingProcess(pc.pbOption.logFile, "traceroute", "-m", "20", pingPath)
pingProcess(pc.pbOption.logFile, "dig", pingPath)
}
}
func prepareLocalFileName(srcName string, destName string) (absDestFileName string, err error) {
absDestFileName = ""
err = nil
keyName := srcName
urlSplits := strings.Split(srcName, "/")
if len(urlSplits) > 1 {
keyName = urlSplits[len(urlSplits)-1]
}
// it is absolute path
currentDir, err := os.Getwd()
if err != nil {
return
}
if destName == "" {
absDestFileName = currentDir + string(os.PathSeparator) + keyName
return
}
// get absolute path
absDestFileName, err = filepath.Abs(destName)
if err != nil {
return
}
if strings.HasSuffix(destName, string(os.PathSeparator)) {
err = os.MkdirAll(absDestFileName, 0755)
if err != nil {
return
}
absDestFileName = absDestFileName + string(os.PathSeparator) + keyName
} else {
f, serr := os.Stat(absDestFileName)
if serr == nil && f.IsDir() {
absDestFileName = absDestFileName + string(os.PathSeparator) + keyName
} else {
err = os.MkdirAll(filepath.Dir(absDestFileName), 0755)
}
}
return
}
func urlCheck(strUrl string) (string, string, error) {
var err error
urlSplits := strings.Split(strUrl, "/")
if len(urlSplits) < 4 {
err = fmt.Errorf("invalid url:%s", strUrl)
return "", "", err
}
pingPath := urlSplits[2]
urlGetFileName := urlSplits[len(urlSplits)-1]
endPos := strings.Index(urlGetFileName, "?")
if endPos > 0 {
urlGetFileName = urlGetFileName[0:endPos]
}
if pingPath == "" || urlGetFileName == "" {
return "", "", fmt.Errorf("invalid url:%s", strUrl)
}
return pingPath, urlGetFileName, nil
}
func logFileMake() (logFile *os.File, logName string, err error) {
dirName, err := os.Getwd()
if err != nil {
return nil, "", err
}
logName = dirName + string(os.PathSeparator) + "logOssProbe" + time.Now().Format("20060102150405") + ".log"
logFile, err = os.OpenFile(logName, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0660)
if err != nil {
return nil, "", err
}
return
}
func pingProcess(logFile *os.File, instruction string, args ...string) {
logFile.WriteString("\n\n")
logFile.WriteString(fmt.Sprintf("************************* %s *************************\n", instruction))
logFile.WriteString(fmt.Sprintf("Command => %s", instruction))
for _, v := range args {
logFile.WriteString(fmt.Sprintf(" %s", v))
}
logFile.WriteString("\n")
c := exec.Command(instruction, args...)
d, _ := c.Output()
logFile.WriteString(string(d))
c.Run()
}
func confirm(str string) bool {
var val string
fmt.Printf(getClearStr(fmt.Sprintf("probe: overwrite \"%s\"(y or N)? ", str)))
if _, err := fmt.Scanln(&val); err != nil || (strings.ToLower(val) != "yes" && strings.ToLower(val) != "y") {
return false
}
return true
}
func (pc *ProbeCommand) probeUpload() error {
upMode := pc.pbOption.upMode
if upMode == "" {
upMode = normalMode
} else {
if upMode != normalMode && upMode != appendMode && upMode != multipartMode {
return fmt.Errorf("probeUpload errro,invalid mode flag:%s", upMode)
}
}
if pc.pbOption.bucketName == "" {
return fmt.Errorf("probeUpload error,bucketName is not exist")
}
endPoint, _ := pc.command.getEndpoint(pc.pbOption.bucketName)
if endPoint == "" {
return fmt.Errorf("probeUpload error,endpoint is not exist")
}
pSlice := strings.Split(endPoint, "//")
if len(pSlice) == 1 {
endPoint = pSlice[0]
} else {
endPoint = pSlice[1]
}
pingPath := endPoint
objectName := pc.pbOption.objectName
srcFileName, err := pc.getFileNameArg()
if err != nil {
return fmt.Errorf("probeUpload errro,getFileNameArg error:%s", err.Error())
}
var bDeleteLocalFile = false
fileSize := int64(0)
if srcFileName == "" {
// it is absolute path
currentDir, err := os.Getwd()
if err != nil {
return fmt.Errorf("probeUpload errro,os.Getwd error:%s", err.Error())
}
uniqId, _ := uuid.NewV4()
uniqKey := uniqId.String()
tempName := objectPrefex + uniqKey
srcFileName = currentDir + string(os.PathSeparator) + tempName
_, err = os.Stat(srcFileName)
if err == nil {
return fmt.Errorf("temp file exist:%s,please retry", srcFileName)
}
// prepare a local file
var textBuffer bytes.Buffer
for i := 0; i < 10240; i++ {
textBuffer.WriteString("testossprobe")
}
err = ioutil.WriteFile(srcFileName, textBuffer.Bytes(), 0644)
if err != nil {
return fmt.Errorf("prepare temp file error,%s", err.Error())
}
bDeleteLocalFile = true
fileSize = int64(textBuffer.Len())
} else {
fStat, err := os.Stat(srcFileName)
if err != nil {
return fmt.Errorf("%s not exist,stat error:%s", srcFileName, err.Error())
}
if fStat.IsDir() {
return fmt.Errorf("%s is dir,not file", srcFileName)
}
fileSize = fStat.Size()
}
var bDeleteObject = false
if objectName == "" {
uniqId, _ := uuid.NewV4()
uniqKey := uniqId.String()
objectName = objectPrefex + uniqKey
bDeleteObject = true
} else {
pc.pbOption.ulObject = objectName
}
// judge object is exist or not
bucket, err := pc.command.ossBucket(pc.pbOption.bucketName)
if err != nil {
return fmt.Errorf("probeUpload ossBucket error:%s", err.Error())
}
isExist, err := bucket.IsObjectExist(objectName)
if err != nil {
return fmt.Errorf("probeUpload IsObjectExist error:%s", err.Error())
}
if isExist {
if bDeleteObject {
return fmt.Errorf("oss temp object %s exist,please try again", objectName)
} else {
bConitnue := confirm(objectName)
if !bConitnue {
return nil
}
}
}
fmt.Printf("begin parse parameters and prepare file...[√]\n")
fmt.Printf("begin network detection...")
pc.ossNetDetection(pingPath)
fmt.Printf("\rbegin network detection...[√]\n")
fmt.Printf("begin upload file(%s)...", upMode)
// begin upload
startT := time.Now()
if upMode == appendMode {
err = pc.probeUploadFileAppend(srcFileName, objectName)
} else if upMode == multipartMode {
err = pc.probeUploadFileMultiPart(srcFileName, objectName)
} else {
err = pc.probeUploadFileNormal(srcFileName, objectName)
}
endT := time.Now()
var logBuff bytes.Buffer
if err == nil {
fmt.Printf("\rbegin upload file(%s)...[√]\n", upMode)
logBuff.WriteString("\n************************* upload result *************************\n")
logBuff.WriteString("upload file:success\n")
logBuff.WriteString(fmt.Sprintf("upload file size:%d(byte)\n", fileSize))
logBuff.WriteString(fmt.Sprintf("upload time consuming:%d(ms)\n", endT.UnixNano()/1000/1000-startT.UnixNano()/1000/1000))
logBuff.WriteString("(only the time consumed by probe command)\n\n")
if pc.pbOption.ulObject != "" {
logBuff.WriteString(fmt.Sprintf("upload object is %s\n", pc.pbOption.ulObject))
}
} else {
fmt.Printf("\rbegin upload file(%s)...[x]\n\n", upMode)
logBuff.WriteString("\n************************* upload result *************************\n")
logBuff.WriteString("upload file:failure\n")
logBuff.WriteString("\n************************* error message *************************\n")
logBuff.WriteString(fmt.Sprintf("%s\n", err.Error()))
}
fmt.Printf("%s", logBuff.String())
pc.pbOption.logFile.WriteString(logBuff.String())
fmt.Printf("\n************************* report log info*************************\n")
fmt.Printf("report log file:%s\n\n", pc.pbOption.logName)
// delete oss temp object
if bDeleteObject {
pc.deleteObject(objectName)
}
// delete local file
if bDeleteLocalFile {
os.Remove(srcFileName)
}
return err
}
func (pc *ProbeCommand) probeUploadFileAppend(absFileName string, objectName string) error {
bucket, err := pc.command.ossBucket(pc.pbOption.bucketName)
if err != nil {
return fmt.Errorf("probeUploadFileAppend error:%s", err.Error())
}
var nextPos int64 = 0
fd, err := os.Open(absFileName)
if err != nil {
return fmt.Errorf("probeUploadFileAppend,open %s error:%s", absFileName, err.Error())
}
defer fd.Close()
nextPos, err = bucket.AppendObject(objectName, fd, nextPos)
if err != nil {
return fmt.Errorf("probeUploadFileAppend error:%s", err.Error())
}
return nil
}
func (pc *ProbeCommand) probeUploadFileMultiPart(absFileName string, objectName string) error {
bucket, err := pc.command.ossBucket(pc.pbOption.bucketName)
if err != nil {
return fmt.Errorf("probeUploadFileMultiPart error:%s", err.Error())
}
err = bucket.UploadFile(objectName, absFileName, 100*1024, oss.Routines(5), oss.Checkpoint(true, ""))
if err != nil {
return fmt.Errorf("probeUploadFileMultiPart error:%s", err.Error())
}
return nil
}
func (pc *ProbeCommand) probeUploadFileNormal(absFileName string, objectName string) error {
bucket, err := pc.command.ossBucket(pc.pbOption.bucketName)
if err != nil {
return err
}
err = bucket.PutObjectFromFile(objectName, absFileName)
if err != nil {
return fmt.Errorf("PutObjectFromFile error:%s", err.Error())
}
return nil
}