[ARVADOS] updated: 1.2.0-40-ge8baef326

Git user git at public.curoverse.com
Fri Aug 31 11:43:50 EDT 2018


Summary of changes:
 lib/dispatchcloud/azure.go      | 58 ++++++++++++------------
 lib/dispatchcloud/azure_test.go | 98 ++++++++++++++++++++++++++++++++++++++---
 lib/dispatchcloud/provider.go   | 34 +++++++++++---
 3 files changed, 147 insertions(+), 43 deletions(-)

       via  e8baef326a98de0fd14144b1c221bb9c98bc1095 (commit)
      from  54701e0e492064eb05bf707d4c1886442cb066de (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit e8baef326a98de0fd14144b1c221bb9c98bc1095
Author: Peter Amstutz <pamstutz at veritasgenetics.com>
Date:   Fri Aug 31 11:42:01 2018 -0400

    13964: SSH access WIP
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz at veritasgenetics.com>

diff --git a/lib/dispatchcloud/azure.go b/lib/dispatchcloud/azure.go
index 21e8d28d8..da2e3eb8f 100644
--- a/lib/dispatchcloud/azure.go
+++ b/lib/dispatchcloud/azure.go
@@ -25,6 +25,7 @@ import (
 	"github.com/Azure/go-autorest/autorest/azure/auth"
 	"github.com/Azure/go-autorest/autorest/to"
 	"github.com/jmcvetta/randutil"
+	"golang.org/x/crypto/ssh"
 )
 
 type AzureProviderConfig struct {
@@ -40,7 +41,6 @@ type AzureProviderConfig struct {
 	StorageAccount               string  `json:"storage_account"`
 	BlobContainer                string  `json:"blob_container"`
 	Image                        string  `json:"image"`
-	AuthorizedKey                string  `json:"authorized_key"`
 	DeleteDanglingResourcesAfter float64 `json:"delete_dangling_resources_after"`
 }
 
@@ -186,7 +186,6 @@ func WrapAzureError(err error) error {
 
 type AzureProvider struct {
 	azconfig          AzureProviderConfig
-	arvconfig         arvados.Cluster
 	vmClient          VirtualMachinesClientWrapper
 	netClient         InterfacesClientWrapper
 	storageAcctClient storageacct.AccountsClient
@@ -196,18 +195,17 @@ type AzureProvider struct {
 	namePrefix        string
 }
 
-func NewAzureProvider(azcfg AzureProviderConfig, arvcfg arvados.Cluster, dispatcherID string) (prv Provider, err error) {
+func NewAzureProvider(azcfg AzureProviderConfig, dispatcherID string) (prv InstanceProvider, err error) {
 	ap := AzureProvider{}
-	err = ap.setup(azcfg, arvcfg, dispatcherID)
+	err = ap.setup(azcfg, dispatcherID)
 	if err != nil {
 		return nil, err
 	}
 	return &ap, nil
 }
 
-func (az *AzureProvider) setup(azcfg AzureProviderConfig, arvcfg arvados.Cluster, dispatcherID string) (err error) {
+func (az *AzureProvider) setup(azcfg AzureProviderConfig, dispatcherID string) (err error) {
 	az.azconfig = azcfg
-	az.arvconfig = arvcfg
 	vmClient := compute.NewVirtualMachinesClient(az.azconfig.SubscriptionID)
 	netClient := network.NewInterfacesClient(az.azconfig.SubscriptionID)
 	storageAcctClient := storageacct.NewAccountsClient(az.azconfig.SubscriptionID)
@@ -245,7 +243,8 @@ func (az *AzureProvider) setup(azcfg AzureProviderConfig, arvcfg arvados.Cluster
 func (az *AzureProvider) Create(ctx context.Context,
 	instanceType arvados.InstanceType,
 	imageId ImageID,
-	newTags InstanceTags) (Instance, error) {
+	newTags InstanceTags,
+	publicKey ssh.PublicKey) (Instance, error) {
 
 	name, err := randutil.String(15, "abcdefghijklmnopqrstuvwxyz0123456789")
 	if err != nil {
@@ -300,8 +299,6 @@ func (az *AzureProvider) Create(ctx context.Context,
 
 	log.Printf("URI instance vhd %v", instance_vhd)
 
-	tags["arvados-instance-type"] = &instanceType.Name
-
 	vmParameters := compute.VirtualMachine{
 		Location: &az.azconfig.Location,
 		Tags:     tags,
@@ -334,14 +331,14 @@ func (az *AzureProvider) Create(ctx context.Context,
 			},
 			OsProfile: &compute.OSProfile{
 				ComputerName:  &name,
-				AdminUsername: to.StringPtr("arvados"),
+				AdminUsername: to.StringPtr("crunch"),
 				LinuxConfiguration: &compute.LinuxConfiguration{
 					DisablePasswordAuthentication: to.BoolPtr(true),
 					SSH: &compute.SSHConfiguration{
 						PublicKeys: &[]compute.SSHPublicKey{
 							compute.SSHPublicKey{
-								Path:    to.StringPtr("/home/arvados/.ssh/authorized_keys"),
-								KeyData: to.StringPtr(az.azconfig.AuthorizedKey),
+								Path:    to.StringPtr("/home/crunch/.ssh/authorized_keys"),
+								KeyData: to.StringPtr(string(ssh.MarshalAuthorizedKey(publicKey))),
 							},
 						},
 					},
@@ -357,10 +354,9 @@ func (az *AzureProvider) Create(ctx context.Context,
 	}
 
 	return &AzureInstance{
-		instanceType: instanceType,
-		provider:     az,
-		nic:          nic,
-		vm:           vm,
+		provider: az,
+		nic:      nic,
+		vm:       vm,
 	}, nil
 }
 
@@ -381,13 +377,11 @@ func (az *AzureProvider) Instances(ctx context.Context) ([]Instance, error) {
 		if err != nil {
 			return nil, WrapAzureError(err)
 		}
-		if strings.HasPrefix(*result.Value().Name, az.namePrefix) &&
-			result.Value().Tags["arvados-instance-type"] != nil {
+		if strings.HasPrefix(*result.Value().Name, az.namePrefix) {
 			instances = append(instances, &AzureInstance{
-				provider:     az,
-				vm:           result.Value(),
-				nic:          interfaces[*(*result.Value().NetworkProfile.NetworkInterfaces)[0].ID],
-				instanceType: az.arvconfig.InstanceTypes[(*result.Value().Tags["arvados-instance-type"])]})
+				provider: az,
+				vm:       result.Value(),
+				nic:      interfaces[*(*result.Value().NetworkProfile.NetworkInterfaces)[0].ID]})
 		}
 	}
 	return instances, nil
@@ -522,19 +516,21 @@ func (az *AzureProvider) ManageBlobs(ctx context.Context) {
 	}
 }
 
+func (az *AzureProvider) Stop() {
+}
+
 type AzureInstance struct {
-	instanceType arvados.InstanceType
-	provider     *AzureProvider
-	nic          network.Interface
-	vm           compute.VirtualMachine
+	provider *AzureProvider
+	nic      network.Interface
+	vm       compute.VirtualMachine
 }
 
-func (ai *AzureInstance) String() string {
-	return *ai.vm.Name
+func (ai *AzureInstance) ID() InstanceID {
+	return InstanceID(*ai.vm.ID)
 }
 
-func (ai *AzureInstance) InstanceType() arvados.InstanceType {
-	return ai.instanceType
+func (ai *AzureInstance) String() string {
+	return *ai.vm.Name
 }
 
 func (ai *AzureInstance) SetTags(ctx context.Context, newTags InstanceTags) error {
@@ -562,7 +558,7 @@ func (ai *AzureInstance) SetTags(ctx context.Context, newTags InstanceTags) erro
 	return nil
 }
 
-func (ai *AzureInstance) GetTags(ctx context.Context) (InstanceTags, error) {
+func (ai *AzureInstance) Tags(ctx context.Context) (InstanceTags, error) {
 	tags := make(map[string]string)
 
 	for k, v := range ai.vm.Tags {
diff --git a/lib/dispatchcloud/azure_test.go b/lib/dispatchcloud/azure_test.go
index a5a173bee..c23360b32 100644
--- a/lib/dispatchcloud/azure_test.go
+++ b/lib/dispatchcloud/azure_test.go
@@ -6,9 +6,14 @@ package dispatchcloud
 
 import (
 	"context"
+	"errors"
 	"flag"
+	"io/ioutil"
 	"log"
+	"net"
 	"net/http"
+	"os"
+	"time"
 
 	"git.curoverse.com/arvados.git/sdk/go/arvados"
 	"git.curoverse.com/arvados.git/sdk/go/config"
@@ -17,6 +22,7 @@ import (
 	"github.com/Azure/go-autorest/autorest"
 	"github.com/Azure/go-autorest/autorest/azure"
 	"github.com/Azure/go-autorest/autorest/to"
+	"golang.org/x/crypto/ssh"
 	check "gopkg.in/check.v1"
 )
 
@@ -64,7 +70,7 @@ func (*InterfacesClientStub) ListComplete(ctx context.Context, resourceGroupName
 
 var live = flag.String("live-azure-cfg", "", "Test with real azure API, provide config file")
 
-func GetProvider() (Provider, ImageID, arvados.Cluster, error) {
+func GetProvider() (InstanceProvider, ImageID, arvados.Cluster, error) {
 	cluster := arvados.Cluster{
 		InstanceTypes: arvados.InstanceTypeMap(map[string]arvados.InstanceType{
 			"tiny": arvados.InstanceType{
@@ -83,14 +89,13 @@ func GetProvider() (Provider, ImageID, arvados.Cluster, error) {
 		if err != nil {
 			return nil, ImageID(""), cluster, err
 		}
-		ap, err := NewAzureProvider(cfg, cluster, "test123")
+		ap, err := NewAzureProvider(cfg, "test123")
 		return ap, ImageID(cfg.Image), cluster, err
 	} else {
 		ap := AzureProvider{
 			azconfig: AzureProviderConfig{
 				BlobContainer: "vhds",
 			},
-			arvconfig:    cluster,
 			dispatcherID: "test123",
 			namePrefix:   "compute-test123-",
 		}
@@ -106,13 +111,24 @@ func (*AzureProviderSuite) TestCreate(c *check.C) {
 		c.Fatal("Error making provider", err)
 	}
 
+	f, err := os.Open("azconfig_sshkey.pub")
+	c.Assert(err, check.IsNil)
+
+	keybytes, err := ioutil.ReadAll(f)
+	c.Assert(err, check.IsNil)
+
+	pk, _, _, _, err := ssh.ParseAuthorizedKey(keybytes)
+	c.Assert(err, check.IsNil)
+
 	inst, err := ap.Create(context.Background(),
 		cluster.InstanceTypes["tiny"],
-		img, map[string]string{"tag1": "bleep"})
+		img, map[string]string{"tag1": "bleep"},
+		pk)
 
 	c.Assert(err, check.IsNil)
 
 	log.Printf("Result %v %v", inst.String(), inst.Address())
+
 }
 
 func (*AzureProviderSuite) TestListInstances(c *check.C) {
@@ -126,8 +142,8 @@ func (*AzureProviderSuite) TestListInstances(c *check.C) {
 	c.Assert(err, check.IsNil)
 
 	for _, i := range l {
-		tg, _ := i.GetTags(context.Background())
-		log.Printf("%v %v %v %v", i.String(), i.Address(), i.InstanceType(), tg)
+		tg, _ := i.Tags(context.Background())
+		log.Printf("%v %v %v", i.String(), i.Address(), tg)
 	}
 }
 
@@ -230,7 +246,75 @@ func (*AzureProviderSuite) TestSetTags(c *check.C) {
 	c.Assert(err, check.IsNil)
 
 	if len(l) > 0 {
-		tg, _ := l[0].GetTags(context.Background())
+		tg, _ := l[0].Tags(context.Background())
 		log.Printf("tags are %v", tg)
 	}
 }
+
+func (*AzureProviderSuite) TestSSH(c *check.C) {
+	ap, _, _, err := GetProvider()
+	if err != nil {
+		c.Fatal("Error making provider", err)
+	}
+	l, err := ap.Instances(context.Background())
+	c.Assert(err, check.IsNil)
+
+	if len(l) > 0 {
+
+		sshclient, err := SetupSSHClient(c, l[0].Address()+":2222")
+		c.Assert(err, check.IsNil)
+
+		sess, err := sshclient.NewSession()
+		c.Assert(err, check.IsNil)
+
+		out, err := sess.Output("ls /")
+		c.Assert(err, check.IsNil)
+
+		log.Printf("%v", out)
+
+		sshclient.Conn.Close()
+	}
+}
+
+func SetupSSHClient(c *check.C, addr string) (*ssh.Client, error) {
+	if addr == "" {
+		return nil, errors.New("instance has no address")
+	}
+
+	f, err := os.Open("azconfig_sshkey")
+	c.Assert(err, check.IsNil)
+
+	keybytes, err := ioutil.ReadAll(f)
+	c.Assert(err, check.IsNil)
+
+	priv, err := ssh.ParsePrivateKey(keybytes)
+	c.Assert(err, check.IsNil)
+
+	var receivedKey ssh.PublicKey
+	client, err := ssh.Dial("tcp", addr, &ssh.ClientConfig{
+		User: "crunch",
+		Auth: []ssh.AuthMethod{
+			ssh.PublicKeys(priv),
+		},
+		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
+			receivedKey = key
+			return nil
+		},
+		Timeout: time.Minute,
+	})
+
+	if err != nil {
+		return nil, err
+	} else if receivedKey == nil {
+		return nil, errors.New("BUG: key was never provided to HostKeyCallback")
+	}
+
+	/*if wkr.publicKey == nil || !bytes.Equal(wkr.publicKey.Marshal(), receivedKey.Marshal()) {
+		err = wkr.instance.VerifyPublicKey(receivedKey, client)
+		if err != nil {
+			return nil, err
+		}
+		wkr.publicKey = receivedKey
+	}*/
+	return client, nil
+}
diff --git a/lib/dispatchcloud/provider.go b/lib/dispatchcloud/provider.go
index 3322575dc..ed5eb8fe2 100644
--- a/lib/dispatchcloud/provider.go
+++ b/lib/dispatchcloud/provider.go
@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"git.curoverse.com/arvados.git/sdk/go/arvados"
+	"golang.org/x/crypto/ssh"
 )
 
 // A RateLimitError should be returned by a Provider when the cloud
@@ -38,21 +39,44 @@ type ImageID string
 
 // instance is implemented by the provider-specific instance types.
 type Instance interface {
+	// ID returns the provider's instance ID. It must be stable
+	// for the life of the instance.
+	ID() InstanceID
+
 	// String typically returns the cloud-provided instance ID.
 	String() string
-	// Configured Arvados instance type
-	InstanceType() arvados.InstanceType
+
 	// Get tags
-	GetTags(context.Context) (InstanceTags, error)
+	Tags(context.Context) (InstanceTags, error)
+
 	// Replace tags with the given tags
 	SetTags(context.Context, InstanceTags) error
+
 	// Shut down the node
 	Destroy(context.Context) error
+
 	// SSH server hostname or IP address, or empty string if unknown pending creation.
 	Address() string
 }
 
-type Provider interface {
-	Create(context.Context, arvados.InstanceType, ImageID, InstanceTags) (Instance, error)
+type InstanceProvider interface {
+	// Create a new instance. If supported by the driver, add the
+	// provided public key to /root/.ssh/authorized_keys.
+	//
+	// The returned error should implement RateLimitError and
+	// QuotaError where applicable.
+	Create(context.Context, arvados.InstanceType, ImageID, InstanceTags, ssh.PublicKey) (Instance, error)
+
+	// Return all instances, including ones that are booting or
+	// shutting down.
+	//
+	// An instance returned by successive calls to Instances() may
+	// -- but does not need to -- be represented by the same
+	// Instance object each time. Thus, the caller is responsible
+	// for de-duplicating the returned instances by comparing the
+	// InstanceIDs returned by the instances' ID() methods.
 	Instances(context.Context) ([]Instance, error)
+
+	// Stop any background tasks and release other resources.
+	Stop()
 }

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list