66 "crypto/sha512"
77 "encoding/hex"
88 "encoding/json"
9+ "errors"
910 "flag"
1011 "fmt"
1112 "io"
@@ -19,6 +20,8 @@ import (
1920 dstack "github.com/Dstack-TEE/dstack/sdk/go/dstack"
2021)
2122
23+ var admissionRetryInterval = 2 * time .Second
24+
2225func main () {
2326 var (
2427 identity = flag .String ("identity" , os .Getenv ("ADMISSION_IDENTITY" ), "claimed SPIFFE identity" )
@@ -96,15 +99,30 @@ func admit(ctx context.Context, httpClient *http.Client, dstackClient quoteClien
9699 if len (brokerURLs ) == 0 {
97100 return "" , fmt .Errorf ("no broker URLs configured" )
98101 }
99- var errs []string
100- for _ , brokerURL := range brokerURLs {
101- token , err := admitOne (ctx , httpClient , dstackClient , strings .TrimRight (brokerURL , "/" ), identity , statementBytes , vmConfig )
102- if err == nil {
103- return token , nil
102+ var lastErrs []string
103+ for {
104+ if err := ctx .Err (); err != nil {
105+ if len (lastErrs ) > 0 {
106+ return "" , fmt .Errorf ("admission timed out or was canceled after broker errors: %s" , strings .Join (lastErrs , "; " ))
107+ }
108+ return "" , err
109+ }
110+ lastErrs = lastErrs [:0 ]
111+ for _ , brokerURL := range brokerURLs {
112+ brokerURL = strings .TrimRight (brokerURL , "/" )
113+ token , err := admitOne (ctx , httpClient , dstackClient , brokerURL , identity , statementBytes , vmConfig )
114+ if err == nil {
115+ return token , nil
116+ }
117+ if isPermanentAdmissionError (err ) {
118+ return "" , fmt .Errorf ("%s: %w" , brokerURL , err )
119+ }
120+ lastErrs = append (lastErrs , fmt .Sprintf ("%s: %v" , brokerURL , err ))
121+ }
122+ if ! sleepContext (ctx , admissionRetryInterval ) {
123+ return "" , fmt .Errorf ("admission timed out or was canceled after broker errors: %s" , strings .Join (lastErrs , "; " ))
104124 }
105- errs = append (errs , fmt .Sprintf ("%s: %v" , brokerURL , err ))
106125 }
107- return "" , fmt .Errorf ("all admission brokers rejected or failed: %s" , strings .Join (errs , "; " ))
108126}
109127
110128func admitOne (ctx context.Context , httpClient * http.Client , dstackClient quoteClient , brokerURL , identity string , statementBytes []byte , vmConfig string ) (string , error ) {
@@ -141,7 +159,7 @@ func challenge(ctx context.Context, httpClient *http.Client, brokerURL string) (
141159 defer resp .Body .Close ()
142160 if resp .StatusCode != http .StatusOK {
143161 body , _ := io .ReadAll (io .LimitReader (resp .Body , 4096 ))
144- return "" , fmt . Errorf ( "challenge HTTP %d: %s" , resp .StatusCode , strings .TrimSpace (string (body )))
162+ return "" , httpStatusError { status : resp .StatusCode , body : strings .TrimSpace (string (body ))}
145163 }
146164 var out struct {
147165 Nonce string `json:"nonce"`
@@ -180,7 +198,7 @@ func attest(ctx context.Context, httpClient *http.Client, brokerURL string, payl
180198 defer resp .Body .Close ()
181199 if resp .StatusCode != http .StatusOK {
182200 body , _ := io .ReadAll (io .LimitReader (resp .Body , 4096 ))
183- return "" , fmt . Errorf ( "attest HTTP %d: %s" , resp .StatusCode , strings .TrimSpace (string (body )))
201+ return "" , httpStatusError { status : resp .StatusCode , body : strings .TrimSpace (string (body ))}
184202 }
185203 var out struct {
186204 ConsulACLToken string `json:"consul_acl_token"`
@@ -232,3 +250,33 @@ func shortHash(h string) string {
232250 }
233251 return h [:12 ]
234252}
253+
254+ type httpStatusError struct {
255+ status int
256+ body string
257+ }
258+
259+ func (e httpStatusError ) Error () string {
260+ return fmt .Sprintf ("HTTP %d: %s" , e .status , e .body )
261+ }
262+
263+ func isPermanentAdmissionError (err error ) bool {
264+ var statusErr httpStatusError
265+ if ! errors .As (err , & statusErr ) {
266+ return false
267+ }
268+ return statusErr .status == http .StatusBadRequest ||
269+ statusErr .status == http .StatusUnauthorized ||
270+ statusErr .status == http .StatusForbidden
271+ }
272+
273+ func sleepContext (ctx context.Context , d time.Duration ) bool {
274+ timer := time .NewTimer (d )
275+ defer timer .Stop ()
276+ select {
277+ case <- timer .C :
278+ return true
279+ case <- ctx .Done ():
280+ return false
281+ }
282+ }
0 commit comments