HTTP API Client: Acquire worker 74/181674/9
authorMaciej Wereski <m.wereski@partner.samsung.com>
Fri, 10 Nov 2017 14:12:31 +0000 (15:12 +0100)
committerMaciej Wereski <m.wereski@partner.samsung.com>
Tue, 10 Jul 2018 08:01:23 +0000 (10:01 +0200)
Definition of boruta/http.AccessInfo2.Addr had to be changed to specific
type (new.TCPAddr) rather than interface, as it's not possible to marshal
interface type to JSON.

Change-Id: I37afd203db356ba4621ad7448a554b59f6553ce9
Signed-off-by: Maciej Wereski <m.wereski@partner.samsung.com>
http/client/client.go
http/client/client_test.go
http/http.go
http/server/api/v1/handlers.go

index 0de4078..26b16dd 100644 (file)
@@ -23,7 +23,9 @@ package client
 
 import (
        "bytes"
+       "crypto/x509"
        "encoding/json"
+       "encoding/pem"
        "errors"
        "io"
        "io/ioutil"
@@ -237,9 +239,29 @@ func (client *BorutaClient) ListRequests(filter boruta.ListFilter) ([]boruta.Req
 // AcquireWorker queries Boruta server for information required to access
 // assigned Dryad. Access information may not be available when the call
 // is issued because requests need to have assigned worker.
-func (client *BorutaClient) AcquireWorker(reqID boruta.ReqID) (
-       *boruta.AccessInfo, error) {
-       return nil, util.ErrNotImplemented
+func (client *BorutaClient) AcquireWorker(reqID boruta.ReqID) (boruta.AccessInfo, error) {
+       var accInfo boruta.AccessInfo
+       path := client.url + "reqs/" + strconv.Itoa(int(reqID)) + "/acquire_worker"
+       resp, err := http.Post(path, "", nil)
+       if err != nil {
+               return accInfo, err
+       }
+       accInfo2 := new(util.AccessInfo2)
+       if err = processResponse(resp, &accInfo2); err != nil {
+               return accInfo, err
+       }
+       block, _ := pem.Decode([]byte(accInfo2.Key))
+       if block == nil || block.Type != "RSA PRIVATE KEY" {
+               return accInfo, errors.New("wrong key: " + accInfo2.Key)
+       }
+       key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+       if err != nil {
+               return accInfo, err
+       }
+       accInfo.Addr = accInfo2.Addr
+       accInfo.Username = accInfo2.Username
+       accInfo.Key = *key
+       return accInfo, nil
 }
 
 // ProlongAccess requests Boruta server to extend running time of job. User may
index 2eda6df..94b4ca1 100644 (file)
 package client
 
 import (
+       "crypto/x509"
        "encoding/json"
+       "encoding/pem"
        "errors"
        "io/ioutil"
+       "net"
        "net/http"
        "net/http/httptest"
        "strings"
@@ -43,6 +46,8 @@ type testCase struct {
        contentType string
        // expected status
        status int
+       // response that should be returned (read from server testdata if empty)
+       resp string
        // expected headers
        header http.Header
 }
@@ -178,9 +183,14 @@ func prepareServer(method string, tests []*testCase) *httptest.Server {
                        default:
                                fpath += ".txt"
                        }
-                       data, err = ioutil.ReadFile(fpath)
-                       if err != nil {
-                               panic(err)
+                       // Or use reply provided in testcase instead.
+                       if test.resp == "" {
+                               data, err = ioutil.ReadFile(fpath)
+                               if err != nil {
+                                       panic(err)
+                               }
+                       } else {
+                               data = []byte(test.resp)
                        }
                        w.Header().Set("Content-Type", test.contentType)
                }
@@ -602,12 +612,82 @@ func TestListRequests(t *testing.T) {
 }
 
 func TestAcquireWorker(t *testing.T) {
-       assert, client := initTest(t, "")
-       assert.NotNil(client)
+       prefix := "acquire-worker-"
+       path := "/api/v1/reqs/"
 
-       accessInfo, err := client.AcquireWorker(ReqID(0))
-       assert.Nil(accessInfo)
-       assert.Equal(util.ErrNotImplemented, err)
+       badkeyAI := util.AccessInfo2{
+               Addr: &net.TCPAddr{
+                       IP:   net.IPv4(127, 0, 0, 1),
+                       Port: 22,
+               },
+               Key:      "bad key :(",
+               Username: "lelpolel",
+       }
+
+       tests := []*testCase{
+               &testCase{
+                       // valid request
+                       name:        prefix + "valid",
+                       path:        path + "1/acquire_worker",
+                       contentType: contentJSON,
+                       status:      http.StatusOK,
+               },
+               &testCase{
+                       // missing request
+                       name:        prefix + "missing",
+                       path:        path + "2/acquire_worker",
+                       contentType: contentJSON,
+                       status:      http.StatusNotFound,
+               },
+               &testCase{
+                       // bad key request
+                       name:        prefix + "badkey",
+                       path:        path + "3/acquire_worker",
+                       contentType: contentJSON,
+                       status:      http.StatusOK,
+                       resp:        string(jsonMustMarshal(badkeyAI)),
+               },
+       }
+
+       srv := prepareServer(http.MethodPost, tests)
+       defer srv.Close()
+       assert, client := initTest(t, srv.URL)
+
+       // from server/api/v1 AcquireWorker tests
+       keyPem := "-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgQCyBgKbrwKh75BDoigwltbazFGDLdlxf9YLpFj5v+4ieKgsaN+W\n+kRvamSuB5CC2tqFql5x7kPt1U+vVMwkzVRewF/HHzRYxgLHlge6d1ZALpCWywaz\nslt5pNCmF7NoZ//WTSrafufDI4IRoNgkHtEKvnWdBaPPnY4Cf+PCbZOYNQIDAQAB\nAoGBAJvoz5fxKekQmdPhzDjhocF1d13fZbQVNSx0/seb476k1QQvxMHA5PZ+wzX2\nwgUYDpFJp/U3qp48VtFC/pasjNoG7zLPLLUJcg15eOoh4Ld7I1e4lRkLl3CwnqMk\nbc6UoKQRLli4O3cmaMxVHXal0o72s3o0qnHlRlZXLekwi6aBAkEA69j3bnbAybsF\n/NHelRYDH8bou+LCX2d/p6ReUR0bJ4yCAWRi/9Ld0ng482xinxGSpfovbIplBMFx\nH2eT2Cw0OQJBAME8LLz/3zb/vLG/t8Lfsequ1ZhVca/LlVR4yJLlyaVcywT9SJlO\nmKCy13SpKl8TY7czyufYrY4lobZjYaIsm90CQQCKhkRGWG/BzRymMyp2DJjHKFB4\nUqbx3FuJPqy7HcpeP1P4t1rCgbsSLNTefRGr9mlZHYqPSPYuheQImxCmTshZAkEA\nwAp5u+vfft1yPoT2r+l4/G99P8PLFJcTdbwEOlm8qWcrLW47dIE0FqEml3536b1v\nYGdMxFYHRjoIGSdzpKUI0QJAAqPdDp+y7kWaeIbKkp3Z3bLrj5wii2QAy2YlBDKe\npXrvruWJvL75OCYcxRju3DpVaoYqEmso+UEiQEDRB42YYg==\n-----END RSA PRIVATE KEY-----\n"
+       block, _ := pem.Decode([]byte(keyPem))
+       assert.NotNil(block)
+       key, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
+
+       access := AccessInfo{
+               Addr: &net.TCPAddr{
+                       IP:   net.IPv4(127, 0, 0, 1),
+                       Port: 22,
+               },
+               Key:      *key,
+               Username: "woƂchw",
+       }
+
+       // valid
+       accessInfo, err := client.AcquireWorker(ReqID(1))
+       assert.Equal(access, accessInfo)
+       assert.Nil(err)
+
+       // missing
+       accessInfo, err = client.AcquireWorker(ReqID(2))
+       assert.Zero(accessInfo)
+       assert.Equal(errReqNotFound, err)
+
+       // bad key
+       accessInfo, err = client.AcquireWorker(ReqID(3))
+       assert.Zero(accessInfo)
+       assert.Equal(errors.New("wrong key: "+badkeyAI.Key), err)
+
+       // http.Post failure
+       client.url = "http://nosuchaddress.fail"
+       accessInfo, err = client.AcquireWorker(ReqID(1))
+       assert.Zero(accessInfo)
+       assert.NotNil(err)
 }
 
 func TestProlongAccess(t *testing.T) {
index 4f137bb..a5d8973 100644 (file)
@@ -39,7 +39,7 @@ type WorkerStatePack struct {
 // replaces with users' public keys when proper user support is added.
 type AccessInfo2 struct {
        // Addr is necessary information to connect to a tunnel to Dryad.
-       Addr net.Addr
+       Addr *net.TCPAddr
        // Key is private RSA key in PEM format.
        Key string
        // Username is a login name for the job session.
index c534ca8..f1295e5 100644 (file)
@@ -23,6 +23,7 @@ import (
        "encoding/json"
        "encoding/pem"
        "io"
+       "net"
        "net/http"
 
        . "git.tizen.org/tools/boruta"
@@ -149,7 +150,7 @@ func (api *API) acquireWorkerHandler(r *http.Request, ps map[string]string) resp
                Bytes: x509.MarshalPKCS1PrivateKey(&accessInfo.Key),
        }))
        return util.AccessInfo2{
-               Addr:     accessInfo.Addr,
+               Addr:     accessInfo.Addr.(*net.TCPAddr),
                Key:      key,
                Username: accessInfo.Username,
        }