|
1 |
| -/* |
2 |
| -Copyright IBM Corp. 2016 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 |
| -*/ |
| 1 | +// Copyright IBM Corp. All Rights Reserved. |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
16 | 3 |
|
17 | 4 | package file
|
18 | 5 |
|
19 | 6 | import (
|
20 |
| - "fmt" |
| 7 | + "io" |
21 | 8 | "io/ioutil"
|
| 9 | + "os" |
22 | 10 |
|
23 | 11 | "github.com/golang/protobuf/proto"
|
24 | 12 | "github.com/hyperledger/fabric/orderer/common/bootstrap"
|
25 | 13 | cb "github.com/hyperledger/fabric/protos/common"
|
| 14 | + "github.com/pkg/errors" |
26 | 15 | )
|
27 | 16 |
|
28 | 17 | type fileBootstrapper struct {
|
29 | 18 | GenesisBlockFile string
|
30 | 19 | }
|
31 | 20 |
|
32 |
| -// New returns a new static bootstrap helper |
| 21 | +// New returns a new static bootstrap helper. |
33 | 22 | func New(fileName string) bootstrap.Helper {
|
34 | 23 | return &fileBootstrapper{
|
35 | 24 | GenesisBlockFile: fileName,
|
36 | 25 | }
|
37 | 26 | }
|
38 | 27 |
|
39 |
| -// GenesisBlock returns the genesis block to be used for bootstrapping |
| 28 | +// NewReplacer returns a new bootstrap replacer. |
| 29 | +func NewReplacer(fileName string) bootstrap.Replacer { |
| 30 | + return &fileBootstrapper{ |
| 31 | + GenesisBlockFile: fileName, |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +// GenesisBlock returns the genesis block to be used for bootstrapping. |
40 | 36 | func (b *fileBootstrapper) GenesisBlock() *cb.Block {
|
41 | 37 | bootstrapFile, fileErr := ioutil.ReadFile(b.GenesisBlockFile)
|
42 | 38 | if fileErr != nil {
|
43 |
| - panic(fmt.Errorf("Unable to bootstrap orderer. Error reading genesis block file: %v", fileErr)) |
| 39 | + panic(errors.Errorf("unable to bootstrap orderer. Error reading genesis block file: %v", fileErr)) |
44 | 40 | }
|
45 | 41 | genesisBlock := &cb.Block{}
|
46 | 42 | unmarshallErr := proto.Unmarshal(bootstrapFile, genesisBlock)
|
47 | 43 | if unmarshallErr != nil {
|
48 |
| - panic(fmt.Errorf("Unable to bootstrap orderer. Error unmarshalling genesis block: %v", unmarshallErr)) |
| 44 | + panic(errors.Errorf("unable to bootstrap orderer. Error unmarshalling genesis block: %v", unmarshallErr)) |
49 | 45 |
|
50 | 46 | }
|
51 | 47 | return genesisBlock
|
52 | 48 | } // GenesisBlock
|
| 49 | + |
| 50 | +// ReplaceGenesisBlockFile creates a backup of the genesis block file, and then replaces |
| 51 | +// it with the content of the given block. |
| 52 | +// This is used during consensus-type migration in order to generate a bootstrap file that |
| 53 | +// specifies the new consensus-type. |
| 54 | +func (b *fileBootstrapper) ReplaceGenesisBlockFile(block *cb.Block) error { |
| 55 | + buff, marshalErr := proto.Marshal(block) |
| 56 | + if marshalErr != nil { |
| 57 | + return errors.Wrap(marshalErr, "could not marshal block into a []byte") |
| 58 | + } |
| 59 | + |
| 60 | + genFileStat, statErr := os.Stat(b.GenesisBlockFile) |
| 61 | + if statErr != nil { |
| 62 | + return errors.Wrapf(statErr, "could not get the os.Stat of the genesis block file: %s", b.GenesisBlockFile) |
| 63 | + } |
| 64 | + |
| 65 | + if !genFileStat.Mode().IsRegular() { |
| 66 | + return errors.Errorf("genesis block file: %s, is not a regular file", b.GenesisBlockFile) |
| 67 | + } |
| 68 | + |
| 69 | + backupFile := b.GenesisBlockFile + ".bak" |
| 70 | + if err := backupGenesisFile(b.GenesisBlockFile, backupFile); err != nil { |
| 71 | + return errors.Wrapf(err, "could not copy genesis block file (%s) into backup file: %s", |
| 72 | + b.GenesisBlockFile, backupFile) |
| 73 | + } |
| 74 | + |
| 75 | + if err := ioutil.WriteFile(b.GenesisBlockFile, buff, genFileStat.Mode()); err != nil { |
| 76 | + return errors.Wrapf(err, "could not write new genesis block into file: %s; use backup if necessary: %s", |
| 77 | + b.GenesisBlockFile, backupFile) |
| 78 | + } |
| 79 | + |
| 80 | + return nil |
| 81 | +} |
| 82 | + |
| 83 | +func backupGenesisFile(src, dst string) error { |
| 84 | + source, err := os.Open(src) |
| 85 | + if err != nil { |
| 86 | + return err |
| 87 | + } |
| 88 | + defer source.Close() |
| 89 | + |
| 90 | + destination, err := os.Create(dst) |
| 91 | + if err != nil { |
| 92 | + return err |
| 93 | + } |
| 94 | + defer destination.Close() |
| 95 | + |
| 96 | + _, err = io.Copy(destination, source) |
| 97 | + return err |
| 98 | +} |
| 99 | + |
| 100 | +func (b *fileBootstrapper) CheckReadWrite() error { |
| 101 | + genFileStat, statErr := os.Stat(b.GenesisBlockFile) |
| 102 | + if statErr != nil { |
| 103 | + return errors.Wrapf(statErr, "could not get the os.Stat of the genesis block file: %s", b.GenesisBlockFile) |
| 104 | + } |
| 105 | + |
| 106 | + if !genFileStat.Mode().IsRegular() { |
| 107 | + return errors.Errorf("genesis block file: %s, is not a regular file", b.GenesisBlockFile) |
| 108 | + } |
| 109 | + |
| 110 | + genFile, openErr := os.OpenFile(b.GenesisBlockFile, os.O_RDWR, genFileStat.Mode().Perm()) |
| 111 | + if openErr != nil { |
| 112 | + if os.IsPermission(openErr) { |
| 113 | + return errors.Wrapf(openErr, "genesis block file: %s, cannot be opened for read-write, check permissions", b.GenesisBlockFile) |
| 114 | + } else { |
| 115 | + return errors.Wrapf(openErr, "genesis block file: %s, cannot be opened for read-write", b.GenesisBlockFile) |
| 116 | + } |
| 117 | + } |
| 118 | + genFile.Close() |
| 119 | + |
| 120 | + return nil |
| 121 | +} |
0 commit comments