// Prepare creates appropriate user, generates RSA key, installs public key
// so that it can be used for SSH authentication and returns private key.
// It removes current instance of the user, etc.
- Prepare() (key *rsa.PrivateKey, err error)
+ Prepare(key *rsa.PublicKey) (err error)
// Healthcheck tests Dryad for system state, STM functions and state on MuxPi.
// It may cause Dryad to call SetFail of Worker interface if the problem detected is critical.
Healthcheck() (err error)
package dryad
import (
- "crypto/rand"
- "crypto/rsa"
"os"
"path"
"strconv"
"golang.org/x/crypto/ssh"
)
-// sizeRSA is a length of the RSA key.
-// It is experimentally chosen value as it is the longest key while still being fast to generate.
-const sizeRSA = 1024
-
// installPublicKey marshals and stores key in a proper location to be read by ssh daemon.
func installPublicKey(key ssh.PublicKey, homedir, uid, gid string) error {
sshDir := path.Join(homedir, ".ssh")
}
return key.Chown(uid, gid)
}
-
-// generateAndInstallKey generates a new RSA key pair, installs the public part,
-// changes its owner, and returns the private part.
-func generateAndInstallKey(homedir, uid, gid string) (*rsa.PrivateKey, error) {
- key, err := rsa.GenerateKey(rand.Reader, sizeRSA)
- if err != nil {
- return nil, err
- }
- sshPubKey, err := ssh.NewPublicKey(&key.PublicKey)
- if err != nil {
- return nil, err
- }
- err = installPublicKey(sshPubKey, homedir, uid, gid)
- if err != nil {
- return nil, err
- }
- return key, nil
-}
+++ /dev/null
-/*
- * Copyright (c) 2017-2018 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package dryad
-
-import (
- "crypto/rand"
- "crypto/rsa"
- "strconv"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("key generator", func() {
- generate := func(size int) {
- _, err := rsa.GenerateKey(rand.Reader, size)
- Expect(err).ToNot(HaveOccurred())
- }
-
- Measure("2048 should be fast", func(b Benchmarker) {
- for _, size := range []int{512, 1024, 2048, 4096} {
- b.Time(strconv.Itoa(size), func() {
- generate(size)
- })
- }
- }, 2)
-})
. "git.tizen.org/tools/boruta"
"git.tizen.org/tools/muxpi/sw/nanopi/stm"
+ "golang.org/x/crypto/ssh"
)
// Rusalka implements Dryad interface. It is intended to be used on NanoPi connected to MuxPi.
}
// Prepare is part of implementation of Dryad interface. Call to Prepare stops LED blinking.
-func (r *Rusalka) Prepare() (key *rsa.PrivateKey, err error) {
+func (r *Rusalka) Prepare(key *rsa.PublicKey) (err error) {
// Stop maintenance.
if r.cancelMaintenance != nil {
r.cancelMaintenance()
// Remove/Add user.
err = r.dryadUser.delete()
if err != nil {
- return nil, fmt.Errorf("user removal failed: %s", err)
+ return fmt.Errorf("user removal failed: %s", err)
}
err = r.dryadUser.add()
if err != nil {
- return nil, fmt.Errorf("user creation failed: %s", err)
+ return fmt.Errorf("user creation failed: %s", err)
}
// Verify user's existance.
err = r.dryadUser.update()
if err != nil {
- return nil, fmt.Errorf("user information update failed: %s", err)
+ return fmt.Errorf("user information update failed: %s", err)
}
- // Prepare SSH access.
- return r.dryadUser.generateAndInstallKey()
+ // Prepare SSH access (it can't fail as key is of type rsa.PublicKey).
+ sshPubKey, _ := ssh.NewPublicKey(key)
+ // TODO: use ssh.PublicKey instead.
+ return r.dryadUser.generateAndInstallKey(sshPubKey)
}
// Healthcheck is part of implementation of Dryad interface.
//go:generate mockgen -destination=muxpi_mock_test.go -package dryad git.tizen.org/tools/muxpi/sw/nanopi/stm Interface
import (
+ "crypto/rand"
+ "crypto/rsa"
"crypto/x509"
"encoding/pem"
"os"
Skip("must be run as root")
}
- key, err := d.Prepare()
+ key, err := rsa.GenerateKey(rand.Reader, 1024)
+ Expect(err).ToNot(HaveOccurred())
+ err = d.Prepare(&key.PublicKey)
Expect(err).ToNot(HaveOccurred())
Expect(sshDir).To(BeADirectory())
Expect(authorizedKeysFile).To(BeARegularFile())
package dryad
import (
- "crypto/rsa"
"fmt"
"os/exec"
"os/user"
"strings"
"syscall"
+
+ "golang.org/x/crypto/ssh"
)
var (
// generateAndInstallKey calls generateAndInstallKey with parameters retrieved from the user field
// of borutaUser structure. This filed must be set before call to this function by update() method.
-func (bu *borutaUser) generateAndInstallKey() (*rsa.PrivateKey, error) {
- return generateAndInstallKey(bu.user.HomeDir, bu.user.Uid, bu.user.Gid)
+func (bu *borutaUser) generateAndInstallKey(key ssh.PublicKey) error {
+ return installPublicKey(key, bu.user.HomeDir, bu.user.Uid, bu.user.Gid)
}
// DryadPrepareRequest is a helper structure for Prepare method.
type DryadPrepareRequest struct {
+ Key *rsa.PublicKey
}
// DryadPrepareResponse is a helper structure for Prepare method.
type DryadPrepareResponse struct {
- Key *rsa.PrivateKey
}
// Prepare is RPC implementation of Prepare calling it.
func (s *DryadService) Prepare(request *DryadPrepareRequest, response *DryadPrepareResponse) (err error) {
- response.Key, err = s.impl.Prepare()
+ err = s.impl.Prepare(request.Key)
return
}
}
// Prepare is part of implementation of Dryad calling corresponding method on RPC server.
-func (_c *DryadClient) Prepare() (key *rsa.PrivateKey, err error) {
- _request := &DryadPrepareRequest{}
+func (_c *DryadClient) Prepare(key *rsa.PublicKey) (err error) {
+ _request := &DryadPrepareRequest{key}
_response := &DryadPrepareResponse{}
err = _c.client.Call("Dryad.Prepare", _request, _response)
- return _response.Key, err
+ return err
}
// Healthcheck is part of implementation of Dryad calling corresponding method on RPC server.
}
// Prepare mocks base method
-func (m *MockDryadClientManager) Prepare() (*rsa.PrivateKey, error) {
- ret := m.ctrl.Call(m, "Prepare")
- ret0, _ := ret[0].(*rsa.PrivateKey)
- ret1, _ := ret[1].(error)
- return ret0, ret1
+func (m *MockDryadClientManager) Prepare(arg0 *rsa.PublicKey) error {
+ ret := m.ctrl.Call(m, "Prepare", arg0)
+ ret0, _ := ret[0].(error)
+ return ret0
}
// Prepare indicates an expected call of Prepare
-func (mr *MockDryadClientManagerMockRecorder) Prepare() *gomock.Call {
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepare", reflect.TypeOf((*MockDryadClientManager)(nil).Prepare))
+func (mr *MockDryadClientManagerMockRecorder) Prepare(arg0 interface{}) *gomock.Call {
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepare", reflect.TypeOf((*MockDryadClientManager)(nil).Prepare), arg0)
}
// PutInMaintenance mocks base method
package workers
+//go:generate mockgen -package workers -destination=dryadclientmanager_mock_test.go -write_package_comment=false -mock_names ClientManager=MockDryadClientManager git.tizen.org/tools/boruta/rpc/dryad ClientManager
+
import (
"crypto/rand"
"crypto/rsa"
IP: dryadAddr.IP,
}
BeforeEach(func() {
+ sizeRSA = 256
wl = NewWorkerList()
})
var ctrl *gomock.Controller
var dcm *MockDryadClientManager
ip := net.IPv4(2, 4, 6, 8)
- key := &rsa.PrivateKey{}
testerr := errors.New("Test Error")
var info *mapWorker
noWorker := WorkerUUID("There's no such worker")
return info.State
}).Should(Equal(state))
}
- eventuallyKey := func(info *mapWorker, key *rsa.PrivateKey) {
+ eventuallyKey := func(info *mapWorker, match types.GomegaMatcher) {
EventuallyWithOffset(1, func() *rsa.PrivateKey {
wl.mutex.RLock()
defer wl.mutex.RUnlock()
return info.key
- }).Should(Equal(key))
+ }).Should(match)
}
BeforeEach(func() {
It("should work to SetState", func() {
gomock.InOrder(
dcm.EXPECT().Create(info.dryad),
- dcm.EXPECT().Prepare().Return(key, nil),
+ dcm.EXPECT().Prepare(gomock.AssignableToTypeOf(&rsa.PublicKey{})).Return(nil),
dcm.EXPECT().Close(),
)
err := wl.SetState(worker, IDLE)
Expect(err).ToNot(HaveOccurred())
eventuallyState(info, IDLE)
- eventuallyKey(info, key)
+ eventuallyKey(info, Not(Equal(&rsa.PrivateKey{})))
})
It("should fail to SetState if dryadClientManager fails to prepare client", func() {
gomock.InOrder(
dcm.EXPECT().Create(info.dryad),
- dcm.EXPECT().Prepare().Return(nil, testerr),
+ dcm.EXPECT().Prepare(gomock.AssignableToTypeOf(&rsa.PublicKey{})).Return(testerr),
dcm.EXPECT().Close(),
)
var ctrl *gomock.Controller
var dcm *MockDryadClientManager
ip := net.IPv4(2, 4, 6, 8)
- key := &rsa.PrivateKey{}
testerr := errors.New("Test Error")
noWorker := WorkerUUID("There's no such worker")
- eventuallyKey := func(info *mapWorker, key *rsa.PrivateKey) {
+ eventuallyKey := func(info *mapWorker, match types.GomegaMatcher) {
EventuallyWithOffset(1, func() *rsa.PrivateKey {
wl.mutex.RLock()
defer wl.mutex.RUnlock()
return info.key
- }).Should(Equal(key))
+ }).Should(match)
}
eventuallyState := func(info *mapWorker, state WorkerState) {
EventuallyWithOffset(1, func() WorkerState {
It("should set worker into IDLE state and prepare a key", func() {
gomock.InOrder(
dcm.EXPECT().Create(info.dryad),
- dcm.EXPECT().Prepare().Return(key, nil),
+ dcm.EXPECT().Prepare(gomock.AssignableToTypeOf(&rsa.PublicKey{})).Return(nil),
dcm.EXPECT().Close(),
)
Expect(err).NotTo(HaveOccurred())
eventuallyState(info, IDLE)
- eventuallyKey(info, key)
+ eventuallyKey(info, Not(Equal(&rsa.PrivateKey{})))
})
It("should fail to prepare worker if dryadClientManager fails to prepare client", func() {
gomock.InOrder(
dcm.EXPECT().Create(info.dryad),
- dcm.EXPECT().Prepare().Return(nil, testerr),
+ dcm.EXPECT().Prepare(gomock.AssignableToTypeOf(&rsa.PublicKey{})).Return(testerr),
dcm.EXPECT().Close(),
)
})
})
})
+
Describe("setState with changeListener", func() {
var ctrl *gomock.Controller
var wc *MockWorkerChange
package workers
import (
+ "crypto/rand"
"crypto/rsa"
"fmt"
"math"
// UUID denotes a key in Capabilities where WorkerUUID is stored.
const UUID string = "UUID"
+// sizeRSA is a length of the RSA key.
+// It is a variable for test purposes.
+var sizeRSA = 4096
+
// mapWorker is used by WorkerList to store all
// (public and private) structures representing Worker.
type mapWorker struct {
return nil
}
-// prepareKey delegates key generation to Dryad and sets up generated key in the
-// worker. In case of any failure it returns an error.
+// prepareKey generates key, installs public part on worker and stores private part in WorkerList.
func (wl *WorkerList) prepareKey(worker WorkerUUID) error {
addr, err := wl.GetWorkerAddr(worker)
if err != nil {
return err
}
defer client.Close()
- key, err := client.Prepare()
+ key, err := rsa.GenerateKey(rand.Reader, sizeRSA)
+ if err != nil {
+ return err
+ }
+ err = client.Prepare(&key.PublicKey)
if err != nil {
return err
}