Example #1
0
// Run contains all the necessary functionality for the OpenShift cli start-build command
func (o *StartBuildOptions) Run() error {
	if len(o.FromWebhook) > 0 {
		return o.RunStartBuildWebHook()
	}
	if len(o.ListWebhooks) > 0 {
		return o.RunListBuildWebHooks()
	}
	buildRequestCauses := []buildapi.BuildTriggerCause{}
	request := &buildapi.BuildRequest{
		TriggeredBy: append(buildRequestCauses,
			buildapi.BuildTriggerCause{
				Message: "Manually triggered",
			},
		),
		ObjectMeta: kapi.ObjectMeta{Name: o.Name},
	}
	if len(o.EnvVar) > 0 {
		request.Env = o.EnvVar
	}
	if len(o.Commit) > 0 {
		request.Revision = &buildapi.SourceRevision{
			Git: &buildapi.GitSourceRevision{
				Commit: o.Commit,
			},
		}
	}

	var err error
	var newBuild *buildapi.Build
	switch {
	case o.AsBinary:
		request := &buildapi.BinaryBuildRequestOptions{
			ObjectMeta: kapi.ObjectMeta{
				Name:      o.Name,
				Namespace: o.Namespace,
			},
			Commit: o.Commit,
		}
		if len(o.EnvVar) > 0 {
			fmt.Fprintf(o.ErrOut, "WARNING: Specifying environment variables with binary builds is not supported.\n")
		}
		if newBuild, err = streamPathToBuild(o.Git, o.In, o.ErrOut, o.Client.BuildConfigs(o.Namespace), o.FromDir, o.FromFile, o.FromRepo, request); err != nil {
			return err
		}
	case len(o.FromBuild) > 0:
		if newBuild, err = o.Client.Builds(o.Namespace).Clone(request); err != nil {
			if isInvalidSourceInputsError(err) {
				return fmt.Errorf("Build %s/%s has no valid source inputs and '--from-build' cannot be used for binary builds", o.Namespace, o.Name)
			}
			return err
		}
	default:
		if newBuild, err = o.Client.BuildConfigs(o.Namespace).Instantiate(request); err != nil {
			if isInvalidSourceInputsError(err) {
				return fmt.Errorf("Build configuration %s/%s has no valid source inputs, if this is a binary build you must specify one of '--from-dir', '--from-repo', or '--from-file'", o.Namespace, o.Name)
			}
			return err
		}
	}

	// TODO: support -o on this command
	fmt.Fprintln(o.Out, newBuild.Name)

	var (
		wg      sync.WaitGroup
		exitErr error
	)

	// Wait for the build to complete
	if o.WaitForComplete {
		wg.Add(1)
		go func() {
			defer wg.Done()
			exitErr = WaitForBuildComplete(o.Client.Builds(o.Namespace), newBuild.Name)
		}()
	}

	// Stream the logs from the build
	if o.Follow {
		wg.Add(1)
		go func() {
			// if --wait option is set, then don't wait for logs to finish streaming
			// but wait for the build to reach its final state
			if o.WaitForComplete {
				wg.Done()
			} else {
				defer wg.Done()
			}
			opts := buildapi.BuildLogOptions{
				Follow: true,
				NoWait: false,
			}
			for {
				rd, err := o.Client.BuildLogs(o.Namespace).Get(newBuild.Name, opts).Stream()
				if err != nil {
					// if --wait options is set, then retry the connection to build logs
					// when we hit the timeout.
					if o.WaitForComplete && oerrors.IsTimeoutErr(err) {
						continue
					}
					fmt.Fprintf(o.ErrOut, "error getting logs: %v\n", err)
					return
				}
				defer rd.Close()
				if _, err = io.Copy(o.Out, rd); err != nil {
					fmt.Fprintf(o.ErrOut, "error streaming logs: %v\n", err)
				}
				break
			}
		}()
	}

	wg.Wait()

	return exitErr
}
Example #2
0
// Run contains all the necessary functionality for the OpenShift cli start-build command
func (o *StartBuildOptions) Run() error {
	if len(o.FromWebhook) > 0 {
		return o.RunStartBuildWebHook()
	}
	if len(o.ListWebhooks) > 0 {
		return o.RunListBuildWebHooks()
	}

	buildRequestCauses := []buildapi.BuildTriggerCause{}
	request := &buildapi.BuildRequest{
		TriggeredBy: append(buildRequestCauses,
			buildapi.BuildTriggerCause{
				Message: "Manually triggered",
			},
		),
		ObjectMeta: kapi.ObjectMeta{Name: o.Name},
	}
	if len(o.EnvVar) > 0 {
		request.Env = o.EnvVar
	}
	if len(o.Commit) > 0 {
		request.Revision = &buildapi.SourceRevision{
			Git: &buildapi.GitSourceRevision{
				Commit: o.Commit,
			},
		}
	}

	var err error
	var newBuild *buildapi.Build
	switch {
	case o.AsBinary:
		request := &buildapi.BinaryBuildRequestOptions{
			ObjectMeta: kapi.ObjectMeta{
				Name:      o.Name,
				Namespace: o.Namespace,
			},
			Commit: o.Commit,
		}
		if len(o.EnvVar) > 0 {
			fmt.Fprintf(o.ErrOut, "WARNING: Specifying environment variables with binary builds is not supported.\n")
		}
		if newBuild, err = streamPathToBuild(o.Git, o.In, o.ErrOut, o.Client.BuildConfigs(o.Namespace), o.FromDir, o.FromFile, o.FromRepo, request); err != nil {
			return err
		}
	case len(o.FromBuild) > 0:
		if newBuild, err = o.Client.Builds(o.Namespace).Clone(request); err != nil {
			if isInvalidSourceInputsError(err) {
				return fmt.Errorf("Build %s/%s has no valid source inputs and '--from-build' cannot be used for binary builds", o.Namespace, o.Name)
			}
			return err
		}
	default:
		if newBuild, err = o.Client.BuildConfigs(o.Namespace).Instantiate(request); err != nil {
			if isInvalidSourceInputsError(err) {
				return fmt.Errorf("Build configuration %s/%s has no valid source inputs, if this is a binary build you must specify one of '--from-dir', '--from-repo', or '--from-file'", o.Namespace, o.Name)
			}
			return err
		}
	}

	kcmdutil.PrintSuccess(o.Mapper, o.ShortOutput, o.Out, "build", newBuild.Name, "started")

	// Stream the logs from the build
	if o.Follow {
		opts := buildapi.BuildLogOptions{
			Follow: true,
			NoWait: false,
		}
		for {
			rd, err := o.Client.BuildLogs(o.Namespace).Get(newBuild.Name, opts).Stream()
			if err != nil {
				// retry the connection to build logs when we hit the timeout.
				if oerrors.IsTimeoutErr(err) {
					fmt.Fprintf(o.ErrOut, "timed out getting logs, retrying\n")
					continue
				}
				fmt.Fprintf(o.ErrOut, "error getting logs (%v), waiting for build to complete\n", err)
				break
			}
			defer rd.Close()
			if _, err = io.Copy(o.Out, rd); err != nil {
				fmt.Fprintf(o.ErrOut, "error streaming logs (%v), waiting for build to complete\n", err)
			}
			break
		}
	}

	if o.Follow || o.WaitForComplete {
		return WaitForBuildComplete(o.Client.Builds(o.Namespace), newBuild.Name)
	}

	return nil
}
Example #3
0
// RunStartBuild contains all the necessary functionality for the OpenShift cli start-build command
func RunStartBuild(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Command, envParams []string, args []string, webhooks util.StringFlag) error {
	webhook := kcmdutil.GetFlagString(cmd, "from-webhook")
	buildName := kcmdutil.GetFlagString(cmd, "from-build")
	follow := kcmdutil.GetFlagBool(cmd, "follow")
	commit := kcmdutil.GetFlagString(cmd, "commit")
	waitForComplete := kcmdutil.GetFlagBool(cmd, "wait")
	fromFile := kcmdutil.GetFlagString(cmd, "from-file")
	fromDir := kcmdutil.GetFlagString(cmd, "from-dir")
	fromRepo := kcmdutil.GetFlagString(cmd, "from-repo")
	buildLogLevel := kcmdutil.GetFlagString(cmd, "build-loglevel")

	switch {
	case len(webhook) > 0:
		if len(args) > 0 || len(buildName) > 0 || len(fromFile) > 0 || len(fromDir) > 0 || len(fromRepo) > 0 {
			return kcmdutil.UsageError(cmd, "The '--from-webhook' flag is incompatible with arguments and all '--from-*' flags")
		}
		path := kcmdutil.GetFlagString(cmd, "git-repository")
		postReceivePath := kcmdutil.GetFlagString(cmd, "git-post-receive")
		repo := git.NewRepository()
		return RunStartBuildWebHook(f, out, webhook, path, postReceivePath, repo)
	case len(args) != 1 && len(buildName) == 0:
		return kcmdutil.UsageError(cmd, "Must pass a name of a build config or specify build name with '--from-build' flag")
	}

	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	var (
		name     = buildName
		resource = "builds"
	)

	if len(name) == 0 && len(args) > 0 && len(args[0]) > 0 {
		mapper, _ := f.Object()
		resource, name, err = cmdutil.ResolveResource("buildconfigs", args[0], mapper)
		if err != nil {
			return err
		}
		switch resource {
		case "buildconfigs":
			// no special handling required
		case "builds":
			return fmt.Errorf("use --from-build to rerun your builds")
		default:
			return fmt.Errorf("invalid resource provided: %s", resource)
		}
	}
	if len(name) == 0 {
		return fmt.Errorf("a resource name is required either as an argument or by using --from-build")
	}

	if webhooks.Provided() {
		return RunListBuildWebHooks(f, out, cmd.Out(), name, resource, webhooks.String())
	}

	client, _, err := f.Clients()
	if err != nil {
		return err
	}

	env, _, err := cmdutil.ParseEnv(envParams, in)
	if err != nil {
		return err
	}

	if len(buildLogLevel) > 0 {
		env = append(env, kapi.EnvVar{Name: "BUILD_LOGLEVEL", Value: buildLogLevel})
	}

	request := &buildapi.BuildRequest{
		ObjectMeta: kapi.ObjectMeta{Name: name},
	}
	if len(env) > 0 {
		request.Env = env
	}
	if len(commit) > 0 {
		request.Revision = &buildapi.SourceRevision{
			Git: &buildapi.GitSourceRevision{
				Commit: commit,
			},
		}
	}

	git := git.NewRepository()

	var newBuild *buildapi.Build
	switch {
	case len(args) > 0 && (len(fromFile) > 0 || len(fromDir) > 0 || len(fromRepo) > 0):
		request := &buildapi.BinaryBuildRequestOptions{
			ObjectMeta: kapi.ObjectMeta{
				Name:      name,
				Namespace: namespace,
			},
			Commit: commit,
		}
		if len(env) > 0 {
			fmt.Fprintf(cmd.Out(), "WARNING: Specifying environment variables with binary builds is not supported.\n")
		}
		if newBuild, err = streamPathToBuild(git, in, cmd.Out(), client.BuildConfigs(namespace), fromDir, fromFile, fromRepo, request); err != nil {
			return err
		}
	case resource == "builds":
		if newBuild, err = client.Builds(namespace).Clone(request); err != nil {
			return err
		}
	case resource == "buildconfigs":
		if newBuild, err = client.BuildConfigs(namespace).Instantiate(request); err != nil {
			return err
		}
	default:
		return fmt.Errorf("invalid resource provided: %s", resource)
	}

	fmt.Fprintln(out, newBuild.Name)
	// mapper, typer := f.Object()
	// resourceMapper := &resource.Mapper{ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand()}
	// info, err := resourceMapper.InfoForObject(newBuild)
	// if err != nil {
	// 	return err
	// }
	// shortOutput := kcmdutil.GetFlagString(cmd, "output") == "name"
	// kcmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "started")

	var (
		wg      sync.WaitGroup
		exitErr error
	)

	// Wait for the build to complete
	if waitForComplete {
		wg.Add(1)
		go func() {
			defer wg.Done()
			exitErr = WaitForBuildComplete(client.Builds(namespace), newBuild.Name)
		}()
	}

	// Stream the logs from the build
	if follow {
		wg.Add(1)
		go func() {
			// if --wait option is set, then don't wait for logs to finish streaming
			// but wait for the build to reach its final state
			if waitForComplete {
				wg.Done()
			} else {
				defer wg.Done()
			}
			opts := buildapi.BuildLogOptions{
				Follow: true,
				NoWait: false,
			}
			for {
				rd, err := client.BuildLogs(namespace).Get(newBuild.Name, opts).Stream()
				if err != nil {
					// if --wait options is set, then retry the connection to build logs
					// when we hit the timeout.
					if waitForComplete && errors.IsTimeoutErr(err) {
						continue
					}
					fmt.Fprintf(cmd.Out(), "error getting logs: %v\n", err)
					return
				}
				defer rd.Close()
				if _, err = io.Copy(out, rd); err != nil {
					fmt.Fprintf(cmd.Out(), "error streaming logs: %v\n", err)
				}
				break
			}
		}()
	}

	wg.Wait()

	return exitErr
}