-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
149 lines (116 loc) · 3.84 KB
/
main.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
// Copyright (c) 2020 Microsoft Corporation, Sean Hinchee.
// Licensed under the MIT License.
package main
import (
"context"
"flag"
"fmt"
"log"
"net/url"
"os"
"strings"
"aqwari.net/net/styx"
"github.com/Azure/azure-storage-blob-go/azblob"
)
const (
maxBlobs = 4096 // Maximum number of blobs to track
)
var (
//announce = flag.String("a", "tcp!localhost!1337", "Dialstring to announce on") // TODO
containerName = flag.String("c", "9pfs", "Name of container to fs-ify")
port = flag.String("p", ":1337", "TCP port to listen for 9p connections")
chatty = flag.Bool("D", false, "Chatty 9p tracing")
verbose = flag.Bool("V", false, "Verbose 9p error output")
)
// A 9p file server exposing an azure blob container
func main() {
flag.Parse()
var (
styxServer styx.Server // 9p file server handle for styx
srv Server // Our file system server
)
srv.Initialize()
log.Printf("Using %s as the container for the fs...\n", *containerName)
/* Set up Azure */
// Acquire azure credential information from environment variables
accountName := os.Getenv("AZURE_STORAGE_ACCOUNT")
accountKey := os.Getenv("AZURE_STORAGE_ACCESS_KEY")
if len(accountName) == 0 || len(accountKey) == 0 {
fatal("$AZURE_STORAGE_ACCOUNT and $AZURE_STORAGE_ACCESS_KEY environment variables must be set to authenticate")
}
// Create a new azure auth pipeline
credential, err := azblob.NewSharedKeyCredential(accountName, accountKey)
if err != nil {
fatal("err: could not authenticate - ", err)
}
p := azblob.NewPipeline(credential, azblob.PipelineOptions{})
/* Set up the storage container */
urlStr, err := url.Parse(fmt.Sprintf("https://%s.blob.core.windows.net/%s", accountName, *containerName))
if err != nil {
fatal("err: could not generate container URL - ", *urlStr)
}
container := azblob.NewContainerURL(*urlStr, p)
ctx := context.Background()
srv.container = container
srv.ctx = ctx
// We only need the error
_, err = container.Create(ctx, azblob.Metadata{}, azblob.PublicAccessNone)
exists := false
if err != nil {
// We have to search the error for the magic response string
if strings.Contains(err.Error(), string(azblob.ServiceCodeContainerAlreadyExists)) {
exists = true
}
// The container didn't exist, but we couldn't create it
if !exists {
fatal("err: could not create container - ", err)
}
}
if exists {
log.Println(`Container "` + *containerName + `" found, using...`)
} else {
log.Println(`No existing container "` + *containerName + `", creating...`)
}
/* Populate tree with contents from the container */
var names []string
// Skip population if the container didn't exist, there's nothing contained
if !exists {
goto Styx
}
log.Println("Reading existing blobs from container...")
// List all remote blobs
names, err = ListBlobs(&srv)
if err != nil {
fatal("err: could not list remote blobs - ", err)
}
if len(names) < 1 {
log.Println("No extant blobs found, continuing...")
goto Styx
}
log.Printf("Found %d extant blobs, populating fs...\n", len(names))
// Insert blobs into file tree
// TODO - some kind of nested directory handling?
for _, name := range names {
f, err := srv.Insert("/"+name, false)
if err != nil {
fatal("err: could not insert extant blobs into fs - ", err)
}
// TODO - lazy download - we only need meta-info, not the whole file
f.Blob.Download(srv.ctx)
}
/* Set up 9p server */
Styx:
if *chatty {
styxServer.TraceLog = log.New(os.Stderr, "", 0)
}
if *verbose {
styxServer.ErrorLog = log.New(os.Stderr, "", 0)
}
// TODO - actually parse dial string (new module?)
// TODO - allow options like /srv posting, unix socket, etc.
//proto, addr, port := dialstring.Parse(*announce)
styxServer.Addr = *port
// Shim our own logger, in case we need it
styxServer.Handler = styx.Stack(logger, &srv)
fatal(styxServer.ListenAndServe())
}