Skip to content

Commit

Permalink
package:container #1 rev.
Browse files Browse the repository at this point in the history
  • Loading branch information
nextisd committed Sep 30, 2016
1 parent 96af471 commit 67c373d
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 9 deletions.
10 changes: 8 additions & 2 deletions core/container/ccintf/ccintf.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,41 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package ccintf

//This package defines the interfaces that support runtime and
//communication between chaincode and peer (chaincode support).
//Currently inproccontroller uses it. dockercontroller does not.
// ccintf 패키지 : 체인코드와 피어간의 런타임/통신 인터페이스를 정의함
// 현재는 inproccontrollse 패키지 에서 사용중임(dockercontroller 에서는 미사용)
package ccintf

import (
pb "github.com/hyperledger/fabric/protos"
"golang.org/x/net/context"
)

// ChaincodeStream interface for stream between Peer and chaincode instance.
// Chaincodestream interface : peer와 chaincode instance 사이의 스트림에 대한 인터페이스.
type ChaincodeStream interface {
Send(*pb.ChaincodeMessage) error
Recv() (*pb.ChaincodeMessage, error)
}

// CCSupport must be implemented by the chaincode support side in peer
// (such as chaincode_support)
// CCSupport 인터페이스는 피어단의 체인코드 지원 소스코드에서 반드시 구현되어야 함(e.g. chaincode_support.go)
// QQQ. ?? 해당 코드에 구현 안되어 있음
type CCSupport interface {
HandleChaincodeStream(context.Context, ChaincodeStream) error
}

// GetCCHandlerKey is used to pass CCSupport via context
// HGetCCHandlerKey는 컨텍스트를 통해 CCSupport을 전달.
func GetCCHandlerKey() string {
return "CCHANDLER"
}

//CCID encapsulates chaincode ID
// CCID는 체인코드ID를 캡슐화 시킴, VM 구동시 사용.
type CCID struct {
ChaincodeSpec *pb.ChaincodeSpec
NetworkID string
Expand Down
17 changes: 12 additions & 5 deletions core/container/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
)

// Config the config wrapper structure
// .config wrapper 구조체를 설정
type Config struct {
}

Expand All @@ -35,14 +36,17 @@ func init() {
}

// SetupTestLogging setup the logging during test execution
// SetupTestLogging함수는 테스트 실행 로그를 셋팅
func SetupTestLogging() {
level, err := logging.LogLevel(viper.GetString("peer.logging.level"))
if err == nil {
// No error, use the setting
// peer.logging.level 설정값 사용
logging.SetLevel(level, "main")
logging.SetLevel(level, "server")
logging.SetLevel(level, "peer")
} else {
// peer.logging.level 미존재시 로그레벨을 ERROR로 설정
vmLogger.Warningf("Log level not recognized '%s', defaulting to %s: %s", viper.GetString("peer.logging.level"), logging.ERROR, err)
logging.SetLevel(logging.ERROR, "main")
logging.SetLevel(logging.ERROR, "server")
Expand All @@ -51,25 +55,28 @@ func SetupTestLogging() {
}

// SetupTestConfig setup the config during test execution
// SetupTestConfig함수는 테스트 실행시 사용할 config를 셋팅
func SetupTestConfig() {
flag.Parse()

// Now set the configuration file
// 여기서 configuration file 셋팅
viper.SetEnvPrefix("CORE")
viper.AutomaticEnv()
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
viper.SetConfigName("core") // name of config file (without extension)
viper.AddConfigPath("./") // path to look for the config file in
viper.AddConfigPath("./../../peer/") // path to look for the config file in
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
viper.SetConfigName("core") // name of config file (without extension) // 설정파일명 (확장자 제외)
viper.AddConfigPath("./") // path to look for the config file in // 설정파일을 찾을 경로
viper.AddConfigPath("./../../peer/") // path to look for the config file in // 설정파일을 찾을 경로
err := viper.ReadInConfig() // Find and read the config file // 경로상의 설정 파일 read
if err != nil { // Handle errors reading the config file // read 에러시 예외처리
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}

SetupTestLogging()

// Set the number of maxprocs
// maxprocs 갯수 설정
var numProcsDesired = viper.GetInt("peer.gomaxprocs")
vmLogger.Debugf("setting Number of procs to %d, was %d\n", numProcsDesired, runtime.GOMAXPROCS(2))

Expand Down
37 changes: 37 additions & 0 deletions core/container/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
)

//abstract virtual image for supporting arbitrary virual machines
//임의의 가상 머신을 지원하기 위한 가상 이미지 abstraction
type vm interface {
Deploy(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, attachstdin bool, attachstdout bool, reader io.Reader) error
Start(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, attachstdin bool, attachstdout bool, reader io.Reader) error
Expand All @@ -46,22 +47,30 @@ type refCountedLock struct {
// . abstract construction of different types of VMs (we only care about Docker for now)
// . manage lifecycle of VM (start with build, start, stop ...
// eventually probably need fine grained management)
//VMController - VM들을 관리
// . VM 유형 생성(현재는 Docker만)
// . VM lifecycle 관리( build, start, stop 등으로 시작해서 세밀한 관리가 필요함)
// .
type VMController struct {
sync.RWMutex
// Handlers for each chaincode
containerLocks map[string]*refCountedLock
}

//singleton...acess through NewVMController
//singleton 객체, NewVMController로 액세스함
var vmcontroller *VMController

//constants for supported containers
//지원하는 컨테이너용 상수
const (
DOCKER = "Docker"
SYSTEM = "System"
)

//NewVMController - creates/returns singleton
//NerVMController - singleton 객체를 생성하고 리턴
//singleton pattern : 여러차례 객체 생성이 호출되더라도 프로그램내에서는 하나의 객체만 생성해서 유지됨
func init() {
vmcontroller = new(VMController)
vmcontroller.containerLocks = make(map[string]*refCountedLock)
Expand All @@ -83,8 +92,10 @@ func (vmc *VMController) newVM(typ string) vm {
return v
}

//컨테이너를 sync.RWMutex lock 처리
func (vmc *VMController) lockContainer(id string) {
//get the container lock under global lock
//global lock 상태에서 컨테이너 lock을 획득
vmcontroller.Lock()
var refLck *refCountedLock
var ok bool
Expand All @@ -101,6 +112,7 @@ func (vmc *VMController) lockContainer(id string) {
vmLogger.Debugf("got container (%s) lock", id)
}

//컨테이너의 sync.RWMutex lock 해제(unlock)
func (vmc *VMController) unlockContainer(id string) {
vmcontroller.Lock()
if refLck, ok := vmcontroller.containerLocks[id]; ok {
Expand All @@ -122,19 +134,24 @@ func (vmc *VMController) unlockContainer(id string) {
//The context should be passed and tested at each layer till we stop
//note that we'd stop on the first method on the stack that does not
//take context
//VMCReqIntf 인터페이스 - 모든 request 들은 이 인터페이스를 구현해야함
//context는 각각의 레이어 구간마다 테스트가 필요함
type VMCReqIntf interface {
do(ctxt context.Context, v vm) VMCResp
getCCID() ccintf.CCID
}

//VMCResp - response from requests. resp field is a anon interface.
//It can hold any response. err should be tested first
//VMCResp - 요청에 대한 응답 구조체. Resp는 anon interface(anonymous)
//따라서 모든 응답을 처리할 수 있음. Err는 가장 먼저 테스트 되어야함.
type VMCResp struct {
Err error
Resp interface{}
}

//CreateImageReq - properties for creating an container image
//CreateImageReq - 컨테이너 이미지 생성을 위한 속성값 구조체
type CreateImageReq struct {
ccintf.CCID
Reader io.Reader
Expand All @@ -161,6 +178,7 @@ func (bp CreateImageReq) getCCID() ccintf.CCID {
}

//StartImageReq - properties for starting a container.
//StartImageReq - 컨테이너 구동을 위한 속성값 구조체
type StartImageReq struct {
ccintf.CCID
Reader io.Reader
Expand All @@ -187,12 +205,15 @@ func (si StartImageReq) getCCID() ccintf.CCID {
}

//StopImageReq - properties for stopping a container.
//StopImageReq - 컨테이너 구동 정지를 위한 속성값 구조체
type StopImageReq struct {
ccintf.CCID
Timeout uint
//by default we will kill the container after stopping
//default : 컨테이너 stop후 kill 처리
Dontkill bool
//by default we will remove the container after killing
//default : 컨테이너 kill후 remove 처리
Dontremove bool
}

Expand Down Expand Up @@ -244,6 +265,22 @@ func (di DestroyImageReq) getCCID() ccintf.CCID {
//context can be cancelled. VMCProcess will try to cancel calling functions if it can
//For instance docker clients api's such as BuildImage are not cancelable.
//In all cases VMCProcess will wait for the called go routine to return

//VMCProcess함수는 아래와 같이 사용되어야 함
// . context 생성
// . 유형별 req(컨테이너 컨트롤 속성 구조체) 생성 (e.g. CreateImageReq)
// . 고루틴 내에서 호출
// . 고루틴 내에서 응답 처리
//context는 취소 가능함. VMCProcess는 함수 호출 취소 시도 가능.
//예를들어 도커 클라이언트 API의 BuildImage 같은 명령은 취소 불가함
//VMCProcess는 호출된 고루틴의 리턴을 항상 대기하고 있음
// KTODO : 체인코드 실행시 VMCProcess()로 VM 이미지를 콘트롤함, chaincode쪽 분석시 추가 연계 분석필요!
// KTODO : 필요하면 아래 flow 그림으로 그릴것
// Chaincode(peer) deploy/invoke -> VMCProcess(Create/start/stop/destroy vm) -> newVM(SYSTEM)-inproccontroller -> req.do() -> 채널
// -> newVM(DOCKER)-dockercontroller -> req.do()
// @param ctxt context.Context : CCHANDLER를 키값으로 context 할당, peer의 체인코드와의 인터페이스 설정
// @param vmtype : 체인코드 deploy시 설정한 값, 현재는 Docker/System 두가지 값을 가짐
// @param req : container 패키지의 CreateImageReq,StartImageReq,StopImageReq,DestroyImageReq 중 택1
func VMCProcess(ctxt context.Context, vmtype string, req VMCReqIntf) (interface{}, error) {
v := vmcontroller.newVM(vmtype)

Expand Down
11 changes: 11 additions & 0 deletions core/container/dockercontroller/dockercontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ var (
)

//DockerVM is a vm. It is identified by an image id
// DockerVM은 image id로 구별되는 vm임
type DockerVM struct {
id string
}

//도커 호스트 config 가져오기
func getDockerHostConfig() *docker.HostConfig {
if hostConfig != nil {
return hostConfig
Expand Down Expand Up @@ -137,6 +139,7 @@ func (vm *DockerVM) deployImage(client *docker.Client, ccid ccintf.CCID, args []
//for docker inputbuf is tar reader ready for use by docker.Client
//the stream from end client to peer could directly be this tar stream
//talk to docker daemon using docker Client and build the image
//Deploy() : tar.gz파일 내부의 Dockerfile을 기초로 도커 이미지를 생성
func (vm *DockerVM) Deploy(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, attachstdin bool, attachstdout bool, reader io.Reader) error {
client, err := cutil.NewDockerClient()
switch err {
Expand All @@ -151,6 +154,7 @@ func (vm *DockerVM) Deploy(ctxt context.Context, ccid ccintf.CCID, args []string
}

//Start starts a container using a previously created docker image
//Start함수는 사전에 생성한 docker image로 컨테이너를 구동시킴.
func (vm *DockerVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, attachstdin bool, attachstdout bool, reader io.Reader) error {
imageID, _ := vm.GetVMName(ccid)
client, err := cutil.NewDockerClient()
Expand All @@ -162,13 +166,15 @@ func (vm *DockerVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string,
containerID := strings.Replace(imageID, ":", "_", -1)

//stop,force remove if necessary
//컨테이너를 강제로 종료시킴, 필요시 삭제할것.
dockerLogger.Debugf("Cleanup container %s", containerID)
vm.stopInternal(ctxt, client, containerID, 0, false, false)

dockerLogger.Debugf("Start container %s", containerID)
err = vm.createContainer(ctxt, client, imageID, containerID, args, env, attachstdin, attachstdout)
if err != nil {
//if image not found try to create image and retry
//image가 없을 경우 신규 생성해서 retry
if err == docker.ErrNoSuchImage {
if reader != nil {
dockerLogger.Debugf("start-could not find image ...attempt to recreate image %s", err)
Expand All @@ -192,6 +198,7 @@ func (vm *DockerVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string,
}

// start container with HostConfig was deprecated since v1.10 and removed in v1.2
// HostConfig을 통한 컨테이너 구동은 v1.2에서 삭제됨
err = client.StartContainer(containerID, nil)
if err != nil {
dockerLogger.Errorf("start-could not start container %s", err)
Expand All @@ -203,6 +210,7 @@ func (vm *DockerVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string,
}

//Stop stops a running chaincode
//Stop함수는 실행중인 체인코드를 정지시킴
func (vm *DockerVM) Stop(ctxt context.Context, ccid ccintf.CCID, timeout uint, dontkill bool, dontremove bool) error {
id, _ := vm.GetVMName(ccid)
client, err := cutil.NewDockerClient()
Expand Down Expand Up @@ -244,6 +252,7 @@ func (vm *DockerVM) stopInternal(ctxt context.Context, client *docker.Client, id
}

//Destroy destroys an image
//Destroy함수는 도커 이미지를 삭제
func (vm *DockerVM) Destroy(ctxt context.Context, ccid ccintf.CCID, force bool, noprune bool) error {
id, _ := vm.GetVMName(ccid)
client, err := cutil.NewDockerClient()
Expand All @@ -266,6 +275,8 @@ func (vm *DockerVM) Destroy(ctxt context.Context, ccid ccintf.CCID, force bool,

//GetVMName generates the docker image from peer information given the hashcode. This is needed to
//keep image name's unique in a single host, multi-peer environment (such as a development environment)
//GetVMName함수는 피어 정보의 해쉬코드값으로 도커 이미지를 생성함.
//single host, multi-peer 환경에서 이미지 이름을 유니크하게 유지하기 위해 필요함.(e.g. 개발환경)
func (vm *DockerVM) GetVMName(ccid ccintf.CCID) (string, error) {
if ccid.NetworkID != "" {
return fmt.Sprintf("%s-%s-%s", ccid.NetworkID, ccid.PeerID, ccid.ChaincodeSpec.ChaincodeID.Name), nil
Expand Down
10 changes: 10 additions & 0 deletions core/container/inproccontroller/inproccontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

// system chaincode 용 vm controller.
package inproccontroller

import (
Expand Down Expand Up @@ -43,6 +44,7 @@ var (
)

//Register registers system chaincode with given path. The deploy should be called to initialize
//Register함수는 주어진 경로에 시스템 체인코드를 등록함. 초기화를 위해 deploy를 호출해야함.
func Register(path string, cc shim.Chaincode) error {
tmp := typeRegistry[path]
if tmp != nil {
Expand All @@ -54,10 +56,12 @@ func Register(path string, cc shim.Chaincode) error {
}

//InprocVM is a vm. It is identified by a executable name
//InprocVM은 excutable name으로 구별되는 vm임.
type InprocVM struct {
id string
}

// 체인코드 인스턴스 생성
func (vm *InprocVM) getInstance(ctxt context.Context, ipctemplate *inprocContainer, ccid ccintf.CCID, args []string, env []string) (*inprocContainer, error) {
ipc := instRegistry[ccid.ChaincodeSpec.ChaincodeID.Name]
if ipc != nil {
Expand All @@ -71,6 +75,7 @@ func (vm *InprocVM) getInstance(ctxt context.Context, ipctemplate *inprocContain
}

//Deploy verifies chaincode is registered and creates an instance for it. Currently only one instance can be created
//Deploy함수는 체인코드 등록여부검증 및 해당 체인코드의 인스턴스를 생성함. 현재는 한개의 인스턴스만 생성 가능.
func (vm *InprocVM) Deploy(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, attachstdin bool, attachstdout bool, reader io.Reader) error {
path := ccid.ChaincodeSpec.ChaincodeID.Path

Expand All @@ -86,6 +91,7 @@ func (vm *InprocVM) Deploy(ctxt context.Context, ccid ccintf.CCID, args []string
_, err := vm.getInstance(ctxt, ipctemplate, ccid, args, env)

//FUTURE ... here is where we might check code for safety
//추후에... 여기서 코드 체크 필요.
inprocLogger.Debugf("registered : %s", path)

return err
Expand All @@ -106,6 +112,7 @@ func (ipc *inprocContainer) launchInProc(ctxt context.Context, id string, args [
if env == nil {
env = ipc.env
}
// shim.StartInProc() : 시스템 체인코드 bootstrap entry point, chaincode용 API는 아님
err := shim.StartInProc(env, args, ipc.chaincode, ccRcvPeerSend, peerRcvCCSend)
if err != nil {
err = fmt.Errorf("chaincode-support ended with err: %s", err)
Expand Down Expand Up @@ -143,6 +150,7 @@ func (ipc *inprocContainer) launchInProc(ctxt context.Context, id string, args [
}

//Start starts a previously registered system codechain
//Start함수는 사전에 등록된 시스템 체인코드를 실행함.
func (vm *InprocVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, attachstdin bool, attachstdout bool, reader io.Reader) error {
path := ccid.ChaincodeSpec.ChaincodeID.Path

Expand Down Expand Up @@ -184,6 +192,7 @@ func (vm *InprocVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string,
}

//Stop stops a system codechain
//Stop함수는 시스템 체인코드를 정지시킴
func (vm *InprocVM) Stop(ctxt context.Context, ccid ccintf.CCID, timeout uint, dontkill bool, dontremove bool) error {
path := ccid.ChaincodeSpec.ChaincodeID.Path

Expand Down Expand Up @@ -216,6 +225,7 @@ func (vm *InprocVM) Destroy(ctxt context.Context, ccid ccintf.CCID, force bool,
}

//GetVMName ignores the peer and network name as it just needs to be unique in process
//GetVMName함수는 프로세스 내에서 unique 해야 하므로 피어와 네트워크명을 무시함
func (vm *InprocVM) GetVMName(ccid ccintf.CCID) (string, error) {
return ccid.ChaincodeSpec.ChaincodeID.Name, nil
}
2 changes: 2 additions & 0 deletions core/container/inproccontroller/inprocstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
pb "github.com/hyperledger/fabric/protos"
)



// PeerChaincodeStream interface for stream between Peer and chaincode instance.
type inProcStream struct {
recv <-chan *pb.ChaincodeMessage
Expand Down
Loading

0 comments on commit 67c373d

Please sign in to comment.