pkg/common/api/api_converter.go (1,268 lines of code) (raw):
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"reflect"
mesosv1 "github.com/uber/peloton/.gen/mesos/v1"
"github.com/uber/peloton/.gen/peloton/api/v0/job"
"github.com/uber/peloton/.gen/peloton/api/v0/peloton"
pelotonv0query "github.com/uber/peloton/.gen/peloton/api/v0/query"
pelotonv0respool "github.com/uber/peloton/.gen/peloton/api/v0/respool"
"github.com/uber/peloton/.gen/peloton/api/v0/task"
"github.com/uber/peloton/.gen/peloton/api/v0/update"
"github.com/uber/peloton/.gen/peloton/api/v1alpha/job/stateless"
v1alphapeloton "github.com/uber/peloton/.gen/peloton/api/v1alpha/peloton"
"github.com/uber/peloton/.gen/peloton/api/v1alpha/pod"
"github.com/uber/peloton/.gen/peloton/api/v1alpha/pod/apachemesos"
"github.com/uber/peloton/.gen/peloton/api/v1alpha/query"
"github.com/uber/peloton/.gen/peloton/api/v1alpha/volume"
"github.com/uber/peloton/.gen/peloton/private/models"
"github.com/uber/peloton/pkg/common/util"
versionutil "github.com/uber/peloton/pkg/common/util/entityversion"
"go.uber.org/yarpc/yarpcerrors"
)
const (
cpuNameMesos = "cpus"
memNameMesos = "mem"
)
// ConvertTaskStateToPodState converts v0 task.TaskState to v1alpha pod.PodState
func ConvertTaskStateToPodState(state task.TaskState) pod.PodState {
switch state {
case task.TaskState_UNKNOWN:
return pod.PodState_POD_STATE_INVALID
case task.TaskState_INITIALIZED:
return pod.PodState_POD_STATE_INITIALIZED
case task.TaskState_PENDING:
return pod.PodState_POD_STATE_PENDING
case task.TaskState_READY:
return pod.PodState_POD_STATE_READY
case task.TaskState_PLACING:
return pod.PodState_POD_STATE_PLACING
case task.TaskState_PLACED:
return pod.PodState_POD_STATE_PLACED
case task.TaskState_LAUNCHING:
return pod.PodState_POD_STATE_LAUNCHING
case task.TaskState_LAUNCHED:
return pod.PodState_POD_STATE_LAUNCHED
case task.TaskState_STARTING:
return pod.PodState_POD_STATE_STARTING
case task.TaskState_RUNNING:
return pod.PodState_POD_STATE_RUNNING
case task.TaskState_SUCCEEDED:
return pod.PodState_POD_STATE_SUCCEEDED
case task.TaskState_FAILED:
return pod.PodState_POD_STATE_FAILED
case task.TaskState_LOST:
return pod.PodState_POD_STATE_LOST
case task.TaskState_PREEMPTING:
return pod.PodState_POD_STATE_PREEMPTING
case task.TaskState_KILLING:
return pod.PodState_POD_STATE_KILLING
case task.TaskState_KILLED:
return pod.PodState_POD_STATE_KILLED
case task.TaskState_DELETED:
return pod.PodState_POD_STATE_DELETED
case task.TaskState_RESERVED:
return pod.PodState_POD_STATE_RESERVED
}
return pod.PodState_POD_STATE_INVALID
}
// ConvertPodStateToTaskState converts v0 task.TaskState to v1alpha pod.PodState
func ConvertPodStateToTaskState(state pod.PodState) task.TaskState {
switch state {
case pod.PodState_POD_STATE_INVALID:
return task.TaskState_UNKNOWN
case pod.PodState_POD_STATE_INITIALIZED:
return task.TaskState_INITIALIZED
case pod.PodState_POD_STATE_PENDING:
return task.TaskState_PENDING
case pod.PodState_POD_STATE_READY:
return task.TaskState_READY
case pod.PodState_POD_STATE_PLACING:
return task.TaskState_PLACING
case pod.PodState_POD_STATE_PLACED:
return task.TaskState_PLACED
case pod.PodState_POD_STATE_LAUNCHING:
return task.TaskState_LAUNCHING
case pod.PodState_POD_STATE_LAUNCHED:
return task.TaskState_LAUNCHED
case pod.PodState_POD_STATE_STARTING:
return task.TaskState_STARTING
case pod.PodState_POD_STATE_RUNNING:
return task.TaskState_RUNNING
case pod.PodState_POD_STATE_SUCCEEDED:
return task.TaskState_SUCCEEDED
case pod.PodState_POD_STATE_FAILED:
return task.TaskState_FAILED
case pod.PodState_POD_STATE_LOST:
return task.TaskState_LOST
case pod.PodState_POD_STATE_PREEMPTING:
return task.TaskState_PREEMPTING
case pod.PodState_POD_STATE_KILLING:
return task.TaskState_KILLING
case pod.PodState_POD_STATE_KILLED:
return task.TaskState_KILLED
case pod.PodState_POD_STATE_DELETED:
return task.TaskState_DELETED
case pod.PodState_POD_STATE_RESERVED:
return task.TaskState_RESERVED
}
return task.TaskState_UNKNOWN
}
// ConvertV1InstanceRangeToV0InstanceRange converts from array of
// v1 pod.InstanceIDRange to array of v0 task.InstanceRange
func ConvertV1InstanceRangeToV0InstanceRange(
instanceRange []*pod.InstanceIDRange) []*task.InstanceRange {
var resp []*task.InstanceRange
for _, inst := range instanceRange {
r := &task.InstanceRange{
From: inst.GetFrom(),
To: inst.GetTo(),
}
resp = append(resp, r)
}
return resp
}
// ConvertTaskRuntimeToPodStatus converts
// v0 task.RuntimeInfo to v1alpha pod.PodStatus
func ConvertTaskRuntimeToPodStatus(runtime *task.RuntimeInfo) *pod.PodStatus {
return &pod.PodStatus{
State: ConvertTaskStateToPodState(runtime.GetState()),
PodId: &v1alphapeloton.PodID{Value: runtime.GetMesosTaskId().GetValue()},
StartTime: runtime.GetStartTime(),
CompletionTime: runtime.GetCompletionTime(),
Host: runtime.GetHost(),
ContainersStatus: []*pod.ContainerStatus{
{
Ports: runtime.GetPorts(),
Healthy: &pod.HealthStatus{
State: pod.HealthState(runtime.GetHealthy()),
},
StartTime: runtime.GetStartTime(),
CompletionTime: runtime.GetCompletionTime(),
Message: runtime.GetMessage(),
Reason: runtime.GetReason(),
TerminationStatus: convertTaskTerminationStatusToPodTerminationStatus(
runtime.TerminationStatus),
},
},
DesiredState: ConvertTaskStateToPodState(runtime.GetGoalState()),
Message: runtime.GetMessage(),
Reason: runtime.GetReason(),
FailureCount: runtime.GetFailureCount(),
VolumeId: &v1alphapeloton.VolumeID{Value: runtime.GetVolumeID().GetValue()},
Version: versionutil.GetPodEntityVersion(runtime.GetConfigVersion()),
DesiredVersion: versionutil.GetPodEntityVersion(runtime.GetDesiredConfigVersion()),
AgentId: runtime.GetAgentID(),
HostId: runtime.GetAgentID().GetValue(),
Revision: &v1alphapeloton.Revision{
Version: runtime.GetRevision().GetVersion(),
CreatedAt: runtime.GetRevision().GetCreatedAt(),
UpdatedAt: runtime.GetRevision().GetUpdatedAt(),
UpdatedBy: runtime.GetRevision().GetUpdatedBy(),
},
PrevPodId: &v1alphapeloton.PodID{Value: runtime.GetPrevMesosTaskId().GetValue()},
ResourceUsage: runtime.GetResourceUsage(),
DesiredPodId: &v1alphapeloton.PodID{Value: runtime.GetDesiredMesosTaskId().GetValue()},
DesiredHost: runtime.GetDesiredHost(),
}
}
// ConvertTaskConfigToPodSpec converts v0 task.TaskConfig to v1alpha pod.PodSpec
func ConvertTaskConfigToPodSpec(taskConfig *task.TaskConfig, jobID string, instanceID uint32) *pod.PodSpec {
result := &pod.PodSpec{
Controller: taskConfig.GetController(),
KillGracePeriodSeconds: taskConfig.GetKillGracePeriodSeconds(),
Revocable: taskConfig.GetRevocable(),
}
if len(jobID) != 0 {
result.PodName = &v1alphapeloton.PodName{
Value: util.CreatePelotonTaskID(jobID, instanceID),
}
}
if taskConfig.GetConstraint() != nil {
result.Constraint = ConvertTaskConstraintsToPodConstraints([]*task.Constraint{taskConfig.GetConstraint()})[0]
}
if taskConfig.GetVolume() != nil {
result.Volume = &pod.PersistentVolumeSpec{
ContainerPath: taskConfig.GetVolume().GetContainerPath(),
SizeMb: taskConfig.GetVolume().GetSizeMB(),
}
}
if taskConfig.GetLabels() != nil {
result.Labels = ConvertLabels(taskConfig.GetLabels())
}
if taskConfig.GetPreemptionPolicy() != nil {
result.PreemptionPolicy = &pod.PreemptionPolicy{
KillOnPreempt: taskConfig.GetPreemptionPolicy().GetKillOnPreempt(),
}
}
if taskConfig.GetRestartPolicy() != nil {
result.RestartPolicy = &pod.RestartPolicy{
MaxFailures: taskConfig.GetRestartPolicy().GetMaxFailures(),
}
}
container := &pod.ContainerSpec{}
if len(taskConfig.GetName()) != 0 {
container.Name = taskConfig.GetName()
}
if taskConfig.GetResource() != nil {
container.Resource = &pod.ResourceSpec{
CpuLimit: taskConfig.GetResource().GetCpuLimit(),
MemLimitMb: taskConfig.GetResource().GetMemLimitMb(),
DiskLimitMb: taskConfig.GetResource().GetDiskLimitMb(),
FdLimit: taskConfig.GetResource().GetFdLimit(),
GpuLimit: taskConfig.GetResource().GetGpuLimit(),
}
}
if taskConfig.GetContainer() != nil {
container.Container = taskConfig.GetContainer()
ConvertMesosContainerToPodSpec(taskConfig.GetContainer(), result, container)
}
if taskConfig.GetCommand() != nil {
container.Command = taskConfig.GetCommand()
ConvertMesosCommandToPodSpec(taskConfig.GetCommand(), result, container)
}
if taskConfig.GetExecutor() != nil {
container.Executor = taskConfig.GetExecutor()
ConvertMesosExecutorInfoToPodSpec(taskConfig.GetExecutor(), result, container)
}
if taskConfig.GetPorts() != nil {
container.Ports = ConvertPortConfigsToPortSpecs(taskConfig.GetPorts())
}
if taskConfig.GetHealthCheck() != nil {
container.LivenessCheck = &pod.HealthCheckSpec{
Enabled: taskConfig.GetHealthCheck().GetEnabled(),
InitialIntervalSecs: taskConfig.GetHealthCheck().GetInitialIntervalSecs(),
IntervalSecs: taskConfig.GetHealthCheck().GetIntervalSecs(),
MaxConsecutiveFailures: taskConfig.GetHealthCheck().GetMaxConsecutiveFailures(),
TimeoutSecs: taskConfig.GetHealthCheck().GetTimeoutSecs(),
Type: pod.HealthCheckSpec_HealthCheckType(taskConfig.GetHealthCheck().GetType()),
}
if taskConfig.GetHealthCheck().GetCommandCheck() != nil {
container.LivenessCheck.CommandCheck = &pod.HealthCheckSpec_CommandCheck{
Command: taskConfig.GetHealthCheck().GetCommandCheck().GetCommand(),
UnshareEnvironments: taskConfig.GetHealthCheck().GetCommandCheck().GetUnshareEnvironments(),
}
}
if taskConfig.GetHealthCheck().GetHttpCheck() != nil {
container.LivenessCheck.HttpCheck = &pod.HealthCheckSpec_HTTPCheck{
Scheme: taskConfig.GetHealthCheck().GetHttpCheck().GetScheme(),
Port: taskConfig.GetHealthCheck().GetHttpCheck().GetPort(),
Path: taskConfig.GetHealthCheck().GetHttpCheck().GetPath(),
}
}
}
if !reflect.DeepEqual(*container, pod.ContainerSpec{}) {
result.Containers = []*pod.ContainerSpec{container}
}
return result
}
// ConvertLabels converts v0 peloton.Label array to
// v1alpha peloton.Label array
func ConvertLabels(labels []*peloton.Label) []*v1alphapeloton.Label {
var podLabels []*v1alphapeloton.Label
for _, l := range labels {
podLabels = append(podLabels, &v1alphapeloton.Label{
Key: l.GetKey(),
Value: l.GetValue(),
})
}
return podLabels
}
// ConvertTaskConstraintsToPodConstraints converts v0 task.Constraint array to
// v1alpha pod.Constraint array
func ConvertTaskConstraintsToPodConstraints(constraints []*task.Constraint) []*pod.Constraint {
var podConstraints []*pod.Constraint
for _, constraint := range constraints {
podConstraint := &pod.Constraint{
Type: pod.Constraint_Type(constraint.GetType()),
}
if constraint.GetLabelConstraint() != nil {
podConstraint.LabelConstraint = &pod.LabelConstraint{
Kind: pod.LabelConstraint_Kind(
constraint.GetLabelConstraint().GetKind(),
),
Condition: pod.LabelConstraint_Condition(
constraint.GetLabelConstraint().GetCondition(),
),
Requirement: constraint.GetLabelConstraint().GetRequirement(),
}
if constraint.GetLabelConstraint().GetLabel() != nil {
podConstraint.LabelConstraint.Label = &v1alphapeloton.Label{
Key: constraint.GetLabelConstraint().GetLabel().GetKey(),
Value: constraint.GetLabelConstraint().GetLabel().GetValue(),
}
}
}
if constraint.GetAndConstraint() != nil {
podConstraint.AndConstraint = &pod.AndConstraint{
Constraints: ConvertTaskConstraintsToPodConstraints(constraint.GetAndConstraint().GetConstraints()),
}
}
if constraint.GetOrConstraint() != nil {
podConstraint.OrConstraint = &pod.OrConstraint{
Constraints: ConvertTaskConstraintsToPodConstraints(constraint.GetOrConstraint().GetConstraints()),
}
}
podConstraints = append(podConstraints, podConstraint)
}
return podConstraints
}
// ConvertPortConfigsToPortSpecs converts v0 task.PortConfig array to
// v1alpha pod.PortSpec array
func ConvertPortConfigsToPortSpecs(ports []*task.PortConfig) []*pod.PortSpec {
var containerPorts []*pod.PortSpec
for _, p := range ports {
containerPorts = append(
containerPorts,
&pod.PortSpec{
Name: p.GetName(),
Value: p.GetValue(),
EnvName: p.GetEnvName(),
},
)
}
return containerPorts
}
// ConvertV0SecretsToV1Secrets converts v0 peloton.Secret to v1alpha peloton.Secret
func ConvertV0SecretsToV1Secrets(secrets []*peloton.Secret) []*v1alphapeloton.Secret {
var v1secrets []*v1alphapeloton.Secret
for _, secret := range secrets {
v1secret := &v1alphapeloton.Secret{
SecretId: &v1alphapeloton.SecretID{
Value: secret.GetId().GetValue(),
},
Path: secret.GetPath(),
Value: &v1alphapeloton.Secret_Value{
Data: secret.GetValue().GetData(),
},
}
v1secrets = append(v1secrets, v1secret)
}
return v1secrets
}
// ConvertV1SecretsToV0Secrets converts v1alpha peloton.Secret to v0 peloton.Secret
func ConvertV1SecretsToV0Secrets(secrets []*v1alphapeloton.Secret) []*peloton.Secret {
var v0secrets []*peloton.Secret
for _, secret := range secrets {
v0secret := &peloton.Secret{
Id: &peloton.SecretID{
Value: secret.GetSecretId().GetValue(),
},
Path: secret.GetPath(),
Value: &peloton.Secret_Value{
Data: secret.GetValue().GetData(),
},
}
v0secrets = append(v0secrets, v0secret)
}
return v0secrets
}
// ConvertJobConfigToJobSpec converts v0 job.JobConfig to v1alpha stateless.JobSpec
func ConvertJobConfigToJobSpec(config *job.JobConfig) *stateless.JobSpec {
instanceSpec := make(map[uint32]*pod.PodSpec)
for instID, taskConfig := range config.GetInstanceConfig() {
instanceSpec[instID] = ConvertTaskConfigToPodSpec(taskConfig, "", instID)
}
return &stateless.JobSpec{
Revision: &v1alphapeloton.Revision{
Version: config.GetChangeLog().GetVersion(),
CreatedAt: config.GetChangeLog().GetCreatedAt(),
UpdatedAt: config.GetChangeLog().GetUpdatedAt(),
UpdatedBy: config.GetChangeLog().GetUpdatedBy(),
},
Name: config.GetName(),
Owner: config.GetOwner(),
OwningTeam: config.GetOwningTeam(),
LdapGroups: config.GetLdapGroups(),
Description: config.GetDescription(),
Labels: ConvertLabels(config.GetLabels()),
InstanceCount: config.GetInstanceCount(),
Sla: ConvertSLAConfigToSLASpec(config.GetSLA()),
DefaultSpec: ConvertTaskConfigToPodSpec(config.GetDefaultConfig(), "", 0),
InstanceSpec: instanceSpec,
RespoolId: &v1alphapeloton.ResourcePoolID{
Value: config.GetRespoolID().GetValue()},
}
}
// ConvertUpdateModelToWorkflowStatus converts private UpdateModel
// to v1alpha stateless.WorkflowStatus
func ConvertUpdateModelToWorkflowStatus(
runtime *job.RuntimeInfo,
updateInfo *models.UpdateModel,
) *stateless.WorkflowStatus {
if updateInfo == nil {
return nil
}
entityVersion := versionutil.GetJobEntityVersion(
updateInfo.GetJobConfigVersion(),
runtime.GetDesiredStateVersion(),
runtime.GetWorkflowVersion(),
)
prevVersion := versionutil.GetJobEntityVersion(
updateInfo.GetPrevJobConfigVersion(),
runtime.GetDesiredStateVersion(),
runtime.GetWorkflowVersion(),
)
return &stateless.WorkflowStatus{
Type: stateless.WorkflowType(updateInfo.GetType()),
State: stateless.WorkflowState(updateInfo.GetState()),
PrevState: stateless.WorkflowState(updateInfo.GetPrevState()),
NumInstancesCompleted: updateInfo.GetInstancesDone(),
NumInstancesRemaining: updateInfo.GetInstancesTotal() - updateInfo.GetInstancesDone() - updateInfo.GetInstancesFailed(),
NumInstancesFailed: updateInfo.GetInstancesFailed(),
InstancesCurrent: updateInfo.GetInstancesCurrent(),
Version: entityVersion,
PrevVersion: prevVersion,
CreationTime: updateInfo.GetCreationTime(),
UpdateTime: updateInfo.GetUpdateTime(),
CompletionTime: updateInfo.GetCompletionTime(),
}
}
// ConvertRuntimeInfoToJobStatus converts v0 job.RuntimeInfo and private
// UpdateModel to v1alpha stateless.JobStatus
func ConvertRuntimeInfoToJobStatus(
runtime *job.RuntimeInfo,
updateInfo *models.UpdateModel,
) *stateless.JobStatus {
result := &stateless.JobStatus{}
podConfigVersionStats := make(map[string]*stateless.JobStatus_PodStateStats)
result.Revision = &v1alphapeloton.Revision{
Version: runtime.GetRevision().GetVersion(),
CreatedAt: runtime.GetRevision().GetCreatedAt(),
UpdatedAt: runtime.GetRevision().GetUpdatedAt(),
UpdatedBy: runtime.GetRevision().GetUpdatedBy(),
}
result.State = stateless.JobState(runtime.GetState())
result.CreationTime = runtime.GetCreationTime()
result.PodStats = ConvertTaskStatsToPodStats(runtime.TaskStats)
result.DesiredState = stateless.JobState(runtime.GetGoalState())
result.Version = versionutil.GetJobEntityVersion(
runtime.GetConfigurationVersion(),
runtime.GetDesiredStateVersion(),
runtime.GetWorkflowVersion(),
)
result.WorkflowStatus = ConvertUpdateModelToWorkflowStatus(runtime, updateInfo)
for configVersion, taskStats := range runtime.GetTaskStatsByConfigurationVersion() {
entityVersion := versionutil.GetPodEntityVersion(configVersion)
podConfigVersionStats[entityVersion.GetValue()] = &stateless.JobStatus_PodStateStats{
StateStats: ConvertTaskStatsToPodStats(taskStats.GetStateStats()),
}
}
result.PodStatsByConfigurationVersion = podConfigVersionStats
return result
}
// ConvertJobSummary converts v0 job.JobSummary and private
// UpdateModel to v1alpha stateless.JobSummary
func ConvertJobSummary(
summary *job.JobSummary,
updateInfo *models.UpdateModel) *stateless.JobSummary {
return &stateless.JobSummary{
JobId: &v1alphapeloton.JobID{Value: summary.GetId().GetValue()},
Name: summary.GetName(),
OwningTeam: summary.GetOwningTeam(),
Owner: summary.GetOwner(),
Labels: ConvertLabels(summary.GetLabels()),
InstanceCount: summary.GetInstanceCount(),
RespoolId: &v1alphapeloton.ResourcePoolID{
Value: summary.GetRespoolID().GetValue()},
Status: ConvertRuntimeInfoToJobStatus(summary.GetRuntime(), updateInfo),
Sla: ConvertSLAConfigToSLASpec(summary.GetSLA()),
}
}
// ConvertSLAConfigToSLASpec convert job's sla config to sla spec
func ConvertSLAConfigToSLASpec(slaConfig *job.SlaConfig) *stateless.SlaSpec {
return &stateless.SlaSpec{
Priority: slaConfig.GetPriority(),
Preemptible: slaConfig.GetPreemptible(),
Revocable: slaConfig.GetRevocable(),
MaximumUnavailableInstances: slaConfig.GetMaximumUnavailableInstances(),
}
}
// ConvertSLASpecToSLAConfig converts job's sla spec to sla config
func ConvertSLASpecToSLAConfig(slaSpec *stateless.SlaSpec) *job.SlaConfig {
return &job.SlaConfig{
Priority: slaSpec.GetPriority(),
Preemptible: slaSpec.GetPreemptible(),
Revocable: slaSpec.GetRevocable(),
MaximumUnavailableInstances: slaSpec.GetMaximumUnavailableInstances(),
}
}
// ConvertUpdateModelToWorkflowInfo converts private UpdateModel
// to v1alpha stateless.WorkflowInfo
func ConvertUpdateModelToWorkflowInfo(
runtime *job.RuntimeInfo,
updateInfo *models.UpdateModel,
workflowEvents []*stateless.WorkflowEvent,
instanceWorkflowEvents []*stateless.WorkflowInfoInstanceWorkflowEvents,
) *stateless.WorkflowInfo {
result := &stateless.WorkflowInfo{}
result.Status = ConvertUpdateModelToWorkflowStatus(runtime, updateInfo)
if updateInfo.GetType() == models.WorkflowType_UPDATE {
result.InstancesAdded = util.ConvertInstanceIDListToInstanceRange(updateInfo.GetInstancesAdded())
result.InstancesRemoved = util.ConvertInstanceIDListToInstanceRange(updateInfo.GetInstancesRemoved())
result.InstancesUpdated = util.ConvertInstanceIDListToInstanceRange(updateInfo.GetInstancesUpdated())
result.UpdateSpec = &stateless.UpdateSpec{
BatchSize: updateInfo.GetUpdateConfig().GetBatchSize(),
RollbackOnFailure: updateInfo.GetUpdateConfig().GetRollbackOnFailure(),
MaxInstanceRetries: updateInfo.GetUpdateConfig().GetMaxInstanceAttempts(),
MaxTolerableInstanceFailures: updateInfo.GetUpdateConfig().GetMaxFailureInstances(),
StartPaused: updateInfo.GetUpdateConfig().GetStartPaused(),
InPlace: updateInfo.GetUpdateConfig().GetInPlace(),
}
} else if updateInfo.GetType() == models.WorkflowType_RESTART {
result.RestartSpec = &stateless.RestartSpec{
BatchSize: updateInfo.GetUpdateConfig().GetBatchSize(),
Ranges: util.ConvertInstanceIDListToInstanceRange(updateInfo.GetInstancesUpdated()),
InPlace: updateInfo.GetUpdateConfig().GetInPlace(),
}
}
result.OpaqueData = &v1alphapeloton.OpaqueData{
Data: updateInfo.GetOpaqueData().GetData(),
}
result.Events = workflowEvents
result.InstanceEvents = instanceWorkflowEvents
return result
}
// ConvertStatelessQuerySpecToJobQuerySpec converts query spec for stateless svc to
// job query spec
func ConvertStatelessQuerySpecToJobQuerySpec(spec *stateless.QuerySpec) *job.QuerySpec {
var labels []*peloton.Label
var jobStates []job.JobState
var creationTimeRange *peloton.TimeRange
var completionTimeRange *peloton.TimeRange
var respoolPath *pelotonv0respool.ResourcePoolPath
var paginationSpec *pelotonv0query.PaginationSpec
for _, label := range spec.GetLabels() {
labels = append(labels, &peloton.Label{
Key: label.GetKey(),
Value: label.GetValue(),
})
}
for _, jobState := range spec.GetJobStates() {
jobStates = append(jobStates, job.JobState(jobState))
}
if spec.GetCreationTimeRange() != nil {
creationTimeRange = &peloton.TimeRange{
Min: spec.GetCreationTimeRange().GetMin(),
Max: spec.GetCreationTimeRange().GetMax(),
}
}
if spec.GetCompletionTimeRange() != nil {
completionTimeRange = &peloton.TimeRange{
Min: spec.GetCompletionTimeRange().GetMin(),
Max: spec.GetCompletionTimeRange().GetMax(),
}
}
if spec.GetRespool() != nil {
respoolPath = &pelotonv0respool.ResourcePoolPath{
Value: spec.GetRespool().GetValue(),
}
}
if spec.GetPagination() != nil {
paginationSpec = convertV1AlphaPaginationSpecToV0PaginationSpec(
spec.GetPagination(),
)
}
return &job.QuerySpec{
Pagination: paginationSpec,
Labels: labels,
Keywords: spec.GetKeywords(),
JobStates: jobStates,
Respool: respoolPath,
Owner: spec.GetOwner(),
Name: spec.GetName(),
CreationTimeRange: creationTimeRange,
CompletionTimeRange: completionTimeRange,
}
}
// ConvertJobSpecToJobConfig converts stateless job spec to job config
func ConvertJobSpecToJobConfig(spec *stateless.JobSpec) (*job.JobConfig, error) {
result := &job.JobConfig{
Type: job.JobType_SERVICE,
Name: spec.GetName(),
Owner: spec.GetOwner(),
OwningTeam: spec.GetOwningTeam(),
LdapGroups: spec.GetLdapGroups(),
Description: spec.GetDescription(),
InstanceCount: spec.GetInstanceCount(),
}
if spec.GetRevision() != nil {
result.ChangeLog = &peloton.ChangeLog{
Version: spec.GetRevision().GetVersion(),
CreatedAt: spec.GetRevision().GetCreatedAt(),
UpdatedAt: spec.GetRevision().GetUpdatedAt(),
UpdatedBy: spec.GetRevision().GetUpdatedBy(),
}
}
if len(spec.GetLabels()) != 0 {
var labels []*peloton.Label
for _, label := range spec.GetLabels() {
labels = append(labels, &peloton.Label{
Key: label.GetKey(), Value: label.GetValue(),
})
}
result.Labels = labels
}
if spec.GetSla() != nil {
result.SLA = ConvertSLASpecToSLAConfig(spec.GetSla())
}
if spec.GetDefaultSpec() != nil {
defaultConfig, err := ConvertPodSpecToTaskConfig(spec.GetDefaultSpec())
if err != nil {
return nil, err
}
result.DefaultConfig = defaultConfig
}
if spec.GetSla() != nil && spec.GetDefaultSpec() != nil {
result.DefaultConfig.Revocable = spec.GetSla().GetRevocable()
}
if len(spec.GetInstanceSpec()) != 0 {
result.InstanceConfig = make(map[uint32]*task.TaskConfig)
for instanceID, instanceSpec := range spec.GetInstanceSpec() {
instanceConfig, err := ConvertPodSpecToTaskConfig(instanceSpec)
if err != nil {
return nil, err
}
if spec.GetSla() != nil && spec.GetDefaultSpec() != nil {
instanceConfig.Revocable = spec.GetSla().GetRevocable()
}
result.InstanceConfig[instanceID] = instanceConfig
}
}
if spec.GetRespoolId() != nil {
result.RespoolID = &peloton.ResourcePoolID{
Value: spec.GetRespoolId().GetValue(),
}
}
return result, nil
}
// FindVolumeInPodSpec finds a volume of given name in the
// volume spec present in the pod spec
func FindVolumeInPodSpec(spec *pod.PodSpec, name string) *volume.VolumeSpec {
for _, volume := range spec.GetVolumes() {
if volume.GetName() == name {
return volume
}
}
return nil
}
// ConvertMesosContainerToPodSpec converts the mesos container info to PodSpec
func ConvertMesosContainerToPodSpec(
containerInfo *mesosv1.ContainerInfo, // input
spec *pod.PodSpec, // output
container *pod.ContainerSpec, //output
) {
if containerInfo == nil {
return
}
if spec.GetMesosSpec() == nil {
spec.MesosSpec = &apachemesos.PodSpec{}
}
// populate container type
switch containerInfo.GetType() {
case mesosv1.ContainerInfo_DOCKER:
spec.MesosSpec.Type = apachemesos.PodSpec_CONTAINER_TYPE_DOCKER
case mesosv1.ContainerInfo_MESOS:
spec.MesosSpec.Type = apachemesos.PodSpec_CONTAINER_TYPE_MESOS
}
// Populate volumes
var volumeSpecs []*volume.VolumeSpec
var volumeMounts []*pod.VolumeMount
for _, v := range containerInfo.GetVolumes() {
// TBD original name is lost, store it with v0 api
volumeSpec := FindVolumeInPodSpec(spec, v.GetHostPath())
if volumeSpec == nil {
volumeSpec = &volume.VolumeSpec{
HostPath: &volume.VolumeSpec_HostPathVolumeSource{
Path: v.GetHostPath(),
},
Type: volume.VolumeSpec_VOLUME_TYPE_HOST_PATH,
Name: v.GetHostPath(),
}
volumeSpecs = append(volumeSpecs, volumeSpec)
}
readOnly := false
if v.GetMode() == mesosv1.Volume_RO {
readOnly = true
}
volumeMount := &pod.VolumeMount{
Name: v.GetHostPath(),
ReadOnly: readOnly,
MountPath: v.GetContainerPath(),
}
volumeMounts = append(volumeMounts, volumeMount)
}
if len(volumeSpecs) > 0 {
spec.Volumes = volumeSpecs
}
if len(volumeMounts) > 0 {
container.VolumeMounts = volumeMounts
}
// Populate container type specific info
if containerInfo.GetType() == mesosv1.ContainerInfo_DOCKER {
dockerInfo := containerInfo.GetDocker()
var parameters []*apachemesos.PodSpec_DockerParameter
for _, parameter := range dockerInfo.GetParameters() {
p := &apachemesos.PodSpec_DockerParameter{
Key: parameter.GetKey(),
Value: parameter.GetValue(),
}
parameters = append(parameters, p)
}
if len(parameters) > 0 {
spec.MesosSpec.DockerParameters = parameters
}
if len(dockerInfo.GetImage()) > 0 {
container.Image = dockerInfo.GetImage()
}
spec.MesosSpec.NetworkSpec = &apachemesos.PodSpec_NetworkSpec{}
switch dockerInfo.GetNetwork() {
case mesosv1.ContainerInfo_DockerInfo_HOST:
spec.MesosSpec.NetworkSpec.Type = apachemesos.PodSpec_NetworkSpec_NETWORK_TYPE_HOST
case mesosv1.ContainerInfo_DockerInfo_BRIDGE:
spec.MesosSpec.NetworkSpec.Type = apachemesos.PodSpec_NetworkSpec_NETWORK_TYPE_BRIDGE
case mesosv1.ContainerInfo_DockerInfo_NONE:
spec.MesosSpec.NetworkSpec.Type = apachemesos.PodSpec_NetworkSpec_NETWORK_TYPE_NONE
case mesosv1.ContainerInfo_DockerInfo_USER:
spec.MesosSpec.NetworkSpec.Type = apachemesos.PodSpec_NetworkSpec_NETWORK_TYPE_USER
}
if len(containerInfo.GetNetworkInfos()) > 0 {
spec.MesosSpec.NetworkSpec.Name = containerInfo.GetNetworkInfos()[0].GetName()
}
} else {
if len(containerInfo.GetMesos().GetImage().GetDocker().GetName()) > 0 {
container.Image = containerInfo.GetMesos().GetImage().GetDocker().GetName()
}
}
}
// ConvertPodSpecToMesosContainer converts pod spec to mesos container info
func ConvertPodSpecToMesosContainer(spec *pod.PodSpec) *mesosv1.ContainerInfo {
if len(spec.GetContainers()) == 0 {
return nil
}
mainContainer := spec.GetContainers()[0]
if mainContainer.GetContainer() != nil {
return mainContainer.GetContainer()
}
containerInfo := &mesosv1.ContainerInfo{}
mesosPodSpec := spec.GetMesosSpec()
// populate ContainerType
if mesosPodSpec.GetType() == apachemesos.PodSpec_CONTAINER_TYPE_MESOS {
containerType := mesosv1.ContainerInfo_MESOS
containerInfo.Type = &containerType
} else if mesosPodSpec.GetType() == apachemesos.PodSpec_CONTAINER_TYPE_DOCKER {
containerType := mesosv1.ContainerInfo_DOCKER
containerInfo.Type = &containerType
} else {
return nil
}
// Populate volumes
var volumes []*mesosv1.Volume
for _, volumeMount := range mainContainer.GetVolumeMounts() {
volumeSpec := FindVolumeInPodSpec(spec, volumeMount.GetName())
if volumeSpec.GetType() != volume.VolumeSpec_VOLUME_TYPE_HOST_PATH ||
volumeSpec.GetHostPath() == nil {
// unsupported volume
continue
}
mode := mesosv1.Volume_RW
if volumeMount.GetReadOnly() {
mode = mesosv1.Volume_RO
}
mountPath := volumeMount.GetMountPath()
containerPath := volumeSpec.GetHostPath().GetPath()
mesosVolume := &mesosv1.Volume{
Mode: &mode,
ContainerPath: &mountPath,
HostPath: &containerPath,
}
volumes = append(volumes, mesosVolume)
}
if len(volumes) > 0 {
containerInfo.Volumes = volumes
}
// Populate container type specific info
cached := true
image := mainContainer.GetImage()
if len(image) > 0 {
if containerInfo.GetType() == mesosv1.ContainerInfo_DOCKER {
var parameters []*mesosv1.Parameter
for _, parameter := range mesosPodSpec.GetDockerParameters() {
key := parameter.GetKey()
value := parameter.GetValue()
mesosParameter := &mesosv1.Parameter{
Key: &key,
Value: &value,
}
parameters = append(parameters, mesosParameter)
}
// Fill in the network
hostNetwork := mesosv1.ContainerInfo_DockerInfo_HOST
if mesosPodSpec.GetNetworkSpec() != nil {
switch mesosPodSpec.GetNetworkSpec().GetType() {
case apachemesos.PodSpec_NetworkSpec_NETWORK_TYPE_INVALID:
// This should never be set and will be mapped to NONE for now.
hostNetwork = mesosv1.ContainerInfo_DockerInfo_NONE
case apachemesos.PodSpec_NetworkSpec_NETWORK_TYPE_HOST:
hostNetwork = mesosv1.ContainerInfo_DockerInfo_HOST
case apachemesos.PodSpec_NetworkSpec_NETWORK_TYPE_BRIDGE:
hostNetwork = mesosv1.ContainerInfo_DockerInfo_BRIDGE
case apachemesos.PodSpec_NetworkSpec_NETWORK_TYPE_NONE:
hostNetwork = mesosv1.ContainerInfo_DockerInfo_NONE
case apachemesos.PodSpec_NetworkSpec_NETWORK_TYPE_USER:
hostNetwork = mesosv1.ContainerInfo_DockerInfo_USER
}
networkName := mesosPodSpec.GetNetworkSpec().GetName()
if len(networkName) > 0 {
containerInfo.NetworkInfos = []*mesosv1.NetworkInfo{
{
Name: &networkName,
},
}
}
}
containerInfo.Docker = &mesosv1.ContainerInfo_DockerInfo{
Image: &image,
Network: &hostNetwork,
Parameters: parameters,
}
} else {
imageType := mesosv1.Image_DOCKER
containerInfo.Mesos = &mesosv1.ContainerInfo_MesosInfo{
Image: &mesosv1.Image{
Type: &imageType,
Docker: &mesosv1.Image_Docker{
Name: &image,
},
Cached: &cached,
},
}
}
}
return containerInfo
}
// ConvertMesosCommandToPodSpec converts the mesos command info to pod spec
func ConvertMesosCommandToPodSpec(
commandInfo *mesosv1.CommandInfo, //input
spec *pod.PodSpec, //output
container *pod.ContainerSpec, // output
) {
if commandInfo == nil {
return
}
if spec.GetMesosSpec() == nil {
spec.MesosSpec = &apachemesos.PodSpec{}
}
// populate uris
var uris []*apachemesos.PodSpec_URI
for _, uri := range commandInfo.GetUris() {
u := &apachemesos.PodSpec_URI{
Value: uri.GetValue(),
Executable: uri.GetExecutable(),
Extract: uri.GetExtract(),
Cache: uri.GetCache(),
OutputFile: uri.GetOutputFile(),
}
uris = append(uris, u)
}
if len(uris) > 0 {
spec.MesosSpec.Uris = uris
}
// populate environment
if commandInfo.GetEnvironment() != nil {
var environments []*pod.Environment
for _, env := range commandInfo.GetEnvironment().GetVariables() {
if env.GetType() != mesosv1.Environment_Variable_VALUE {
// unsupported type
continue
}
e := &pod.Environment{
Name: env.GetName(),
Value: env.GetValue(),
}
environments = append(environments, e)
}
container.Environment = environments
}
// populate shell
if commandInfo.Shell != nil {
spec.MesosSpec.Shell = commandInfo.GetShell()
}
// populate entrypoint
container.Entrypoint = &pod.CommandSpec{}
if len(commandInfo.GetValue()) > 0 {
container.Entrypoint.Value = commandInfo.GetValue()
}
if len(commandInfo.GetArguments()) > 0 {
container.Entrypoint.Arguments = commandInfo.GetArguments()
}
}
// ConvertPodSpecToMesosCommand converts pod spec to mesos command info
func ConvertPodSpecToMesosCommand(spec *pod.PodSpec) *mesosv1.CommandInfo {
if len(spec.GetContainers()) == 0 {
return nil
}
mainContainer := spec.GetContainers()[0]
if mainContainer.GetCommand() != nil {
return mainContainer.GetCommand()
}
commandInfo := &mesosv1.CommandInfo{}
mesosPodSpec := spec.GetMesosSpec()
// populate uris
var uris []*mesosv1.CommandInfo_URI
for _, uri := range mesosPodSpec.GetUris() {
uriValue := uri.GetValue()
uriExecutable := uri.GetExecutable()
uriExtract := uri.GetExtract()
uriCache := uri.GetCache()
mesosUri := &mesosv1.CommandInfo_URI{
Value: &uriValue,
Executable: &uriExecutable,
Extract: &uriExtract,
Cache: &uriCache,
}
if len(uri.GetOutputFile()) > 0 {
uriOutputFile := uri.GetOutputFile()
mesosUri.OutputFile = &uriOutputFile
}
uris = append(uris, mesosUri)
}
if len(uris) > 0 {
commandInfo.Uris = uris
}
// populate environment
var environments []*mesosv1.Environment_Variable
for _, env := range mainContainer.GetEnvironment() {
envName := env.GetName()
envValue := env.GetValue()
envType := mesosv1.Environment_Variable_VALUE
mesosEnv := &mesosv1.Environment_Variable{
Name: &envName,
Value: &envValue,
Type: &envType,
}
environments = append(environments, mesosEnv)
}
if len(environments) > 0 {
environment := &mesosv1.Environment{
Variables: environments,
}
commandInfo.Environment = environment
}
// populate shell
if mesosPodSpec != nil {
commandShell := mesosPodSpec.GetShell()
commandInfo.Shell = &commandShell
}
// populate command
if len(mainContainer.GetEntrypoint().GetValue()) > 0 {
commandValue := mainContainer.GetEntrypoint().GetValue()
commandInfo.Value = &commandValue
}
// populate arguments
if len(mainContainer.GetEntrypoint().GetArguments()) > 0 {
commandInfo.Arguments = mainContainer.GetEntrypoint().GetArguments()
}
return commandInfo
}
// ConvertMesosExecutorInfoToPodSpec converts mesos executor info to pod spec
func ConvertMesosExecutorInfoToPodSpec(
executorInfo *mesosv1.ExecutorInfo, // input
spec *pod.PodSpec, // output
container *pod.ContainerSpec, //output
) {
if executorInfo == nil {
return
}
if spec.GetMesosSpec() == nil {
spec.MesosSpec = &apachemesos.PodSpec{}
}
spec.MesosSpec.ExecutorSpec = &apachemesos.PodSpec_ExecutorSpec{}
// populate the executor type
switch executorInfo.GetType() {
case mesosv1.ExecutorInfo_UNKNOWN:
spec.MesosSpec.ExecutorSpec.Type = apachemesos.PodSpec_ExecutorSpec_EXECUTOR_TYPE_INVALID
case mesosv1.ExecutorInfo_DEFAULT:
spec.MesosSpec.ExecutorSpec.Type = apachemesos.PodSpec_ExecutorSpec_EXECUTOR_TYPE_DEFAULT
case mesosv1.ExecutorInfo_CUSTOM:
spec.MesosSpec.ExecutorSpec.Type = apachemesos.PodSpec_ExecutorSpec_EXECUTOR_TYPE_CUSTOM
}
// ppopulate the executor ID
if executorInfo.GetExecutorId() != nil {
spec.MesosSpec.ExecutorSpec.ExecutorId = executorInfo.GetExecutorId().GetValue()
}
// populate the executor data
if len(executorInfo.GetData()) > 0 {
spec.MesosSpec.ExecutorSpec.Data = executorInfo.GetData()
}
// populate executor resources
if len(executorInfo.GetResources()) > 0 {
executorResources := &apachemesos.PodSpec_ExecutorSpec_Resources{}
for _, resource := range executorInfo.GetResources() {
if resource.GetType() == mesosv1.Value_SCALAR {
if resource.GetName() == cpuNameMesos {
executorResources.Cpu = resource.GetScalar().GetValue()
}
if resource.GetName() == memNameMesos {
executorResources.MemMb = resource.GetScalar().GetValue()
}
}
}
spec.MesosSpec.ExecutorSpec.Resources = executorResources
}
}
// ConvertPodSpecToMesosExecutorInfo converts pod spec to mesos executor info
func ConvertPodSpecToMesosExecutorInfo(spec *pod.PodSpec) *mesosv1.ExecutorInfo {
if len(spec.GetContainers()) == 0 {
return nil
}
mainContainer := spec.GetContainers()[0]
if mainContainer.GetExecutor() != nil {
return mainContainer.GetExecutor()
}
executorInfo := &mesosv1.ExecutorInfo{}
mesosExecutorSpec := spec.GetMesosSpec().GetExecutorSpec()
if mesosExecutorSpec == nil {
return nil
}
// populate the executor type
executorType := mesosv1.ExecutorInfo_UNKNOWN
if mesosExecutorSpec.GetType() == apachemesos.PodSpec_ExecutorSpec_EXECUTOR_TYPE_CUSTOM {
executorType = mesosv1.ExecutorInfo_CUSTOM
} else if mesosExecutorSpec.GetType() == apachemesos.PodSpec_ExecutorSpec_EXECUTOR_TYPE_DEFAULT {
executorType = mesosv1.ExecutorInfo_DEFAULT
}
executorInfo.Type = &executorType
// ppopulate the executor ID
executorID := mesosExecutorSpec.GetExecutorId()
if len(mesosExecutorSpec.GetExecutorId()) > 0 {
executorInfo.ExecutorId = &mesosv1.ExecutorID{
Value: &executorID,
}
}
// populate the executor data
if len(mesosExecutorSpec.GetData()) > 0 {
executorInfo.Data = mesosExecutorSpec.GetData()
}
// populate the executor resources
var resources []*mesosv1.Resource
cpuValue := mesosExecutorSpec.GetResources().GetCpu()
if cpuValue > 0 {
cpuName := cpuNameMesos
resources = append(resources, &mesosv1.Resource{
Type: mesosv1.Value_SCALAR.Enum(),
Name: &cpuName,
Scalar: &mesosv1.Value_Scalar{
Value: &cpuValue,
},
})
}
memValue := mesosExecutorSpec.GetResources().GetMemMb()
if memValue > 0 {
memName := memNameMesos
resources = append(resources, &mesosv1.Resource{
Type: mesosv1.Value_SCALAR.Enum(),
Name: &memName,
Scalar: &mesosv1.Value_Scalar{
Value: &memValue,
},
})
}
executorInfo.Resources = resources
return executorInfo
}
// ConvertPodSpecToTaskConfig converts a pod spec to task config
func ConvertPodSpecToTaskConfig(spec *pod.PodSpec) (*task.TaskConfig, error) {
if len(spec.GetContainers()) > 1 {
return nil,
yarpcerrors.UnimplementedErrorf("configuration of more than one container per pod is not supported")
}
if len(spec.GetInitContainers()) > 0 {
return nil,
yarpcerrors.UnimplementedErrorf("init containers are not supported")
}
result := &task.TaskConfig{
Controller: spec.GetController(),
KillGracePeriodSeconds: spec.GetKillGracePeriodSeconds(),
Revocable: spec.GetRevocable(),
}
var mainContainer *pod.ContainerSpec
if len(spec.GetContainers()) > 0 {
mainContainer = spec.GetContainers()[0]
result.Container = ConvertPodSpecToMesosContainer(spec)
result.Command = ConvertPodSpecToMesosCommand(spec)
result.Executor = ConvertPodSpecToMesosExecutorInfo(spec)
}
result.Name = mainContainer.GetName()
if spec.GetLabels() != nil {
var labels []*peloton.Label
for _, label := range spec.GetLabels() {
labels = append(labels, &peloton.Label{
Key: label.GetKey(), Value: label.GetValue(),
})
}
result.Labels = labels
}
if mainContainer.GetResource() != nil {
result.Resource = &task.ResourceConfig{
CpuLimit: mainContainer.GetResource().GetCpuLimit(),
MemLimitMb: mainContainer.GetResource().GetMemLimitMb(),
DiskLimitMb: mainContainer.GetResource().GetDiskLimitMb(),
FdLimit: mainContainer.GetResource().GetFdLimit(),
GpuLimit: mainContainer.GetResource().GetGpuLimit(),
}
}
if mainContainer.GetLivenessCheck() != nil {
healthCheck := &task.HealthCheckConfig{
Enabled: mainContainer.GetLivenessCheck().GetEnabled(),
InitialIntervalSecs: mainContainer.GetLivenessCheck().GetInitialIntervalSecs(),
IntervalSecs: mainContainer.GetLivenessCheck().GetIntervalSecs(),
MaxConsecutiveFailures: mainContainer.GetLivenessCheck().GetMaxConsecutiveFailures(),
TimeoutSecs: mainContainer.GetLivenessCheck().GetTimeoutSecs(),
Type: task.HealthCheckConfig_Type(mainContainer.GetLivenessCheck().GetType()),
}
if mainContainer.GetLivenessCheck().GetCommandCheck() != nil {
healthCheck.CommandCheck = &task.HealthCheckConfig_CommandCheck{
Command: mainContainer.GetLivenessCheck().GetCommandCheck().GetCommand(),
UnshareEnvironments: mainContainer.GetLivenessCheck().GetCommandCheck().GetUnshareEnvironments(),
}
}
if mainContainer.GetLivenessCheck().GetHttpCheck() != nil {
healthCheck.HttpCheck = &task.HealthCheckConfig_HTTPCheck{
Scheme: mainContainer.GetLivenessCheck().GetHttpCheck().GetScheme(),
Port: mainContainer.GetLivenessCheck().GetHttpCheck().GetPort(),
Path: mainContainer.GetLivenessCheck().GetHttpCheck().GetPath(),
}
}
result.HealthCheck = healthCheck
}
if len(mainContainer.GetPorts()) != 0 {
var portConfigs []*task.PortConfig
for _, port := range mainContainer.GetPorts() {
portConfigs = append(portConfigs, &task.PortConfig{
Name: port.GetName(),
Value: port.GetValue(),
EnvName: port.GetEnvName(),
})
}
result.Ports = portConfigs
}
if spec.GetConstraint() != nil {
result.Constraint = ConvertPodConstraintsToTaskConstraints(
[]*pod.Constraint{spec.GetConstraint()},
)[0]
}
if spec.GetRestartPolicy() != nil {
result.RestartPolicy = &task.RestartPolicy{
MaxFailures: spec.GetRestartPolicy().GetMaxFailures(),
}
}
if spec.GetVolume() != nil {
result.Volume = &task.PersistentVolumeConfig{
ContainerPath: spec.GetVolume().GetContainerPath(),
SizeMB: spec.GetVolume().GetSizeMb(),
}
}
if spec.GetPreemptionPolicy() != nil {
result.PreemptionPolicy = &task.PreemptionPolicy{
KillOnPreempt: spec.GetPreemptionPolicy().GetKillOnPreempt(),
}
if result.GetPreemptionPolicy().GetKillOnPreempt() {
result.PreemptionPolicy.Type = task.PreemptionPolicy_TYPE_PREEMPTIBLE
} else {
result.PreemptionPolicy.Type = task.PreemptionPolicy_TYPE_NON_PREEMPTIBLE
}
}
return result, nil
}
// ConvertPodConstraintsToTaskConstraints converts pod constraints to task constraints
func ConvertPodConstraintsToTaskConstraints(
constraints []*pod.Constraint,
) []*task.Constraint {
var result []*task.Constraint
for _, podConstraint := range constraints {
taskConstraint := &task.Constraint{
Type: task.Constraint_Type(podConstraint.GetType()),
}
if podConstraint.GetLabelConstraint() != nil {
taskConstraint.LabelConstraint = &task.LabelConstraint{
Kind: task.LabelConstraint_Kind(
podConstraint.GetLabelConstraint().GetKind(),
),
Condition: task.LabelConstraint_Condition(
podConstraint.GetLabelConstraint().GetCondition(),
),
Requirement: podConstraint.GetLabelConstraint().GetRequirement(),
}
if podConstraint.GetLabelConstraint().GetLabel() != nil {
taskConstraint.LabelConstraint.Label = &peloton.Label{
Key: podConstraint.GetLabelConstraint().GetLabel().GetKey(),
Value: podConstraint.GetLabelConstraint().GetLabel().GetValue(),
}
}
}
if podConstraint.GetAndConstraint() != nil {
taskConstraint.AndConstraint = &task.AndConstraint{
Constraints: ConvertPodConstraintsToTaskConstraints(
podConstraint.GetAndConstraint().GetConstraints()),
}
}
if podConstraint.GetOrConstraint() != nil {
taskConstraint.OrConstraint = &task.OrConstraint{
Constraints: ConvertPodConstraintsToTaskConstraints(
podConstraint.GetOrConstraint().GetConstraints()),
}
}
result = append(result, taskConstraint)
}
return result
}
// ConvertUpdateSpecToUpdateConfig converts update spec to update config
func ConvertUpdateSpecToUpdateConfig(spec *stateless.UpdateSpec) *update.UpdateConfig {
return &update.UpdateConfig{
BatchSize: spec.GetBatchSize(),
RollbackOnFailure: spec.GetRollbackOnFailure(),
MaxInstanceAttempts: spec.GetMaxInstanceRetries(),
MaxFailureInstances: spec.GetMaxTolerableInstanceFailures(),
StartPaused: spec.GetStartPaused(),
InPlace: spec.GetInPlace(),
StartTasks: spec.GetStartPods(),
}
}
// ConvertCreateSpecToUpdateConfig converts create spec to update config
func ConvertCreateSpecToUpdateConfig(spec *stateless.CreateSpec) *update.UpdateConfig {
return &update.UpdateConfig{
BatchSize: spec.GetBatchSize(),
MaxInstanceAttempts: spec.GetMaxInstanceRetries(),
MaxFailureInstances: spec.GetMaxTolerableInstanceFailures(),
StartPaused: spec.GetStartPaused(),
}
}
// ConvertPodQuerySpecToTaskQuerySpec converts
// v1alpha pod.QuerySpec to v0 task.QuerySpec
func ConvertPodQuerySpecToTaskQuerySpec(spec *pod.QuerySpec) *task.QuerySpec {
var taskStates []task.TaskState
var taskNames []string
if spec.GetPodStates() != nil {
for _, state := range spec.GetPodStates() {
taskStates = append(taskStates, ConvertPodStateToTaskState(state))
}
}
if spec.GetNames() != nil {
for _, podName := range spec.GetNames() {
taskNames = append(taskNames, podName.GetValue())
}
}
return &task.QuerySpec{
Pagination: convertV1AlphaPaginationSpecToV0PaginationSpec(
spec.GetPagination(),
),
TaskStates: taskStates,
Names: taskNames,
Hosts: spec.GetHosts(),
}
}
// ConvertTaskInfosToPodInfos converts a list of
// v0 task info to a list of v1alpha pod info
func ConvertTaskInfosToPodInfos(taskInfos []*task.TaskInfo) []*pod.PodInfo {
var podInfos []*pod.PodInfo
for _, taskInfo := range taskInfos {
podInfo := &pod.PodInfo{
Spec: ConvertTaskConfigToPodSpec(
taskInfo.GetConfig(),
taskInfo.GetJobId().GetValue(),
taskInfo.GetInstanceId(),
),
Status: ConvertTaskRuntimeToPodStatus(taskInfo.GetRuntime()),
}
podInfos = append(podInfos, podInfo)
}
return podInfos
}
// ConvertTaskStatsToPodStats converts v0 task stats to v1alpha pod stats
func ConvertTaskStatsToPodStats(taskStats map[string]uint32) map[string]uint32 {
result := make(map[string]uint32)
for stateStr, num := range taskStats {
taskState := task.TaskState(task.TaskState_value[stateStr])
result[ConvertTaskStateToPodState(taskState).String()] = num
}
return result
}
func convertV1AlphaPaginationSpecToV0PaginationSpec(
pagination *query.PaginationSpec,
) *pelotonv0query.PaginationSpec {
if pagination == nil {
return nil
}
var orderBy []*pelotonv0query.OrderBy
for _, ele := range pagination.GetOrderBy() {
orderBy = append(orderBy, &pelotonv0query.OrderBy{
Order: pelotonv0query.OrderBy_Order(ele.GetOrder()),
Property: &pelotonv0query.PropertyPath{
Value: ele.GetProperty().GetValue(),
},
})
}
return &pelotonv0query.PaginationSpec{
Offset: pagination.GetOffset(),
Limit: pagination.GetLimit(),
OrderBy: orderBy,
MaxLimit: pagination.GetMaxLimit(),
}
}
func convertTaskTerminationStatusToPodTerminationStatus(
termStatus *task.TerminationStatus,
) *pod.TerminationStatus {
if termStatus == nil {
return nil
}
podReason := pod.TerminationStatus_TERMINATION_STATUS_REASON_INVALID
switch termStatus.GetReason() {
case task.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_ON_REQUEST:
podReason = pod.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_ON_REQUEST
case task.TerminationStatus_TERMINATION_STATUS_REASON_FAILED:
podReason = pod.TerminationStatus_TERMINATION_STATUS_REASON_FAILED
case task.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_HOST_MAINTENANCE:
podReason = pod.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_HOST_MAINTENANCE
case task.TerminationStatus_TERMINATION_STATUS_REASON_PREEMPTED_RESOURCES:
podReason = pod.TerminationStatus_TERMINATION_STATUS_REASON_PREEMPTED_RESOURCES
case task.TerminationStatus_TERMINATION_STATUS_REASON_DEADLINE_TIMEOUT_EXCEEDED:
podReason = pod.TerminationStatus_TERMINATION_STATUS_REASON_DEADLINE_TIMEOUT_EXCEEDED
case task.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_FOR_UPDATE:
podReason = pod.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_FOR_UPDATE
case task.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_FOR_RESTART:
podReason = pod.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_FOR_RESTART
case task.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_FOR_SLA_AWARE_RESTART:
podReason = pod.TerminationStatus_TERMINATION_STATUS_REASON_KILLED_FOR_SLA_AWARE_RESTART
}
return &pod.TerminationStatus{
Reason: podReason,
ExitCode: termStatus.GetExitCode(),
Signal: termStatus.GetSignal(),
}
}