diff --git a/apis/authorization.cattle.io/v1/schema/schema.go b/apis/authorization.cattle.io/v1/schema/schema.go index fc975bc5..855b61f8 100644 --- a/apis/authorization.cattle.io/v1/schema/schema.go +++ b/apis/authorization.cattle.io/v1/schema/schema.go @@ -2,6 +2,8 @@ package schema import ( "github.com/rancher/norman/types" + "github.com/rancher/norman/types/factory" + "github.com/rancher/norman/types/mapper" "github.com/rancher/types/apis/authorization.cattle.io/v1" ) @@ -12,11 +14,30 @@ var ( Path: "/v1-authz", } - Schemas = types.NewSchemas(). - MustImport(&Version, v1.Project{}). + Schemas = factory.Schemas(&Version). + AddMapperForType(&Version, v1.Project{}, + mapper.DisplayName{}, + ). + AddMapperForType(&Version, v1.ProjectRoleTemplateBinding{}, + &mapper.Move{From: "subject/name", To: "subjectName"}, + &mapper.Move{From: "subject/kind", To: "subjectKind"}, + &mapper.Move{From: "subject/namespace", To: "subjectNamespace"}, + &mapper.Drop{Field: "subject"}, + ). + MustImportAndCustomize(&Version, v1.Project{}, func(schema *types.Schema) { + schema.SubContext = "projects" + }). MustImport(&Version, v1.ProjectRoleTemplate{}). - MustImport(&Version, v1.PodSecurityPolicyTemplate{}). MustImport(&Version, v1.ProjectRoleTemplateBinding{}). + MustImport(&Version, v1.PodSecurityPolicyTemplate{}). MustImport(&Version, v1.ClusterRoleTemplate{}). - MustImport(&Version, v1.ClusterRoleTemplateBinding{}) + MustImport(&Version, v1.ClusterRoleTemplateBinding{}). + MustImportAndCustomize(&Version, v1.ProjectRoleTemplateBinding{}, func(schema *types.Schema) { + schema.MustCustomizeField("subjectKind", func(field types.Field) types.Field { + field.Type = "enum" + field.Options = []string{"User", "Group", "ServiceAccount"} + field.Nullable = false + return field + }) + }) ) diff --git a/apis/authorization.cattle.io/v1/types.go b/apis/authorization.cattle.io/v1/types.go index c7ae2b4c..19404618 100644 --- a/apis/authorization.cattle.io/v1/types.go +++ b/apis/authorization.cattle.io/v1/types.go @@ -25,7 +25,7 @@ type ProjectRoleTemplate struct { Rules []rbacv1.PolicyRule `json:"rules,omitempty"` - ProjectRoleTemplates []string `json:"projectRoleTemplates,omitempty" norman:"type=array[reference[projectRoleTemplate]]"` + ProjectRoleTemplateNames []string `json:"projectRoleTemplateNames,omitempty" norman:"type=array[reference[projectRoleTemplate]]"` } type PodSecurityPolicyTemplate struct { @@ -51,7 +51,7 @@ type ClusterRoleTemplate struct { Rules []rbacv1.PolicyRule `json:"rules,omitempty"` - ClusterRoleTemplates []string `json:"clusterRoleTemplates,omitempty" norman:"type=array[reference[clusterRoleTemplate]]"` + ClusterRoleTemplateNames []string `json:"clusterRoleTemplateNames,omitempty" norman:"type=array[reference[clusterRoleTemplate]]"` } type ClusterRoleTemplateBinding struct { diff --git a/apis/cluster.cattle.io/v1/schema/schema.go b/apis/cluster.cattle.io/v1/schema/schema.go index 02c217ce..314e2615 100644 --- a/apis/cluster.cattle.io/v1/schema/schema.go +++ b/apis/cluster.cattle.io/v1/schema/schema.go @@ -2,9 +2,8 @@ package schema import ( "github.com/rancher/norman/types" - m "github.com/rancher/norman/types/mapping/mapper" + "github.com/rancher/norman/types/factory" "github.com/rancher/types/apis/cluster.cattle.io/v1" - "github.com/rancher/types/commonmappers" ) var ( @@ -12,14 +11,9 @@ var ( Version: "v1", Group: "cluster.cattle.io", Path: "/v1-cluster", - SubContexts: map[string]bool{ - "clusters": true, - }, } - Schemas = commonmappers.Add(&Version, types.NewSchemas()). - AddMapperForType(&Version, v1.Cluster{}, m.NewObject()). - AddMapperForType(&Version, v1.ClusterNode{}, m.NewObject()). + Schemas = factory.Schemas(&Version). MustImport(&Version, v1.Cluster{}). MustImport(&Version, v1.ClusterNode{}) ) diff --git a/apis/workload.cattle.io/v1/schema/mapper/deployment_strategy.go b/apis/workload.cattle.io/v1/schema/mapper/deployment_strategy.go new file mode 100644 index 00000000..d39e5000 --- /dev/null +++ b/apis/workload.cattle.io/v1/schema/mapper/deployment_strategy.go @@ -0,0 +1,47 @@ +package mapper + +import ( + "github.com/rancher/norman/types" + "github.com/rancher/norman/types/convert" + m "github.com/rancher/norman/types/mapper" +) + +type DeploymentStrategyMapper struct { +} + +func (d DeploymentStrategyMapper) FromInternal(data map[string]interface{}) { + if m.GetValueN(data, "strategy", "type") != "Recreate" { + m.PutValue(data, "Parallel", "deploymentStrategy", "kind") + maxUnavailable := m.GetValueN(data, "strategy", "rollingUpdate", "maxUnavailable") + maxSurge := m.GetValueN(data, "strategy", "rollingUpdate", "maxSurge") + if !convert.IsEmpty(maxSurge) { + m.PutValue(data, true, "deploymentStrategy", "parallelConfig", "startFirst") + m.PutValue(data, convert.ToString(maxSurge), "batchSize") + } else if !convert.IsEmpty(maxUnavailable) { + m.PutValue(data, convert.ToString(maxUnavailable), "batchSize") + } + } +} + +func (d DeploymentStrategyMapper) ToInternal(data map[string]interface{}) { + batchSize := m.GetValueN(data, "batchSize") + if convert.IsEmpty(batchSize) { + batchSize = 1 + } + + batchSize, _ = convert.ToNumber(batchSize) + + kind, _ := m.GetValueN(data, "deploymentStrategy", "kind").(string) + if kind == "" || kind == "Parallel" { + startFirst, _ := m.GetValueN(data, "deploymentStrategy", "startFirst").(bool) + if startFirst { + m.PutValue(data, batchSize, "strategy", "rollingUpdate", "maxSurge") + } else { + m.PutValue(data, batchSize, "strategy", "rollingUpdate", "maxUnavailable") + } + } +} + +func (d DeploymentStrategyMapper) ModifySchema(schema *types.Schema, schemas *types.Schemas) error { + return nil +} diff --git a/apis/workload.cattle.io/v1/schema/mapper/node_address.go b/apis/workload.cattle.io/v1/schema/mapper/node_address.go index 51d05afe..e57e34fc 100644 --- a/apis/workload.cattle.io/v1/schema/mapper/node_address.go +++ b/apis/workload.cattle.io/v1/schema/mapper/node_address.go @@ -2,7 +2,7 @@ package mapper import ( "github.com/rancher/norman/types" - "github.com/rancher/norman/types/mapping/mapper" + "github.com/rancher/norman/types/mapper" ) type NodeAddressMapper struct { diff --git a/apis/workload.cattle.io/v1/schema/mapper/os_info.go b/apis/workload.cattle.io/v1/schema/mapper/os_info.go index a42bbdd5..1bc31df4 100644 --- a/apis/workload.cattle.io/v1/schema/mapper/os_info.go +++ b/apis/workload.cattle.io/v1/schema/mapper/os_info.go @@ -5,7 +5,7 @@ import ( "github.com/rancher/norman/types" "github.com/rancher/norman/types/convert" - "github.com/rancher/norman/types/mapping/mapper" + "github.com/rancher/norman/types/mapper" ) type OSInfo struct { diff --git a/apis/workload.cattle.io/v1/schema/mapper/resource.go b/apis/workload.cattle.io/v1/schema/mapper/resource.go index 00d62f93..d544b55f 100644 --- a/apis/workload.cattle.io/v1/schema/mapper/resource.go +++ b/apis/workload.cattle.io/v1/schema/mapper/resource.go @@ -4,7 +4,7 @@ import ( "strings" "github.com/rancher/norman/types" - m "github.com/rancher/norman/types/mapping/mapper" + m "github.com/rancher/norman/types/mapper" ) type PivotMapper struct { diff --git a/apis/workload.cattle.io/v1/schema/mapper/scheduling.go b/apis/workload.cattle.io/v1/schema/mapper/scheduling.go index 5d1ddbc9..7c588667 100644 --- a/apis/workload.cattle.io/v1/schema/mapper/scheduling.go +++ b/apis/workload.cattle.io/v1/schema/mapper/scheduling.go @@ -9,7 +9,7 @@ import ( "github.com/rancher/norman/types" "github.com/rancher/norman/types/convert" - "github.com/rancher/norman/types/mapping/mapper" + "github.com/rancher/norman/types/mapper" "k8s.io/api/core/v1" ) diff --git a/apis/workload.cattle.io/v1/schema/mapper/status.go b/apis/workload.cattle.io/v1/schema/mapper/status.go new file mode 100644 index 00000000..653611f9 --- /dev/null +++ b/apis/workload.cattle.io/v1/schema/mapper/status.go @@ -0,0 +1,34 @@ +package mapper + +import ( + "github.com/rancher/norman/types" + "github.com/rancher/types/status" +) + +type Status struct { +} + +func (s Status) FromInternal(data map[string]interface{}) { + status.Set(data) +} + +func (s Status) ToInternal(data map[string]interface{}) { +} + +func (s Status) ModifySchema(schema *types.Schema, schemas *types.Schemas) error { + schema.ResourceFields["state"] = types.Field{ + Type: "string", + } + schema.ResourceFields["transitioning"] = types.Field{ + Type: "enum", + Options: []string{ + "yes", + "no", + "error", + }, + } + schema.ResourceFields["transitioningMessage"] = types.Field{ + Type: "string", + } + return nil +} diff --git a/apis/workload.cattle.io/v1/schema/mapper/workload.go b/apis/workload.cattle.io/v1/schema/mapper/workload.go new file mode 100644 index 00000000..92195755 --- /dev/null +++ b/apis/workload.cattle.io/v1/schema/mapper/workload.go @@ -0,0 +1,16 @@ +package mapper + +import ( + "github.com/rancher/norman/types" + m "github.com/rancher/norman/types/mapper" +) + +func NewWorkloadTypeMapper() types.Mapper { + return &types.Mappers{ + &m.Move{From: "labels", To: "workloadLabels"}, + &m.Move{From: "annotations", To: "workloadAnnotations"}, + &m.Move{From: "metadata/labels", To: "labels", NoDeleteFromField: true}, + &m.Move{From: "metadata/annotations", To: "annotations", NoDeleteFromField: true}, + &m.Drop{Field: "metadata"}, + } +} diff --git a/apis/workload.cattle.io/v1/schema/schema.go b/apis/workload.cattle.io/v1/schema/schema.go index 1185d3a2..a8be020b 100644 --- a/apis/workload.cattle.io/v1/schema/schema.go +++ b/apis/workload.cattle.io/v1/schema/schema.go @@ -2,9 +2,10 @@ package schema import ( "github.com/rancher/norman/types" - m "github.com/rancher/norman/types/mapping/mapper" + "github.com/rancher/norman/types/factory" + m "github.com/rancher/norman/types/mapper" + workloadv1 "github.com/rancher/types/apis/workload.cattle.io/v1" "github.com/rancher/types/apis/workload.cattle.io/v1/schema/mapper" - "github.com/rancher/types/commonmappers" "k8s.io/api/core/v1" "k8s.io/kubernetes/staging/src/k8s.io/api/apps/v1beta2" ) @@ -15,249 +16,283 @@ var ( Group: "workload.cattle.io", Path: "/v1-workload", SubContexts: map[string]bool{ - "projects": true, - "namespaces": true, + "projects": true, }, } - Schemas = commonmappers.Add(&Version, types.NewSchemas()). + Schemas = factory.Schemas(&Version). Init(podTypes). Init(namespaceTypes). Init(nodeTypes). - Init(replicaSetTypes). Init(deploymentTypes). - Init(statefulSetTypes) + Init(statefulSetTypes). + Init(replicaSet). + Init(replicationController). + Init(daemonSet). + Init(workloadTypes) ) +func workloadTypes(schemas *types.Schemas) *types.Schemas { + return schemas. + AddMapperForType(&Version, workloadv1.WorkloadSpec{}, + &m.Embed{Field: "deployConfig"}, + &m.Embed{Field: "template"}, + ). + AddMapperForType(&Version, workloadv1.Workload{}, mapper.NewWorkloadTypeMapper()). + MustImport(&Version, workloadv1.Workload{}, projectOverride{}) +} + func statefulSetTypes(schemas *types.Schemas) *types.Schemas { return schemas. - AddMapperForType(&Version, v1beta2.StatefulSetUpdateStrategy{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - m.Enum{Field: "type", - Values: map[string][]string{ - "RollingUpdate": {"rollingUpdate"}, - "OnDelete": {"onDelete"}, - }, - }, - m.Move{From: "type", To: "kind"}, - m.Move{From: "rollingUpdate", To: "rollingUpdateConfig"}, + AddMapperForType(&Version, v1beta2.StatefulSetSpec{}, + &m.Move{ + From: "replicas", + To: "scale", + DestDefined: true, }, - }). - AddMapperForType(&Version, v1beta2.StatefulSetSpec{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - &m.Move{ - From: "replicas", - To: "deploy/scale", - }, - m.Enum{Field: "podManagementPolicy", - Values: map[string][]string{ - "OrderedReady": {"ordered"}, - "Parallel": {"parallel"}, - }, - }, - &m.Move{ - From: "podManagementPolicy", - To: "deploy/strategy", - }, - &m.Move{ - From: "revisionHistoryLimit", - To: "deploy/maxRevisions", - }, - m.Drop{"selector"}, - m.SliceToMap{ - Field: "volumeClaimTemplates", - Key: "name", - }, + &m.Move{ + From: "updateStrategy/rollingUpdate/partition", + To: "deploymentStrategy/orderedConfig/partition", }, - }). - AddMapperForType(&Version, v1beta2.StatefulSet{}, m.NewObject()). + m.SetValue{ + From: "updateStrategy/type", + IfEq: "OnDelete", + Value: true, + To: "deploymentStrategy/orderedConfig/onDelete", + }, + m.SetValue{ + From: "podManagementPolicy", + IfEq: "Parallel", + Value: "Parallel", + To: "deploymentStrategy/kind", + }, + m.SetValue{ + From: "podManagementPolicy", + IfEq: "OrderedReady", + Value: "Ordered", + To: "deploymentStrategy/kind", + }, + m.Drop{Field: "selector"}, + &m.Embed{Field: "template"}, + ). + AddMapperForType(&Version, v1beta2.StatefulSet{}, mapper.NewWorkloadTypeMapper()). MustImport(&Version, v1beta2.StatefulSetSpec{}, deployOverride{}). - MustImport(&Version, v1beta2.StatefulSet{}) + MustImport(&Version, v1beta2.StatefulSet{}, projectOverride{}) +} + +func replicaSet(schemas *types.Schemas) *types.Schemas { + return schemas. + AddMapperForType(&Version, v1beta2.ReplicaSetSpec{}, + &m.Move{ + From: "replicas", + To: "scale", + DestDefined: true, + }, + &m.Move{ + From: "minReadySeconds", + To: "deploymentStrategy/parallelConfig/minReadySeconds", + }, + m.Drop{Field: "selector"}, + &m.Embed{Field: "template"}, + ). + AddMapperForType(&Version, v1beta2.ReplicaSet{}, mapper.NewWorkloadTypeMapper()). + MustImport(&Version, v1beta2.ReplicaSetSpec{}, deployOverride{}). + MustImportAndCustomize(&Version, v1beta2.ReplicaSet{}, func(schema *types.Schema) { + schema.BaseType = "workload" + }, projectOverride{}) +} + +func replicationController(schemas *types.Schemas) *types.Schemas { + return schemas. + AddMapperForType(&Version, v1.ReplicationControllerSpec{}, + &m.Move{ + From: "replicas", + To: "scale", + DestDefined: true, + }, + &m.Move{ + From: "minReadySeconds", + To: "deploymentStrategy/parallelConfig/minReadySeconds", + }, + m.Drop{Field: "selector"}, + &m.Embed{Field: "template"}, + ). + AddMapperForType(&Version, v1.ReplicationController{}, mapper.NewWorkloadTypeMapper()). + MustImport(&Version, v1.ReplicationControllerSpec{}, deployOverride{}). + MustImportAndCustomize(&Version, v1.ReplicationController{}, func(schema *types.Schema) { + schema.BaseType = "workload" + }, projectOverride{}) +} + +func daemonSet(schemas *types.Schemas) *types.Schemas { + return schemas. + AddMapperForType(&Version, v1beta2.DaemonSetSpec{}, + m.SetValue{ + From: "updateStrategy/type", + IfEq: "OnDelete", + Value: true, + To: "deploymentStrategy/globalConfig/onDelete", + }, + &m.Move{ + From: "minReadySeconds", + To: "deploymentStrategy/globalConfig/minReadySeconds", + }, + m.Drop{Field: "selector"}, + &m.Embed{Field: "template"}, + ). + AddMapperForType(&Version, v1beta2.DaemonSet{}, mapper.NewWorkloadTypeMapper()). + MustImport(&Version, v1beta2.DaemonSetSpec{}, deployOverride{}). + MustImportAndCustomize(&Version, v1beta2.DaemonSet{}, func(schema *types.Schema) { + schema.BaseType = "workload" + }, projectOverride{}) } func deploymentTypes(schemas *types.Schemas) *types.Schemas { return schemas. - AddMapperForType(&Version, v1beta2.DeploymentStrategy{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - m.Enum{Field: "type", - Values: map[string][]string{ - "RollingUpdate": {"rollingUpdate"}, - "Recreate": {"recreate"}, - }, - }, - m.Move{From: "type", To: "kind"}, - m.Move{From: "rollingUpdate", To: "rollingUpdateConfig"}, + AddMapperForType(&Version, v1beta2.DeploymentSpec{}, + &m.Move{ + From: "replicas", + To: "scale", + DestDefined: true, }, - }). - AddMapperForType(&Version, v1beta2.DeploymentSpec{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - &m.Move{ - From: "replicas", - To: "deploy/scale", - }, - &m.Move{ - From: "minReadySeconds", - To: "deploy/minReadySeconds", - }, - &m.Move{ - From: "progressDeadlineSeconds", - To: "deploy/progressDeadlineSeconds", - }, - &m.Move{ - From: "revisionHistoryLimit", - To: "deploy/maxRevisions", - }, - m.Drop{"selector"}, - m.Move{From: "strategy", To: "updateStrategy"}, + &m.Move{ + From: "minReadySeconds", + To: "deploymentStrategy/parallelConfig/minReadySeconds", }, - }). - AddMapperForType(&Version, v1beta2.Deployment{}, m.NewObject()). + &m.Move{ + From: "progressDeadlineSeconds", + To: "deploymentStrategy/parallelConfig/progressDeadlineSeconds", + }, + mapper.DeploymentStrategyMapper{}, + m.Drop{Field: "selector"}, + m.Drop{Field: "strategy"}, + &m.Embed{Field: "template"}, + ). + AddMapperForType(&Version, v1beta2.Deployment{}, mapper.NewWorkloadTypeMapper()). MustImport(&Version, v1beta2.DeploymentSpec{}, deployOverride{}). - MustImport(&Version, v1beta2.Deployment{}) -} - -func replicaSetTypes(schemas *types.Schemas) *types.Schemas { - return schemas. - AddMapperForType(&Version, v1beta2.ReplicaSetSpec{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - &m.Move{ - From: "replicas", - To: "deploy/scale", - }, - &m.Move{ - From: "minReadySeconds", - To: "deploy/minReadySeconds", - }, - m.Drop{"selector"}, - }, - }). - AddMapperForType(&Version, v1beta2.ReplicaSet{}, m.NewObject()). - MustImport(&Version, v1beta2.ReplicaSetSpec{}, deployOverride{}). - MustImport(&Version, v1beta2.ReplicaSet{}) + MustImportAndCustomize(&Version, v1beta2.Deployment{}, func(schema *types.Schema) { + schema.BaseType = "workload" + }, projectOverride{}) } func nodeTypes(schemas *types.Schemas) *types.Schemas { return schemas. - AddMapperForType(&Version, v1.NodeStatus{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - &mapper.NodeAddressMapper{}, - &mapper.OSInfo{}, - &m.Drop{"addresses"}, - &m.Drop{"conditions"}, - &m.Drop{"daemonEndpoints"}, - &m.Drop{"images"}, - &m.Drop{"nodeInfo"}, - &m.SliceToMap{Field: "volumesAttached", Key: "devicePath"}, - }, - }). - AddMapperForType(&Version, v1.Node{}, m.NewObject()). - MustImport(&Version, v1.NodeStatus{}, nodeStatusOverride{}). + AddMapperForType(&Version, v1.NodeStatus{}, + &mapper.NodeAddressMapper{}, + &mapper.OSInfo{}, + &m.Drop{Field: "addresses"}, + &m.Drop{Field: "daemonEndpoints"}, + &m.Drop{Field: "images"}, + &m.Drop{Field: "nodeInfo"}, + &m.SliceToMap{Field: "volumesAttached", Key: "devicePath"}, + ). + AddMapperForType(&Version, v1.Node{}, + mapper.Status{}, + &m.Embed{Field: "status"}, + &m.Drop{Field: "conditions"}, + ). + MustImport(&Version, v1.NodeStatus{}, struct { + IPAddress string + Hostname string + Info NodeInfo + }{}). MustImport(&Version, v1.Node{}) } + func namespaceTypes(schemas *types.Schemas) *types.Schemas { return schemas. - AddMapperForType(&Version, v1.NamespaceStatus{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - &m.Drop{"phase"}, - }, - }). - AddMapperForType(&Version, v1.NamespaceSpec{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - &m.Drop{"finalizers"}, - }, - }). - AddMapperForType(&Version, v1.Namespace{}, m.NewObject()). - MustImport(&Version, v1.Namespace{}) + AddMapperForType(&Version, v1.NamespaceStatus{}, + &m.Drop{Field: "phase"}, + ). + AddMapperForType(&Version, v1.NamespaceSpec{}, + &m.Drop{Field: "finalizers"}, + ). + AddMapperForType(&Version, v1.Namespace{}, + &m.LabelField{Field: "projectId"}, + ). + MustImport(&Version, v1.Namespace{}, projectOverride{}, struct { + Templates map[string]string + Answers map[string]interface{} + Prune bool + ExternalID string + Tags []string + }{}) } func podTypes(schemas *types.Schemas) *types.Schemas { return schemas. - AddMapperForType(&Version, v1.Capabilities{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - m.Move{From: "add", To: "capAdd"}, - m.Move{From: "drop", To: "capDrop"}, - }, - }). - AddMapperForType(&Version, v1.PodSecurityContext{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - m.Drop{"seLinuxOptions"}, - m.Move{From: "runAsUser", To: "uid"}, - m.Move{From: "supplementalGroups", To: "gids"}, - m.Move{From: "fsGroup", To: "fsgid"}, - }, - }). - AddMapperForType(&Version, v1.SecurityContext{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - &m.Embed{Field: "capabilities"}, - m.Drop{"seLinuxOptions"}, - m.Move{From: "readOnlyRootFilesystem", To: "readOnly"}, - m.Move{From: "runAsUser", To: "uid"}, - }, - }). - AddMapperForType(&Version, v1.Container{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - m.Move{"command", "entrypoint"}, - m.Move{"args", "command"}, - m.Move{"livenessProbe", "healthcheck"}, - m.Move{"readinessProbe", "readycheck"}, - m.Move{"imagePullPolicy", "pullPolicy"}, - mapper.EnvironmentMapper{}, - &m.Embed{Field: "securityContext"}, - &m.Embed{Field: "lifecycle"}, - }, - }). - AddMapperForType(&Version, v1.ContainerPort{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - m.Drop{"name"}, - }, - }). - AddMapperForType(&Version, v1.VolumeMount{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - m.Enum{ - Field: "mountPropagation", - Values: map[string][]string{ - "HostToContainer": []string{"rslave"}, - "Bidirectional": []string{"rshared", "shared"}, - }, + AddMapperForType(&Version, v1.PodTemplateSpec{}, + &m.Embed{Field: "spec"}, + ). + AddMapperForType(&Version, v1.Capabilities{}, + m.Move{From: "add", To: "capAdd"}, + m.Move{From: "drop", To: "capDrop"}, + ). + AddMapperForType(&Version, v1.PodSecurityContext{}, + m.Drop{Field: "seLinuxOptions"}, + m.Move{From: "runAsUser", To: "uid"}, + m.Move{From: "supplementalGroups", To: "gids"}, + m.Move{From: "fsGroup", To: "fsgid"}, + ). + AddMapperForType(&Version, v1.SecurityContext{}, + &m.Embed{Field: "capabilities"}, + m.Drop{Field: "seLinuxOptions"}, + m.Move{From: "readOnlyRootFilesystem", To: "readOnly"}, + m.Move{From: "runAsUser", To: "uid"}, + ). + AddMapperForType(&Version, v1.Container{}, + m.Move{From: "command", To: "entrypoint"}, + m.Move{From: "args", To: "command"}, + m.Move{From: "livenessProbe", To: "healthcheck"}, + m.Move{From: "readinessProbe", To: "readycheck"}, + m.Move{From: "imagePullPolicy", To: "pullPolicy"}, + mapper.EnvironmentMapper{}, + &m.Embed{Field: "securityContext"}, + &m.Embed{Field: "lifecycle"}, + ). + AddMapperForType(&Version, v1.ContainerPort{}, + m.Drop{Field: "name"}, + ). + AddMapperForType(&Version, v1.VolumeMount{}, + m.Enum{ + Field: "mountPropagation", + Values: map[string][]string{ + "HostToContainer": {"rslave"}, + "Bidirectional": {"rshared", "shared"}, }, }, - }). + ). AddMapperForType(&Version, v1.Handler{}, handlerMapper). AddMapperForType(&Version, v1.Probe{}, handlerMapper). - AddMapperForType(&Version, v1.PodSpec{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - m.Move{From: "restartPolicy", To: "restart"}, - m.Move{From: "imagePullSecrets", To: "pullSecrets"}, - mapper.NamespaceMapper{}, - mapper.InitContainerMapper{}, - mapper.SchedulingMapper{}, - &m.Embed{Field: "securityContext"}, - &m.SliceToMap{ - Field: "volumes", - Key: "name", - }, - &m.SliceToMap{ - Field: "containers", - Key: "name", - }, - &m.SliceToMap{ - Field: "hostAliases", - Key: "ip", - }, + AddMapperForType(&Version, v1.PodStatus{}, + m.Move{From: "hostIP", To: "nodeIp"}, + m.Move{From: "podIP", To: "podIp"}, + ). + AddMapperForType(&Version, v1.PodSpec{}, + m.Move{From: "restartPolicy", To: "restart"}, + m.Move{From: "imagePullSecrets", To: "pullSecrets"}, + mapper.NamespaceMapper{}, + mapper.InitContainerMapper{}, + mapper.SchedulingMapper{}, + &m.Embed{Field: "securityContext"}, + &m.Drop{Field: "serviceAccount"}, + &m.SliceToMap{ + Field: "volumes", + Key: "name", }, - }). - AddMapperForType(&Version, v1.Pod{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - &m.Drop{"status"}, - &m.Embed{Field: "metadata"}, - &m.Embed{Field: "spec"}, + &m.SliceToMap{ + Field: "containers", + Key: "name", }, - }). - AddMapperForType(&Version, v1.ResourceRequirements{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - mapper.PivotMapper{Plural: true}, + &m.SliceToMap{ + Field: "hostAliases", + Key: "ip", }, - }). + ). + AddMapperForType(&Version, v1.ResourceRequirements{}, + mapper.PivotMapper{Plural: true}, + ). + AddMapperForType(&Version, v1.Pod{}, mapper.Status{}). // Must import handlers before Container MustImport(&Version, v1.Handler{}, handlerOverride{}). MustImport(&Version, v1.Probe{}, handlerOverride{}). @@ -269,9 +304,12 @@ func podTypes(schemas *types.Schemas) *types.Schemas { InitContainer bool }{}). MustImport(&Version, v1.PodSpec{}, struct { - Net string - PID string - IPC string + NodeName string `norman:"type=reference[node]"` + Net string + PID string + IPC string }{}). - MustImport(&Version, v1.Pod{}) + MustImport(&Version, v1.Pod{}, projectOverride{}, struct { + WorkloadID string `norman:"type=reference[workload]"` + }{}) } diff --git a/apis/workload.cattle.io/v1/schema/types.go b/apis/workload.cattle.io/v1/schema/types.go index b41503bd..4ad69b9e 100644 --- a/apis/workload.cattle.io/v1/schema/types.go +++ b/apis/workload.cattle.io/v1/schema/types.go @@ -2,28 +2,25 @@ package schema import ( "github.com/rancher/norman/types" - m "github.com/rancher/norman/types/mapping/mapper" + m "github.com/rancher/norman/types/mapper" + "github.com/rancher/types/apis/workload.cattle.io/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) var ( - handlerMapper = &types.TypeMapper{ - Mappers: []types.Mapper{ - &m.UnionEmbed{ - Fields: []m.UnionMapping{ - { - FieldName: "exec", - CheckFields: []string{"command"}, - }, - { - FieldName: "tcpSocket", - CheckFields: []string{"tcp", "port"}, - }, - { - FieldName: "httpGet", - CheckFields: []string{"port"}, - }, - }, + handlerMapper = &m.UnionEmbed{ + Fields: []m.UnionMapping{ + { + FieldName: "exec", + CheckFields: []string{"command"}, + }, + { + FieldName: "tcpSocket", + CheckFields: []string{"tcp", "port"}, + }, + { + FieldName: "httpGet", + CheckFields: []string{"port"}, }, }, } @@ -76,22 +73,6 @@ type NodeScheduling struct { Preferred []string } -type deployParams struct { - BatchSize int64 - Scale int64 - Global bool - Cron string - Job bool - Ordered bool - QuorumSize int64 -} - -type nodeStatusOverride struct { - IPAddress string - Hostname string - Info NodeInfo -} - type NodeInfo struct { CPU CPUInfo Memory MemoryInfo @@ -118,9 +99,11 @@ type KubernetesInfo struct { KubeProxyVersion string } -type DeployParams struct { +type deployOverride struct { + v1.DeployConfig } -type deployOverride struct { - Deploy *DeployParams +type projectOverride struct { + types.Namespaced + ProjectID string `norman:"type=reference[/v1-authz/schemas/project]"` } diff --git a/apis/workload.cattle.io/v1/types.go b/apis/workload.cattle.io/v1/types.go new file mode 100644 index 00000000..0f9f0609 --- /dev/null +++ b/apis/workload.cattle.io/v1/types.go @@ -0,0 +1,56 @@ +package v1 + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type WorkloadSpec struct { + DeployConfig DeployConfig + Template v1.PodTemplateSpec +} + +type WorkloadStatus struct { +} + +type Workload struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec WorkloadSpec `json:"spec"` + Status *WorkloadStatus `json:"status"` +} + +type DeployConfig struct { + Scale int64 + BatchSize string + DeploymentStrategy *DeployStrategy +} + +type DeploymentParallelConfig struct { + StartFirst bool + MinReadySeconds int64 + ProgressDeadlineSeconds int64 +} + +type DeploymentJobConfig struct { + BatchLimit int64 + ActiveDeadlineSeconds int64 + OnDelete bool +} + +type DeploymentOrderedConfig struct { + PartitionSize int64 + OnDelete bool +} + +type DeploymentGlobalConfig struct { + OnDelete bool +} + +type DeployStrategy struct { + Kind string + ParallelConfig *DeploymentParallelConfig + JobConfig *DeploymentJobConfig + OrderedConfig *DeploymentOrderedConfig + GlobalConfig *DeploymentGlobalConfig +} diff --git a/commonmappers/setup.go b/commonmappers/setup.go deleted file mode 100644 index d75a18a3..00000000 --- a/commonmappers/setup.go +++ /dev/null @@ -1,28 +0,0 @@ -package commonmappers - -import ( - "github.com/rancher/norman/types" - m "github.com/rancher/norman/types/mapping/mapper" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func Add(version *types.APIVersion, schemas *types.Schemas) *types.Schemas { - return schemas. - AddMapperForType(version, metav1.ObjectMeta{}, &types.TypeMapper{ - Mappers: []types.Mapper{ - m.Drop{"generateName"}, - m.Drop{"selfLink"}, - m.Move{From: "uid", To: "uuid"}, - m.Drop{"resourceVersion"}, - m.Drop{"generation"}, - m.Move{From: "creationTimestamp", To: "created"}, - m.Move{From: "deletionTimestamp", To: "removed"}, - m.Drop{"deletionGracePeriodSeconds"}, - //DeletionGracePeriodSecondsMapper{}, - m.Drop{"initializers"}, - m.Drop{"finalizers"}, - m.Drop{"clusterName"}, - m.Drop{"ownerReferences"}, - }, - }) -} diff --git a/generator/cleanup/main.go b/generator/cleanup/main.go new file mode 100644 index 00000000..b68d01e6 --- /dev/null +++ b/generator/cleanup/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +func main() { + if err := run(); err != nil { + panic(err) + } +} + +func run() error { + return filepath.Walk("../..", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if strings.Contains(path, "vendor") { + return filepath.SkipDir + } + + if strings.HasPrefix(info.Name(), "zz_generated") { + fmt.Println("Removing", path) + if err := os.Remove(path); err != nil { + return err + } + } + + return nil + }) +} diff --git a/main.go b/main.go index 33c47c73..63498f3c 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,4 @@ +//go:generate go run generator/cleanup/main.go //go:generate go run main.go package main diff --git a/status/status.go b/status/status.go new file mode 100644 index 00000000..7677a339 --- /dev/null +++ b/status/status.go @@ -0,0 +1,172 @@ +package status + +import ( + "strings" + + "github.com/rancher/norman/types/convert" + "github.com/rancher/norman/types/mapper" +) + +type conditionMapping struct { + Name string + State string + Transition bool + Error bool + FalseIsGood bool +} + +type condition struct { + Type string + Status string + Message string +} + +var conditionMappings = []conditionMapping{ + { + Name: "Initialized", + Transition: true, + State: "initializing", + }, + { + Name: "Ready", + Transition: true, + State: "activating", + }, + { + Name: "Available", + Transition: true, + State: "activating", + }, + { + Name: "Progressing", + Transition: true, + State: "updating", + }, + { + Name: "ConfigOK", + Transition: true, + State: "configuring", + }, + { + Name: "PodScheduled", + Transition: true, + State: "scheduling", + }, + { + Name: "Completed", + State: "completed", + }, + { + Name: "Failed", + Error: true, + State: "error", + }, + { + Name: "OutOfDisk", + Error: true, + FalseIsGood: true, + }, + { + Name: "MemoryPressure", + Error: true, + FalseIsGood: true, + }, + { + Name: "DiskPressure", + Error: true, + FalseIsGood: true, + }, + { + Name: "NetworkUnavailable", + Error: true, + }, + { + Name: "Unschedulable", + Error: true, + FalseIsGood: true, + }, + { + Name: "ReplicaFailure", + Error: true, + FalseIsGood: true, + }, +} + +func Set(data map[string]interface{}) { + val, ok := mapper.GetValue(data, "status", "conditions") + if !ok || val == nil { + return + } + + var conditions []condition + if err := convert.ToObj(val, &conditions); err != nil { + // ignore error + return + } + + conditionMap := map[string]condition{} + for _, c := range conditions { + conditionMap[c.Type] = condition{ + Status: c.Status, + Message: c.Message, + } + } + + state := "" + error := false + transitioning := false + message := "" + + for _, conditionMapping := range conditionMappings { + good := true + condition, ok := conditionMap[conditionMapping.Name] + if !ok { + continue + } + + if conditionMapping.FalseIsGood && condition.Status == "True" { + good = false + } else if !conditionMapping.FalseIsGood && condition.Status == "False" { + good = false + } + + if !good && conditionMapping.Transition { + transitioning = true + } + + if !good && state == "" && conditionMapping.State != "" { + state = conditionMapping.State + } + + if !good && conditionMapping.Error { + error = true + if len(message) > 0 { + message = strings.Join([]string{message, condition.Message}, ",") + } else { + message = condition.Message + } + } + } + + if state == "" { + val, _ := mapper.GetValueN(data, "status", "phase").(string) + if val != "" { + state = val + } + } + + if state == "" { + state = "active" + } + + data["state"] = strings.ToLower(state) + if error { + data["transitioning"] = "error" + } else if transitioning { + data["transitioning"] = "yes" + } else { + data["transitioning"] = "no" + } + + data["transitioningMessage"] = message +}