github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/common/ccprovider/cc_statedb_artifacts_provider.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package ccprovider
     8  
     9  import (
    10  	"archive/tar"
    11  	"bytes"
    12  	"fmt"
    13  	"io"
    14  	"io/ioutil"
    15  	"path/filepath"
    16  	"strings"
    17  )
    18  
    19  // tarFileEntry encapsulates a file entry and it's contents inside a tar
    20  type TarFileEntry struct {
    21  	FileHeader  *tar.Header
    22  	FileContent []byte
    23  }
    24  
    25  // ExtractStatedbArtifactsAsTarbytes extracts the statedb artifacts from the code package tar and create a statedb artifact tar.
    26  // The state db artifacts are expected to contain state db specific artifacts such as index specification in the case of couchdb.
    27  // This function is intended to be used during chaincode instantiate/upgrade so that statedb artifacts can be created.
    28  func ExtractStatedbArtifactsForChaincode(ccNameVersion string) (installed bool, statedbArtifactsTar []byte, err error) {
    29  	ccpackage, err := GetChaincodeFromFS(ccNameVersion)
    30  	if err != nil {
    31  		// TODO for now, we assume that an error indicates that the chaincode is not installed on the peer.
    32  		// However, we need a way to differentiate between the 'not installed' and a general error so that on general error,
    33  		// we can abort the chaincode instantiate/upgrade/install operation.
    34  		ccproviderLogger.Infof("Error while loading installation package for ccNameVersion=%s Err=%s", ccNameVersion, err)
    35  		return false, nil, nil
    36  	}
    37  
    38  	statedbArtifactsTar, err = ExtractStatedbArtifactsFromCCPackage(ccpackage)
    39  	return true, statedbArtifactsTar, err
    40  }
    41  
    42  // ExtractStatedbArtifactsFromCCPackage extracts the statedb artifacts from the code package tar and create a statedb artifact tar.
    43  // The state db artifacts are expected to contain state db specific artifacts such as index specification in the case of couchdb.
    44  // This function is called during chaincode instantiate/upgrade (from above), and from install, so that statedb artifacts can be created.
    45  func ExtractStatedbArtifactsFromCCPackage(ccpackage CCPackage) (statedbArtifactsTar []byte, err error) {
    46  	cds := ccpackage.GetDepSpec()
    47  
    48  	metaprov, err := MetadataAsTarEntries(cds.CodePackage)
    49  	if err != nil {
    50  		ccproviderLogger.Infof("invalid deployment spec: %s", err)
    51  		return nil, fmt.Errorf("invalid deployment spec")
    52  	}
    53  	return metaprov, nil
    54  }
    55  
    56  // ExtractFileEntries extract file entries from the given `tarBytes`. A file entry is included in the
    57  // returned results only if it is located in a directory under the indicated databaseType directory
    58  // Example for chaincode indexes:
    59  // "META-INF/statedb/couchdb/indexes/indexColorSortName.json"
    60  // Example for collection scoped indexes:
    61  // "META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexCollMarbles.json"
    62  // An empty string will have the effect of returning all statedb metadata.  This is useful in validating an
    63  // archive in the future with multiple database types
    64  func ExtractFileEntries(tarBytes []byte, databaseType string) (map[string][]*TarFileEntry, error) {
    65  
    66  	indexArtifacts := map[string][]*TarFileEntry{}
    67  	tarReader := tar.NewReader(bytes.NewReader(tarBytes))
    68  	for {
    69  		hdr, err := tarReader.Next()
    70  		if err == io.EOF {
    71  			// end of tar archive
    72  			break
    73  		}
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  		if hdr.Typeflag == tar.TypeDir {
    78  			continue
    79  		}
    80  
    81  		//split the directory from the full name
    82  		dir, _ := filepath.Split(hdr.Name)
    83  		//remove the ending slash
    84  		if strings.HasPrefix(hdr.Name, "META-INF/statedb/"+databaseType) {
    85  			fileContent, err := ioutil.ReadAll(tarReader)
    86  			if err != nil {
    87  				return nil, err
    88  			}
    89  			indexArtifacts[filepath.Clean(dir)] = append(indexArtifacts[filepath.Clean(dir)], &TarFileEntry{FileHeader: hdr, FileContent: fileContent})
    90  		}
    91  	}
    92  
    93  	return indexArtifacts, nil
    94  }