github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/peer/chaincode/install.go (about)

     1  /*
     2  Copyright IBM Corp. 2016-2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package chaincode
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  
    23  	"github.com/golang/protobuf/proto"
    24  	"golang.org/x/net/context"
    25  
    26  	"github.com/hyperledger/fabric/core/common/ccpackage"
    27  	"github.com/hyperledger/fabric/core/common/ccprovider"
    28  	"github.com/hyperledger/fabric/peer/common"
    29  	pcommon "github.com/hyperledger/fabric/protos/common"
    30  	pb "github.com/hyperledger/fabric/protos/peer"
    31  	"github.com/hyperledger/fabric/protos/utils"
    32  
    33  	"github.com/spf13/cobra"
    34  )
    35  
    36  var chaincodeInstallCmd *cobra.Command
    37  
    38  const install_cmdname = "install"
    39  
    40  const install_desc = "Package the specified chaincode into a deployment spec and save it on the peer's path."
    41  
    42  // installCmd returns the cobra command for Chaincode Deploy
    43  func installCmd(cf *ChaincodeCmdFactory) *cobra.Command {
    44  	chaincodeInstallCmd = &cobra.Command{
    45  		Use:       "install",
    46  		Short:     fmt.Sprint(install_desc),
    47  		Long:      fmt.Sprint(install_desc),
    48  		ValidArgs: []string{"1"},
    49  		RunE: func(cmd *cobra.Command, args []string) error {
    50  			var ccpackfile string
    51  			if len(args) > 0 {
    52  				ccpackfile = args[0]
    53  			}
    54  			return chaincodeInstall(cmd, ccpackfile, cf)
    55  		},
    56  	}
    57  
    58  	return chaincodeInstallCmd
    59  }
    60  
    61  //install the depspec to "peer.address"
    62  func install(msg proto.Message, cf *ChaincodeCmdFactory) error {
    63  	creator, err := cf.Signer.Serialize()
    64  	if err != nil {
    65  		return fmt.Errorf("Error serializing identity for %s: %s", cf.Signer.GetIdentifier(), err)
    66  	}
    67  
    68  	prop, _, err := utils.CreateInstallProposalFromCDS(msg, creator)
    69  	if err != nil {
    70  		return fmt.Errorf("Error creating proposal  %s: %s", chainFuncName, err)
    71  	}
    72  
    73  	var signedProp *pb.SignedProposal
    74  	signedProp, err = utils.GetSignedProposal(prop, cf.Signer)
    75  	if err != nil {
    76  		return fmt.Errorf("Error creating signed proposal  %s: %s", chainFuncName, err)
    77  	}
    78  
    79  	proposalResponse, err := cf.EndorserClient.ProcessProposal(context.Background(), signedProp)
    80  	if err != nil {
    81  		return fmt.Errorf("Error endorsing %s: %s", chainFuncName, err)
    82  	}
    83  
    84  	if proposalResponse != nil {
    85  		logger.Debugf("Installed remotely %v", proposalResponse)
    86  	}
    87  
    88  	return nil
    89  }
    90  
    91  //generateChaincode creates ChaincodeDeploymentSpec as the package to install
    92  func generateChaincode(cmd *cobra.Command, chaincodeName, chaincodeVersion string) (*pb.ChaincodeDeploymentSpec, error) {
    93  	tmppkg, _ := ccprovider.GetChaincodePackage(chaincodeName, chaincodeVersion)
    94  	if tmppkg != nil {
    95  		return nil, fmt.Errorf("chaincode %s:%s exists", chaincodeName, chaincodeVersion)
    96  	}
    97  
    98  	spec, err := getChaincodeSpec(cmd)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	cds, err := getChaincodeDeploymentSpec(spec, true)
   104  	if err != nil {
   105  		return nil, fmt.Errorf("Error getting chaincode code %s: %s", chainFuncName, err)
   106  	}
   107  
   108  	return cds, nil
   109  }
   110  
   111  //getPackageFromFile get the chaincode package from file and the extracted ChaincodeDeploymentSpec
   112  func getPackageFromFile(ccpackfile string) (proto.Message, *pb.ChaincodeDeploymentSpec, error) {
   113  	b, err := ioutil.ReadFile(ccpackfile)
   114  	if err != nil {
   115  		return nil, nil, err
   116  	}
   117  
   118  	//the bytes should be a valid package (CDS or SigedCDS)
   119  	ccpack, err := ccprovider.GetCCPackage(b)
   120  	if err != nil {
   121  		return nil, nil, err
   122  	}
   123  
   124  	//either CDS or Envelope
   125  	o, err := ccpack.GetPackageObject(), nil
   126  	if err != nil {
   127  		return nil, nil, err
   128  	}
   129  
   130  	//try CDS first
   131  	cds, ok := o.(*pb.ChaincodeDeploymentSpec)
   132  	if !ok || cds == nil {
   133  		//try Envelope next
   134  		env, ok := o.(*pcommon.Envelope)
   135  		if !ok || env == nil {
   136  			return nil, nil, fmt.Errorf("error extracting valid chaincode package")
   137  		}
   138  
   139  		//this will check for a valid package Envelope
   140  		_, sCDS, err := ccpackage.ExtractSignedCCDepSpec(env)
   141  		if err != nil {
   142  			return nil, nil, fmt.Errorf("error extracting valid signed chaincode package(%s)", err)
   143  		}
   144  
   145  		//...and get the CDS at last
   146  		cds, err = utils.GetChaincodeDeploymentSpec(sCDS.ChaincodeDeploymentSpec)
   147  		if err != nil {
   148  			return nil, nil, fmt.Errorf("error extracting chaincode deployment spec(%s)", err)
   149  		}
   150  	}
   151  
   152  	return o, cds, nil
   153  }
   154  
   155  // chaincodeInstall installs the chaincode. If remoteinstall, does it via a lscc call
   156  func chaincodeInstall(cmd *cobra.Command, ccpackfile string, cf *ChaincodeCmdFactory) error {
   157  	var err error
   158  	if cf == nil {
   159  		cf, err = InitCmdFactory(true, false)
   160  		if err != nil {
   161  			return err
   162  		}
   163  	}
   164  
   165  	var ccpackmsg proto.Message
   166  	if ccpackfile == "" {
   167  		if chaincodePath == common.UndefinedParamValue || chaincodeVersion == common.UndefinedParamValue {
   168  			return fmt.Errorf("Must supply value for %s path and version parameters.", chainFuncName)
   169  		}
   170  		//generate a raw ChaincodeDeploymentSpec
   171  		ccpackmsg, err = generateChaincode(cmd, chaincodeName, chaincodeVersion)
   172  		if err != nil {
   173  			return err
   174  		}
   175  	} else {
   176  		//read in a package generated by the "package" sub-command (and perhaps signed
   177  		//by multiple owners with the "signpackage" sub-command)
   178  		var cds *pb.ChaincodeDeploymentSpec
   179  		ccpackmsg, cds, err = getPackageFromFile(ccpackfile)
   180  
   181  		if err != nil {
   182  			return err
   183  		}
   184  
   185  		//get the chaincode details from cds
   186  		cName := cds.ChaincodeSpec.ChaincodeId.Name
   187  		cVersion := cds.ChaincodeSpec.ChaincodeId.Version
   188  
   189  		//if user provided chaincodeName, use it for validation
   190  		if chaincodeName != "" && chaincodeName != cName {
   191  			return fmt.Errorf("chaincode name %s does not match name %s in package", chaincodeName, cName)
   192  		}
   193  
   194  		//if user provided chaincodeVersion, use it for validation
   195  		if chaincodeVersion != "" && chaincodeVersion != cVersion {
   196  			return fmt.Errorf("chaincode version %s does not match version %s in packages", chaincodeVersion, cVersion)
   197  		}
   198  	}
   199  
   200  	err = install(ccpackmsg, cf)
   201  
   202  	return err
   203  }