-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
1,013 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#SPDX-License-Identifier: Apache-2.0 | ||
bin/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"text/template" | ||
|
||
"github.com/otiai10/copy" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
var logger = log.New(os.Stderr, "", 0) | ||
|
||
type chaincodeMetadata struct { | ||
Type string `json:"type"` | ||
} | ||
|
||
// Connection structure is used to represent the | ||
// connection.json file that is supplied in the | ||
// chaincode package. | ||
type connection struct { | ||
Address string `json:"address"` | ||
DialTimeout string `json:"dial_timeout"` | ||
TLS bool `json:"tls_required"` | ||
ClientAuth bool `json:"client_auth_required"` | ||
RootCert string `json:"root_cert"` | ||
ClientKey string `json:"client_key"` | ||
ClientCert string `json:"client_cert"` | ||
} | ||
|
||
type Config struct { | ||
PeerName string | ||
} | ||
|
||
func main() { | ||
logger.Println("::Build") | ||
|
||
if err := run(); err != nil { | ||
logger.Printf("::Error: %v\n", err) | ||
os.Exit(1) | ||
} | ||
|
||
logger.Printf("::Build phase completed") | ||
|
||
} | ||
|
||
func run() error { | ||
if len(os.Args) < 4 { | ||
return fmt.Errorf("incorrect number of arguments") | ||
} | ||
|
||
sourceDir, metadataDir, outputDir := os.Args[1], os.Args[2], os.Args[3] | ||
|
||
connectionSrcFile := filepath.Join(sourceDir, "/connection.json") | ||
metadataFile := filepath.Clean(filepath.Join(metadataDir, "metadata.json")) | ||
connectionDestFile := filepath.Join(outputDir, "/connection.json") | ||
metainfoSrcDir := filepath.Join(sourceDir, "META-INF") | ||
metainfoDestDir := filepath.Join(outputDir, "META-INF") | ||
|
||
// Process and check the metadata file, then copy to the output location | ||
if _, err := os.Stat(metadataFile); err != nil { | ||
return errors.WithMessagef(err, "%s not found ", metadataFile) | ||
} | ||
|
||
metadataFileContents, cause := os.ReadFile(metadataFile) | ||
if cause != nil { | ||
return errors.WithMessagef(cause, "%s file not readable", metadataFile) | ||
} | ||
|
||
var metadata chaincodeMetadata | ||
if err := json.Unmarshal(metadataFileContents, &metadata); err != nil { | ||
return errors.WithMessage(err, "Unable to parse JSON") | ||
} | ||
|
||
if strings.ToLower(metadata.Type) != "external" { | ||
return fmt.Errorf("chaincode type should be external, it is %s", metadata.Type) | ||
} | ||
|
||
if err := copy.Copy(metadataDir, outputDir); err != nil { | ||
return fmt.Errorf("failed to copy build metadata folder: %s", err) | ||
} | ||
|
||
if _, err := os.Stat(metainfoSrcDir); !os.IsNotExist(err) { | ||
if err := copy.Copy(metainfoSrcDir, metainfoDestDir); err != nil { | ||
return fmt.Errorf("failed to copy build META-INF folder: %s", err) | ||
} | ||
} | ||
|
||
// Process and update the connections file | ||
fileInfo, err := os.Stat(connectionSrcFile) | ||
if err != nil { | ||
return errors.WithMessagef(err, "%s not found ", connectionSrcFile) | ||
} | ||
|
||
connectionFileContents, err := os.ReadFile(connectionSrcFile) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// read the connection.json file into structure to process | ||
var connectionData connection | ||
if err := json.Unmarshal(connectionFileContents, &connectionData); err != nil { | ||
return err | ||
} | ||
|
||
// Treat each of the string fields in the connection.json as Go template | ||
// strings. They can be fixed strings, but if they are templates | ||
// then the JSON string that is defined in CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG | ||
// is used as the 'context' to parse the string | ||
|
||
updatedConnection := connection{} | ||
var cfg map[string]interface{} | ||
|
||
cfgString := os.Getenv("CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG") | ||
if cfgString != "" { | ||
if err := json.Unmarshal([]byte(cfgString), &cfg); err != nil { | ||
return fmt.Errorf("Failed to unmarshal %s", err) | ||
} | ||
} | ||
|
||
updatedConnection.Address, err = execTempl(cfg, connectionData.Address) | ||
if err != nil { | ||
return fmt.Errorf("Failed to parse the Address field template: %s", err) | ||
} | ||
|
||
updatedConnection.DialTimeout, err = execTempl(cfg, connectionData.DialTimeout) | ||
if err != nil { | ||
return fmt.Errorf("Failed to parse the DialTimeout field template: %s", err) | ||
} | ||
|
||
// if connection is TLS Enabled, updated with the correct information | ||
// no other information is needed for the no-TLS case, so the default can be assumed | ||
// to be good | ||
if connectionData.TLS { | ||
updatedConnection.TLS = true | ||
updatedConnection.ClientAuth = connectionData.ClientAuth | ||
|
||
updatedConnection.RootCert, err = execTempl(cfg, connectionData.RootCert) | ||
if err != nil { | ||
return fmt.Errorf("Failed to parse the RootCert field template: %s", err) | ||
} | ||
updatedConnection.ClientKey, err = execTempl(cfg, connectionData.ClientKey) | ||
if err != nil { | ||
return fmt.Errorf("Failed to parse the ClientKey field template: %s", err) | ||
} | ||
updatedConnection.ClientCert, err = execTempl(cfg, connectionData.ClientCert) | ||
if err != nil { | ||
return fmt.Errorf("Failed to parse the ClientCert field template: %s", err) | ||
} | ||
} | ||
|
||
updatedConnectionBytes, err := json.Marshal(updatedConnection) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal updated connection.json file: %s", err) | ||
} | ||
|
||
err = os.WriteFile(connectionDestFile, updatedConnectionBytes, fileInfo.Mode()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
|
||
} | ||
|
||
// execTempl is a helper function to process a template against a string, and return a string | ||
func execTempl(cfg map[string]interface{}, inputStr string) (string, error) { | ||
|
||
t, err := template.New("").Option("missingkey=error").Parse(inputStr) | ||
if err != nil { | ||
fmt.Printf("Failed to parse the template: %s", err) | ||
return "", err | ||
} | ||
|
||
buf := &bytes.Buffer{} | ||
err = t.Execute(buf, cfg) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return buf.String(), nil | ||
} |
Oops, something went wrong.