suport multistage onbuild
This commit is contained in:
parent
2609944787
commit
70eb7ebcfa
|
|
@ -87,6 +87,75 @@ func Stages(opts *config.KanikoOptions) ([]config.KanikoStage, error) {
|
|||
return kanikoStages, nil
|
||||
}
|
||||
|
||||
func ParseInstructions(opts *config.KanikoOptions) ([]instructions.Stage, []instructions.ArgCommand, error) {
|
||||
var err error
|
||||
var d []uint8
|
||||
match, _ := regexp.MatchString("^https?://", opts.DockerfilePath)
|
||||
if match {
|
||||
response, e := http.Get(opts.DockerfilePath)
|
||||
if e != nil {
|
||||
return nil, nil, e
|
||||
}
|
||||
d, err = ioutil.ReadAll(response.Body)
|
||||
} else {
|
||||
d, err = ioutil.ReadFile(opts.DockerfilePath)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, fmt.Sprintf("reading dockerfile at path %s", opts.DockerfilePath))
|
||||
}
|
||||
|
||||
stages, metaArgs, err := Parse(d)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "parsing dockerfile")
|
||||
}
|
||||
|
||||
return stages, metaArgs, nil
|
||||
}
|
||||
|
||||
func ResolveCrossStageInstructions(stages []instructions.Stage) map[string]string {
|
||||
nameToIndex := make(map[string]string)
|
||||
for i, stage := range stages {
|
||||
index := strconv.Itoa(i)
|
||||
if stage.Name != "" {
|
||||
nameToIndex[stage.Name] = index
|
||||
}
|
||||
ResolveCommands(stage.Commands, nameToIndex)
|
||||
}
|
||||
|
||||
logrus.Debugf("Built stage name to index map: %v", nameToIndex)
|
||||
return nameToIndex
|
||||
}
|
||||
|
||||
func MakeKanikoStages(opts *config.KanikoOptions, stages []instructions.Stage, metaArgs []instructions.ArgCommand) ([]config.KanikoStage, error) {
|
||||
targetStage, err := targetStage(stages, opts.Target)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error finding target stage")
|
||||
}
|
||||
var kanikoStages []config.KanikoStage
|
||||
for index, stage := range stages {
|
||||
resolvedBaseName, err := util.ResolveEnvironmentReplacement(stage.BaseName, opts.BuildArgs, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resolving base name")
|
||||
}
|
||||
stage.Name = resolvedBaseName
|
||||
logrus.Infof("Resolved base name %s to %s", stage.BaseName, stage.Name)
|
||||
kanikoStages = append(kanikoStages, config.KanikoStage{
|
||||
Stage: stage,
|
||||
BaseImageIndex: baseImageIndex(index, stages),
|
||||
BaseImageStoredLocally: (baseImageIndex(index, stages) != -1),
|
||||
SaveStage: saveStage(index, stages),
|
||||
Final: index == targetStage,
|
||||
MetaArgs: metaArgs,
|
||||
Index: index,
|
||||
})
|
||||
if index == targetStage {
|
||||
break
|
||||
}
|
||||
}
|
||||
return kanikoStages, nil
|
||||
}
|
||||
|
||||
// baseImageIndex returns the index of the stage the current stage is built off
|
||||
// returns -1 if the current stage isn't built off a previous stage
|
||||
func baseImageIndex(currentStage int, stages []instructions.Stage) int {
|
||||
|
|
@ -221,7 +290,6 @@ func resolveStages(stages []instructions.Stage) {
|
|||
if val, ok := nameToIndex[strings.ToLower(c.From)]; ok {
|
||||
c.From = val
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -264,3 +332,18 @@ func saveStage(index int, stages []instructions.Stage) bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO move it to private method or put elsewhere
|
||||
func ResolveCommands(cmds []instructions.Command, stageNameToIdx map[string]string) () {
|
||||
for _, cmd := range cmds {
|
||||
switch c := cmd.(type) {
|
||||
case *instructions.CopyCommand:
|
||||
if c.From != "" {
|
||||
if val, ok := stageNameToIdx[strings.ToLower(c.From)]; ok {
|
||||
c.From = val
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/GoogleContainerTools/kaniko/pkg/config"
|
||||
"github.com/GoogleContainerTools/kaniko/testutil"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/instructions"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func Test_Stages_ArgValueWithQuotes(t *testing.T) {
|
||||
|
|
@ -364,3 +365,30 @@ func Test_baseImageIndex(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func Test_ResolveStages(t *testing.T) {
|
||||
in := &instructions.CopyCommand{
|
||||
SourcesAndDest: []string{
|
||||
"/var/bo", "foo.txt",
|
||||
},
|
||||
From: "boo",
|
||||
Chown: "",
|
||||
}
|
||||
ibn := &instructions.CopyCommand{
|
||||
SourcesAndDest: []string{
|
||||
"/var/bo", "foo.txt",
|
||||
},
|
||||
From: "poo",
|
||||
Chown: "",
|
||||
}
|
||||
|
||||
foo := []instructions.Command{in, ibn}
|
||||
stageMap := map[string]string{"boo": "1"}
|
||||
logrus.Infof("%#v", foo)
|
||||
ResolveCommands(foo, stageMap)
|
||||
logrus.Infof("%#v", foo)
|
||||
logrus.Infof("%#v", foo[0])
|
||||
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ type stageBuilder struct {
|
|||
}
|
||||
|
||||
// newStageBuilder returns a new type stageBuilder which contains all the information required to build the stage
|
||||
func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, crossStageDeps map[int][]string, dcm map[string]string, sid map[string]string) (*stageBuilder, error) {
|
||||
func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, crossStageDeps map[int][]string, dcm map[string]string, sid map[string]string, stageNameToIdx map[string]string) (*stageBuilder, error) {
|
||||
sourceImage, err := util.RetrieveSourceImage(stage, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -89,7 +89,7 @@ func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, cross
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := resolveOnBuild(&stage, &imageConfig.Config); err != nil {
|
||||
if err := resolveOnBuild(&stage, &imageConfig.Config, stageNameToIdx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -550,8 +550,25 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
|
|||
digestToCacheKey := make(map[string]string)
|
||||
stageIdxToDigest := make(map[string]string)
|
||||
|
||||
//* dani plan
|
||||
// 1. parse opts - to []instruction.Stages
|
||||
// 2. resolve environment - get map stageidx-->name
|
||||
// 3. convert []instruction.Stages to []config.KanikoStages
|
||||
// 4. pass to newStageBuilder() the map to resolve on build
|
||||
//*/
|
||||
|
||||
// Parse dockerfile
|
||||
stages, err := dockerfile.Stages(opts)
|
||||
//stages, err := dockerfile.Stages(opts)
|
||||
//if err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
instrct, metaArgs, err := dockerfile.ParseInstructions(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stageNameToIdx := dockerfile.ResolveCrossStageInstructions(instrct)
|
||||
|
||||
stages, err := dockerfile.MakeKanikoStages(opts, instrct, metaArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -571,7 +588,7 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
|
|||
logrus.Infof("Built cross stage deps: %v", crossStageDependencies)
|
||||
|
||||
for index, stage := range stages {
|
||||
sb, err := newStageBuilder(opts, stage, crossStageDependencies, digestToCacheKey, stageIdxToDigest)
|
||||
sb, err := newStageBuilder(opts, stage, crossStageDependencies, digestToCacheKey, stageIdxToDigest, stageNameToIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -771,7 +788,7 @@ func getHasher(snapshotMode string) (func(string) (string, error), error) {
|
|||
return nil, fmt.Errorf("%s is not a valid snapshot mode", snapshotMode)
|
||||
}
|
||||
|
||||
func resolveOnBuild(stage *config.KanikoStage, config *v1.Config) error {
|
||||
func resolveOnBuild(stage *config.KanikoStage, config *v1.Config, stageNameToIdx map[string]string) error {
|
||||
if config.OnBuild == nil || len(config.OnBuild) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -780,6 +797,10 @@ func resolveOnBuild(stage *config.KanikoStage, config *v1.Config) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Iterate over commands and replace references to other stages with their index
|
||||
dockerfile.ResolveCommands(cmds, stageNameToIdx)
|
||||
|
||||
// Append to the beginning of the commands in the stage
|
||||
stage.Commands = append(cmds, stage.Commands...)
|
||||
logrus.Infof("Executing %v build triggers", len(cmds))
|
||||
|
|
|
|||
Loading…
Reference in New Issue