func (o *OpenShiftLogsOptions) runLogsForDeployment(dc *deployapi.DeploymentConfig) error { opts := deployapi.DeploymentLogOptions{ Follow: o.KubeLogOptions.Follow, NoWait: false, } readCloser, err := o.OriginClient.DeploymentLogs(dc.Namespace).Get(dc.Name, opts).Stream() if err != nil { return err } defer readCloser.Close() written, err := io.Copy(o.KubeLogOptions.Out, readCloser) if err != nil { return err } // If nothing is written, it means there are no logs returned. Normally // in two cases we will get no logs: either if we don't want to wait // for the deployer pod to be created (NoWait = true) or if the deployer // pod has been deleted (successful deployment). // // Note that in case of manual pod deletion or deployment pruning, this may // be inaccurate. if written == 0 && !opts.NoWait { if opts.Version == nil { fmt.Fprintln(o.KubeLogOptions.Out, "Latest deployment successfully made active, no logs to show.") return nil } fmt.Fprintf(o.KubeLogOptions.Out, "No logs exist for deployment %s.\n", deployutil.DeploymentNameForConfigVersion(dc.Name, *opts.Version)) } return nil }
// Create generates a new DeploymentConfig representing a rollback. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { namespace, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kerrors.NewBadRequest("namespace parameter required.") } rollback, ok := obj.(*deployapi.DeploymentConfigRollback) if !ok { return nil, kerrors.NewBadRequest(fmt.Sprintf("not a rollback spec: %#v", obj)) } if errs := validation.ValidateDeploymentConfigRollback(rollback); len(errs) > 0 { return nil, kerrors.NewInvalid(deployapi.Kind("DeploymentConfigRollback"), rollback.Name, errs) } from, err := r.dn.DeploymentConfigs(namespace).Get(rollback.Name) if err != nil { return nil, newInvalidError(rollback, fmt.Sprintf("cannot get deployment config %q: %v", rollback.Name, err)) } switch from.Status.LatestVersion { case 0: return nil, newInvalidError(rollback, "cannot rollback an undeployed config") case 1: return nil, newInvalidError(rollback, fmt.Sprintf("no previous deployment exists for %q", deployutil.LabelForDeploymentConfig(from))) } revision := from.Status.LatestVersion - 1 if rollback.Spec.Revision > 0 { revision = rollback.Spec.Revision } // Find the target deployment and decode its config. name := deployutil.DeploymentNameForConfigVersion(from.Name, revision) targetDeployment, err := r.rn.ReplicationControllers(namespace).Get(name) if err != nil { return nil, newInvalidError(rollback, err.Error()) } to, err := deployutil.DecodeDeploymentConfig(targetDeployment, r.codec) if err != nil { return nil, newInvalidError(rollback, fmt.Sprintf("couldn't decode deployment config from deployment: %v", err)) } if from.Annotations == nil && len(rollback.UpdatedAnnotations) > 0 { from.Annotations = make(map[string]string) } for key, value := range rollback.UpdatedAnnotations { from.Annotations[key] = value } return r.generator.GenerateRollback(from, to, &rollback.Spec) }
return false, nil } return dc.Status.LatestVersion == 2, nil }) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("by checking that the second deployment exists")) err = wait.PollImmediate(500*time.Millisecond, 30*time.Second, func() (bool, error) { _, rcs, _, err := deploymentInfo(oc, name) if err != nil { return false, nil } secondDeploymentExists := false for _, rc := range rcs { if rc.Name == deployutil.DeploymentNameForConfigVersion(name, 2) { secondDeploymentExists = true break } } return secondDeploymentExists, nil }) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("by checking that the first deployer was deleted and the second deployer exists")) err = wait.PollImmediate(500*time.Millisecond, 10*time.Second, func() (bool, error) { _, _, pods, err := deploymentInfo(oc, name) if err != nil { return false, nil }
// Get returns a streamer resource with the contents of the deployment log func (r *REST) Get(ctx kapi.Context, name string, opts runtime.Object) (runtime.Object, error) { // Ensure we have a namespace in the context namespace, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, errors.NewBadRequest("namespace parameter required.") } // Validate DeploymentLogOptions deployLogOpts, ok := opts.(*deployapi.DeploymentLogOptions) if !ok { return nil, errors.NewBadRequest("did not get an expected options.") } if errs := validation.ValidateDeploymentLogOptions(deployLogOpts); len(errs) > 0 { return nil, errors.NewInvalid(deployapi.Kind("DeploymentLogOptions"), "", errs) } // Fetch deploymentConfig and check latest version; if 0, there are no deployments // for this config config, err := r.dn.DeploymentConfigs(namespace).Get(name) if err != nil { return nil, errors.NewNotFound(deployapi.Resource("deploymentconfig"), name) } desiredVersion := config.Status.LatestVersion if desiredVersion == 0 { return nil, errors.NewBadRequest(fmt.Sprintf("no deployment exists for deploymentConfig %q", config.Name)) } // Support retrieving logs for older deployments switch { case deployLogOpts.Version == nil: // Latest or previous if deployLogOpts.Previous { desiredVersion-- if desiredVersion < 1 { return nil, errors.NewBadRequest(fmt.Sprintf("no previous deployment exists for deploymentConfig %q", config.Name)) } } case *deployLogOpts.Version <= 0 || *deployLogOpts.Version > config.Status.LatestVersion: // Invalid version return nil, errors.NewBadRequest(fmt.Sprintf("invalid version for deploymentConfig %q: %d", config.Name, *deployLogOpts.Version)) default: desiredVersion = *deployLogOpts.Version } // Get desired deployment targetName := deployutil.DeploymentNameForConfigVersion(config.Name, desiredVersion) target, err := r.waitForExistingDeployment(namespace, targetName) if err != nil { return nil, err } podName := deployutil.DeployerPodNameForDeployment(target.Name) // Check for deployment status; if it is new or pending, we will wait for it. If it is complete, // the deployment completed successfully and the deployer pod will be deleted so we will return a // success message. If it is running or failed, retrieve the log from the deployer pod. status := deployutil.DeploymentStatusFor(target) switch status { case deployapi.DeploymentStatusNew, deployapi.DeploymentStatusPending: if deployLogOpts.NoWait { glog.V(4).Infof("Deployment %s is in %s state. No logs to retrieve yet.", deployutil.LabelForDeployment(target), status) return &genericrest.LocationStreamer{}, nil } glog.V(4).Infof("Deployment %s is in %s state, waiting for it to start...", deployutil.LabelForDeployment(target), status) if err := deployutil.WaitForRunningDeployerPod(r.pn, target, r.timeout); err != nil { return nil, errors.NewBadRequest(fmt.Sprintf("failed to run deployer pod %s: %v", podName, err)) } latest, ok, err := registry.WaitForRunningDeployment(r.rn, target, r.timeout) if err != nil { return nil, errors.NewBadRequest(fmt.Sprintf("unable to wait for deployment %s to run: %v", deployutil.LabelForDeployment(target), err)) } if !ok { return nil, errors.NewServerTimeout(kapi.Resource("ReplicationController"), "get", 2) } if deployutil.DeploymentStatusFor(latest) == deployapi.DeploymentStatusComplete { podName, err = r.returnApplicationPodName(target) if err != nil { return nil, err } } case deployapi.DeploymentStatusComplete: podName, err = r.returnApplicationPodName(target) if err != nil { return nil, err } } logOpts := deployapi.DeploymentToPodLogOptions(deployLogOpts) location, transport, err := pod.LogLocation(&podGetter{r.pn}, r.connInfo, ctx, podName, logOpts) if err != nil { return nil, errors.NewBadRequest(err.Error()) } return &genericrest.LocationStreamer{ Location: location, Transport: transport, ContentType: "text/plain", Flush: deployLogOpts.Follow, ResponseChecker: genericrest.NewGenericHttpResponseChecker(kapi.Resource("pod"), podName), }, nil }
// Get returns a streamer resource with the contents of the deployment log func (r *REST) Get(ctx kapi.Context, name string, opts runtime.Object) (runtime.Object, error) { // Ensure we have a namespace in the context namespace, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, errors.NewBadRequest("namespace parameter required.") } // Validate DeploymentLogOptions deployLogOpts, ok := opts.(*deployapi.DeploymentLogOptions) if !ok { return nil, errors.NewBadRequest("did not get an expected options.") } if errs := validation.ValidateDeploymentLogOptions(deployLogOpts); len(errs) > 0 { return nil, errors.NewInvalid("deploymentLogOptions", "", errs) } // Fetch deploymentConfig and check latest version; if 0, there are no deployments // for this config config, err := r.ConfigGetter.DeploymentConfigs(namespace).Get(name) if err != nil { return nil, errors.NewNotFound("deploymentConfig", name) } desiredVersion := config.Status.LatestVersion if desiredVersion == 0 { return nil, errors.NewBadRequest(fmt.Sprintf("no deployment exists for deploymentConfig %q", config.Name)) } // Support retrieving logs for older deployments switch { case deployLogOpts.Version == nil: // Latest case *deployLogOpts.Version <= 0 || int(*deployLogOpts.Version) > config.Status.LatestVersion: // Invalid version return nil, errors.NewBadRequest(fmt.Sprintf("invalid version for deploymentConfig %q: %d", config.Name, *deployLogOpts.Version)) default: desiredVersion = int(*deployLogOpts.Version) } // Get desired deployment targetName := deployutil.DeploymentNameForConfigVersion(config.Name, desiredVersion) target, err := r.DeploymentGetter.ReplicationControllers(namespace).Get(targetName) if err != nil { return nil, err } // Check for deployment status; if it is new or pending, we will wait for it. If it is complete, // the deployment completed successfully and the deployer pod will be deleted so we will return a // success message. If it is running or failed, retrieve the log from the deployer pod. status := deployutil.DeploymentStatusFor(target) switch status { case deployapi.DeploymentStatusNew, deployapi.DeploymentStatusPending: if deployLogOpts.NoWait { glog.V(4).Infof("Deployment %s is in %s state. No logs to retrieve yet.", deployutil.LabelForDeployment(target), status) return &genericrest.LocationStreamer{}, nil } glog.V(4).Infof("Deployment %s is in %s state, waiting for it to start...", deployutil.LabelForDeployment(target), status) latest, ok, err := registry.WaitForRunningDeployment(r.DeploymentGetter, target, r.Timeout) if err != nil { return nil, errors.NewBadRequest(fmt.Sprintf("unable to wait for deployment %s to run: %v", deployutil.LabelForDeployment(target), err)) } if !ok { return nil, errors.NewTimeoutError(fmt.Sprintf("timed out waiting for deployment %s to start after %s", deployutil.LabelForDeployment(target), r.Timeout), 1) } if deployutil.DeploymentStatusFor(latest) == deployapi.DeploymentStatusComplete { // Deployer pod has been deleted, no logs to retrieve glog.V(4).Infof("Deployment %s was successful so the deployer pod is deleted. No logs to retrieve.", deployutil.LabelForDeployment(target)) return &genericrest.LocationStreamer{}, nil } case deployapi.DeploymentStatusComplete: // Deployer pod has been deleted, no logs to retrieve glog.V(4).Infof("Deployment %s was successful so the deployer pod is deleted. No logs to retrieve.", deployutil.LabelForDeployment(target)) return &genericrest.LocationStreamer{}, nil } // Setup url of the deployer pod deployPodName := deployutil.DeployerPodNameForDeployment(target.Name) logOpts := deployapi.DeploymentToPodLogOptions(deployLogOpts) location, transport, err := pod.LogLocation(r.PodGetter, r.ConnectionInfo, ctx, deployPodName, logOpts) if err != nil { return nil, errors.NewBadRequest(err.Error()) } return &genericrest.LocationStreamer{ Location: location, Transport: transport, ContentType: "text/plain", Flush: deployLogOpts.Follow, ResponseChecker: genericrest.NewGenericHttpResponseChecker("Pod", deployPodName), }, nil }