// WritePackage satisfies the platform interface for generating a docker package // that encapsulates the environment for a CAR based chaincode func (carPlatform *Platform) WritePackage(spec *pb.ChaincodeSpec, tw *tar.Writer) error { path, err := download(spec.ChaincodeID.Path) if err != nil { return err } var buf []string //let the executable's name be chaincode ID's name buf = append(buf, cutil.GetDockerfileFromConfig("chaincode.car.Dockerfile")) buf = append(buf, "COPY package.car /tmp/package.car") // invoking directly for maximum JRE compatiblity buf = append(buf, fmt.Sprintf("RUN java -jar /usr/local/bin/chaintool buildcar /tmp/package.car -o $GOPATH/bin/%s && rm /tmp/package.car", spec.ChaincodeID.Name)) dockerFileContents := strings.Join(buf, "\n") dockerFileSize := int64(len([]byte(dockerFileContents))) //Make headers identical by using zero time var zeroTime time.Time tw.WriteHeader(&tar.Header{Name: "Dockerfile", Size: dockerFileSize, ModTime: zeroTime, AccessTime: zeroTime, ChangeTime: zeroTime}) tw.Write([]byte(dockerFileContents)) err = cutil.WriteFileToPackage(path, "package.car", tw) if err != nil { return err } return nil }
//tw is expected to have the chaincode in it from GenerateHashcode. //This method will just package the dockerfile func writeChaincodePackage(spec *pb.ChaincodeSpec, tw *tar.Writer) error { var urlLocation string var err error if strings.HasPrefix(spec.ChaincodeID.Path, "http://") || strings.HasPrefix(spec.ChaincodeID.Path, "https://") { urlLocation, err = getCodeFromHTTP(spec.ChaincodeID.Path) defer func() { os.RemoveAll(urlLocation) }() if err != nil { return err } } else { urlLocation = spec.ChaincodeID.Path } if urlLocation == "" { return fmt.Errorf("empty url location") } if strings.LastIndex(urlLocation, "/") == len(urlLocation)-1 { urlLocation = urlLocation[:len(urlLocation)-1] } buildCmd, err := getBuildCmd(urlLocation) if err != nil { return err } var dockerFileContents string var buf []string if viper.GetBool("security.enabled") { //todo } else { buf = append(buf, cutil.GetDockerfileFromConfig("chaincode.java.Dockerfile")) buf = append(buf, "COPY src /root/chaincode") buf = append(buf, "RUN cd /root/chaincode && "+buildCmd) buf = append(buf, "RUN cp /root/chaincode/build/chaincode.jar /root") buf = append(buf, "RUN cp /root/chaincode/build/libs/* /root/libs") } dockerFileContents = strings.Join(buf, "\n") dockerFileSize := int64(len([]byte(dockerFileContents))) //Make headers identical by using zero time var zeroTime time.Time tw.WriteHeader(&tar.Header{Name: "Dockerfile", Size: dockerFileSize, ModTime: zeroTime, AccessTime: zeroTime, ChangeTime: zeroTime}) tw.Write([]byte(dockerFileContents)) err = cutil.WriteJavaProjectToPackage(tw, urlLocation) if err != nil { return fmt.Errorf("Error writing Chaincode package contents: %s", err) } return nil }
//tw is expected to have the chaincode in it from GenerateHashcode. This method //will just package rest of the bytes func writeChaincodePackage(spec *pb.ChaincodeSpec, tw *tar.Writer) error { var urlLocation string if strings.HasPrefix(spec.ChaincodeID.Path, "http://") { urlLocation = spec.ChaincodeID.Path[7:] } else if strings.HasPrefix(spec.ChaincodeID.Path, "https://") { urlLocation = spec.ChaincodeID.Path[8:] } else { urlLocation = spec.ChaincodeID.Path } if urlLocation == "" { return fmt.Errorf("empty url location") } if strings.LastIndex(urlLocation, "/") == len(urlLocation)-1 { urlLocation = urlLocation[:len(urlLocation)-1] } toks := strings.Split(urlLocation, "/") if toks == nil || len(toks) == 0 { return fmt.Errorf("cannot get path components from %s", urlLocation) } chaincodeGoName := toks[len(toks)-1] if chaincodeGoName == "" { return fmt.Errorf("could not get chaincode name from path %s", urlLocation) } //let the executable's name be chaincode ID's name newRunLine := fmt.Sprintf("RUN go install %s && cp src/github.com/hyperledger/fabric/peer/core.yaml $GOPATH/bin && mv $GOPATH/bin/%s $GOPATH/bin/%s", urlLocation, chaincodeGoName, spec.ChaincodeID.Name) //NOTE-this could have been abstracted away so we could use it for all platforms in a common manner //However, it would still be docker specific. Hence any such abstraction has to be done in a manner that //is not just language dependent but also container depenedent. So lets make this change per platform for now //in the interest of avoiding over-engineering without proper abstraction if viper.GetBool("peer.tls.enabled") { newRunLine = fmt.Sprintf("%s\nCOPY src/certs/cert.pem %s", newRunLine, viper.GetString("peer.tls.cert.file")) } dockerFileContents := fmt.Sprintf("%s\n%s", cutil.GetDockerfileFromConfig("chaincode.golang.Dockerfile"), newRunLine) dockerFileSize := int64(len([]byte(dockerFileContents))) //Make headers identical by using zero time var zeroTime time.Time tw.WriteHeader(&tar.Header{Name: "Dockerfile", Size: dockerFileSize, ModTime: zeroTime, AccessTime: zeroTime, ChangeTime: zeroTime}) tw.Write([]byte(dockerFileContents)) err := cutil.WriteGopathSrc(tw, urlLocation) if err != nil { return fmt.Errorf("Error writing Chaincode package contents: %s", err) } return nil }