github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/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 installCmdName = "install"
    39  
    40  const installDesc = "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(installDesc),
    47  		Long:      fmt.Sprint(installDesc),
    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  	flagList := []string{
    58  		"lang",
    59  		"ctor",
    60  		"path",
    61  		"name",
    62  		"version",
    63  	}
    64  	attachFlags(chaincodeInstallCmd, flagList)
    65  
    66  	return chaincodeInstallCmd
    67  }
    68  
    69  //install the depspec to "peer.address"
    70  func install(msg proto.Message, cf *ChaincodeCmdFactory) error {
    71  	creator, err := cf.Signer.Serialize()
    72  	if err != nil {
    73  		return fmt.Errorf("Error serializing identity for %s: %s", cf.Signer.GetIdentifier(), err)
    74  	}
    75  
    76  	prop, _, err := utils.CreateInstallProposalFromCDS(msg, creator)
    77  	if err != nil {
    78  		return fmt.Errorf("Error creating proposal  %s: %s", chainFuncName, err)
    79  	}
    80  
    81  	var signedProp *pb.SignedProposal
    82  	signedProp, err = utils.GetSignedProposal(prop, cf.Signer)
    83  	if err != nil {
    84  		return fmt.Errorf("Error creating signed proposal  %s: %s", chainFuncName, err)
    85  	}
    86  
    87  	proposalResponse, err := cf.EndorserClient.ProcessProposal(context.Background(), signedProp)
    88  	if err != nil {
    89  		return fmt.Errorf("Error endorsing %s: %s", chainFuncName, err)
    90  	}
    91  
    92  	if proposalResponse != nil {
    93  		logger.Debugf("Installed remotely %v", proposalResponse)
    94  	}
    95  
    96  	return nil
    97  }
    98  
    99  //genChaincodeDeploymentSpec creates ChaincodeDeploymentSpec as the package to install
   100  func genChaincodeDeploymentSpec(cmd *cobra.Command, chaincodeName, chaincodeVersion string) (*pb.ChaincodeDeploymentSpec, error) {
   101  	if existed, _ := ccprovider.ChaincodePackageExists(chaincodeName, chaincodeVersion); existed {
   102  		return nil, fmt.Errorf("chaincode %s:%s already exists", chaincodeName, chaincodeVersion)
   103  	}
   104  
   105  	spec, err := getChaincodeSpec(cmd)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	cds, err := getChaincodeDeploymentSpec(spec, true)
   111  	if err != nil {
   112  		return nil, fmt.Errorf("Error getting chaincode code %s: %s", chainFuncName, err)
   113  	}
   114  
   115  	return cds, nil
   116  }
   117  
   118  //getPackageFromFile get the chaincode package from file and the extracted ChaincodeDeploymentSpec
   119  func getPackageFromFile(ccpackfile string) (proto.Message, *pb.ChaincodeDeploymentSpec, error) {
   120  	b, err := ioutil.ReadFile(ccpackfile)
   121  	if err != nil {
   122  		return nil, nil, err
   123  	}
   124  
   125  	//the bytes should be a valid package (CDS or SigedCDS)
   126  	ccpack, err := ccprovider.GetCCPackage(b)
   127  	if err != nil {
   128  		return nil, nil, err
   129  	}
   130  
   131  	//either CDS or Envelope
   132  	o, err := ccpack.GetPackageObject(), nil
   133  	if err != nil {
   134  		return nil, nil, err
   135  	}
   136  
   137  	//try CDS first
   138  	cds, ok := o.(*pb.ChaincodeDeploymentSpec)
   139  	if !ok || cds == nil {
   140  		//try Envelope next
   141  		env, ok := o.(*pcommon.Envelope)
   142  		if !ok || env == nil {
   143  			return nil, nil, fmt.Errorf("error extracting valid chaincode package")
   144  		}
   145  
   146  		//this will check for a valid package Envelope
   147  		_, sCDS, err := ccpackage.ExtractSignedCCDepSpec(env)
   148  		if err != nil {
   149  			return nil, nil, fmt.Errorf("error extracting valid signed chaincode package(%s)", err)
   150  		}
   151  
   152  		//...and get the CDS at last
   153  		cds, err = utils.GetChaincodeDeploymentSpec(sCDS.ChaincodeDeploymentSpec)
   154  		if err != nil {
   155  			return nil, nil, fmt.Errorf("error extracting chaincode deployment spec(%s)", err)
   156  		}
   157  	}
   158  
   159  	return o, cds, nil
   160  }
   161  
   162  // chaincodeInstall installs the chaincode. If remoteinstall, does it via a lscc call
   163  func chaincodeInstall(cmd *cobra.Command, ccpackfile string, cf *ChaincodeCmdFactory) error {
   164  	var err error
   165  	if cf == nil {
   166  		cf, err = InitCmdFactory(true, false)
   167  		if err != nil {
   168  			return err
   169  		}
   170  	}
   171  
   172  	var ccpackmsg proto.Message
   173  	if ccpackfile == "" {
   174  		if chaincodePath == common.UndefinedParamValue || chaincodeVersion == common.UndefinedParamValue || chaincodeName == common.UndefinedParamValue {
   175  			return fmt.Errorf("Must supply value for %s name, path and version parameters.", chainFuncName)
   176  		}
   177  		//generate a raw ChaincodeDeploymentSpec
   178  		ccpackmsg, err = genChaincodeDeploymentSpec(cmd, chaincodeName, chaincodeVersion)
   179  		if err != nil {
   180  			return err
   181  		}
   182  	} else {
   183  		//read in a package generated by the "package" sub-command (and perhaps signed
   184  		//by multiple owners with the "signpackage" sub-command)
   185  		var cds *pb.ChaincodeDeploymentSpec
   186  		ccpackmsg, cds, err = getPackageFromFile(ccpackfile)
   187  
   188  		if err != nil {
   189  			return err
   190  		}
   191  
   192  		//get the chaincode details from cds
   193  		cName := cds.ChaincodeSpec.ChaincodeId.Name
   194  		cVersion := cds.ChaincodeSpec.ChaincodeId.Version
   195  
   196  		//if user provided chaincodeName, use it for validation
   197  		if chaincodeName != "" && chaincodeName != cName {
   198  			return fmt.Errorf("chaincode name %s does not match name %s in package", chaincodeName, cName)
   199  		}
   200  
   201  		//if user provided chaincodeVersion, use it for validation
   202  		if chaincodeVersion != "" && chaincodeVersion != cVersion {
   203  			return fmt.Errorf("chaincode version %s does not match version %s in packages", chaincodeVersion, cVersion)
   204  		}
   205  	}
   206  
   207  	err = install(ccpackmsg, cf)
   208  
   209  	return err
   210  }