1//
2// Copyright (c) 2018, Joyent, Inc. All rights reserved.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7//
8
9package main
10
11import (
12	"context"
13	"fmt"
14	"io/ioutil"
15	"log"
16	"os"
17	"strconv"
18
19	"encoding/pem"
20
21	triton "github.com/joyent/triton-go"
22	"github.com/joyent/triton-go/authentication"
23	"github.com/joyent/triton-go/storage"
24)
25
26func main() {
27	keyID := os.Getenv("TRITON_KEY_ID")
28	accountName := os.Getenv("TRITON_ACCOUNT")
29	keyMaterial := os.Getenv("TRITON_KEY_MATERIAL")
30	userName := os.Getenv("TRITON_USER")
31	fileName := "foo.txt"
32	localPath := "/tmp/" + fileName
33	mantaPath := "/stor/bar/baz/" + fileName
34
35	var signer authentication.Signer
36	var err error
37
38	if keyMaterial == "" {
39		input := authentication.SSHAgentSignerInput{
40			KeyID:       keyID,
41			AccountName: accountName,
42			Username:    userName,
43		}
44		signer, err = authentication.NewSSHAgentSigner(input)
45		if err != nil {
46			log.Fatalf("Error Creating SSH Agent Signer: %v", err)
47		}
48	} else {
49		var keyBytes []byte
50		if _, err = os.Stat(keyMaterial); err == nil {
51			keyBytes, err = ioutil.ReadFile(keyMaterial)
52			if err != nil {
53				log.Fatalf("Error reading key material from %s: %s",
54					keyMaterial, err)
55			}
56			block, _ := pem.Decode(keyBytes)
57			if block == nil {
58				log.Fatalf(
59					"Failed to read key material '%s': no key found", keyMaterial)
60			}
61
62			if block.Headers["Proc-Type"] == "4,ENCRYPTED" {
63				log.Fatalf(
64					"Failed to read key '%s': password protected keys are\n"+
65						"not currently supported. Please decrypt the key prior to use.", keyMaterial)
66			}
67
68		} else {
69			keyBytes = []byte(keyMaterial)
70		}
71
72		input := authentication.PrivateKeySignerInput{
73			KeyID:              keyID,
74			PrivateKeyMaterial: keyBytes,
75			AccountName:        accountName,
76			Username:           userName,
77		}
78		signer, err = authentication.NewPrivateKeySigner(input)
79		if err != nil {
80			log.Fatalf("Error Creating SSH Private Key Signer: %v", err)
81		}
82	}
83
84	config := &triton.ClientConfig{
85		MantaURL:    os.Getenv("MANTA_URL"),
86		AccountName: accountName,
87		Username:    userName,
88		Signers:     []authentication.Signer{signer},
89	}
90
91	client, err := storage.NewClient(config)
92	if err != nil {
93		log.Fatalf("NewClient: %v", err)
94	}
95
96	mpuBody := storage.CreateMpuBody{
97		ObjectPath: mantaPath,
98	}
99
100	fooFile := []byte("this is only a test\n")
101	err = ioutil.WriteFile(localPath, fooFile, 0644)
102	if err != nil {
103		log.Fatalf("Failed to write temporary upload file " + localPath)
104	}
105
106	createMpuInput := &storage.CreateMpuInput{
107		DurabilityLevel: 2,
108		Body:            mpuBody,
109		ForceInsert:     true,
110	}
111
112	// Create a multipart upload to use for further testing
113	fmt.Println("*** Creating new multipart upload ***")
114	response := &storage.CreateMpuOutput{}
115	response, err = client.Objects().CreateMultipartUpload(context.Background(), createMpuInput)
116	if err != nil {
117		log.Fatalf("storage.Objects.CreateMpu: %v", err)
118	}
119	fmt.Printf("Response Body\nid: %s\npartsDirectory: %s\n", response.Id, response.PartsDirectory)
120	fmt.Println("Successfully created MPU for " + localPath)
121
122	reader, err := os.Open(localPath)
123	if err != nil {
124		log.Fatalf("os.Open: %v", err)
125	}
126	defer reader.Close()
127
128	uploadPartInput := &storage.UploadPartInput{
129		Id:           response.Id,
130		PartNum:      0,
131		ObjectReader: reader,
132	}
133
134	fmt.Println("ObjectDirectorPath for UploadPartInput: " + response.PartsDirectory)
135
136	// Upload a single part
137	fmt.Println("\n*** Upload a single part to the previous multipart upload ***")
138	response2 := &storage.UploadPartOutput{}
139	response2, err = client.Objects().UploadPart(context.Background(), uploadPartInput)
140	if err != nil {
141		log.Fatalf("storage.Objects.UploadPart: %v", err)
142	}
143	fmt.Println("Successfully uploaded " + fileName + " part 0!")
144
145	var parts []string
146	fmt.Printf("Part: %s\n", response2.Part)
147	parts = append(parts, response2.Part)
148	commitBody := storage.CommitMpuBody{
149		Parts: parts,
150	}
151
152	commitMpuInput := &storage.CommitMpuInput{
153		Id:   response.Id,
154		Body: commitBody,
155	}
156
157	// List parts
158	fmt.Println("\n*** List the parts of the current multipart upload ***")
159	listMpuInput := &storage.ListMpuPartsInput{
160		Id: response.Id,
161	}
162	listPartsOutput, err := client.Objects().ListMultipartUploadParts(context.Background(), listMpuInput)
163	if err != nil {
164		log.Fatalf("storage.Objects.ListMultipartUploadParts: %v", err)
165	}
166	for _, value := range listPartsOutput.Parts {
167		fmt.Println("Etag: " + value.ETag + " PartNumber: " + strconv.Itoa(value.PartNumber) + " Size: " + strconv.FormatInt(value.Size, 10))
168	}
169	fmt.Println("Successfully listed MPU parts!")
170
171	// Commit completed multipart upload
172	fmt.Println("\n*** Commit the completed multipart upload ***")
173	err = client.Objects().CommitMultipartUpload(context.Background(), commitMpuInput)
174	if err != nil {
175		log.Fatalf("storage.Objects.CommitMultipartUpload: %v", err)
176	}
177	fmt.Println("Successfully committed " + response.Id + "!")
178
179	getMpuInput := &storage.GetMpuInput{
180		PartsDirectoryPath: response.PartsDirectory,
181	}
182
183	// Get the status of the completed multipart upload
184	fmt.Println("\n*** Get the status of the multipart upload ***")
185	response3 := &storage.GetMpuOutput{}
186	response3, err = client.Objects().GetMultipartUpload(context.Background(), getMpuInput)
187	if err != nil {
188		log.Fatalf("storage.Objects.GetMultipartUpload: %v", err)
189	}
190	fmt.Println("Successful get of " + response3.Id + " for targetObject: " + response3.TargetObject)
191
192	err = os.Remove(localPath)
193	if err != nil {
194		log.Fatalf("os.Remove: %v", err)
195	}
196
197	// Create a new multipart upload just to test abort
198	fmt.Println("\n*** Create a throwaway multipart upload ***")
199	response, err = client.Objects().CreateMultipartUpload(context.Background(), createMpuInput)
200	if err != nil {
201		log.Fatalf("storage.Objects.CreateMpu: %v", err)
202	}
203	fmt.Printf("Response Body\nid: %s\npartsDirectory: %s\n", response.Id, response.PartsDirectory)
204	fmt.Println("Successfully created MPU for " + localPath)
205
206	abortMpuInput := &storage.AbortMpuInput{
207		PartsDirectoryPath: response.PartsDirectory,
208	}
209
210	// Abort multipart upload
211	fmt.Println("\n*** Abort the previous multipart upload ***")
212	err = client.Objects().AbortMultipartUpload(context.Background(), abortMpuInput)
213	if err != nil {
214		log.Fatalf("storage.Objects.AbortMultipartUpload: %v", err)
215	}
216
217	fmt.Println("Successfully aborted MPU")
218}
219