Преглед изворни кода

simplify logic using strict types

Feroze Mohideen пре 2 година
родитељ
комит
0e094a63d4
2 измењених фајлова са 229 додато и 332 уклоњено
  1. 170 0
      internal/porter_app/v1/types.go
  2. 59 332
      internal/porter_app/v1/yaml.go

+ 170 - 0
internal/porter_app/v1/types.go

@@ -0,0 +1,170 @@
+package v1
+
+type v1_ServiceConfig struct {
+	// Autoscaling contains all configuration for autoscaling.  If enabled, ReplicaCount is ignored.
+	Autoscaling *Autoscaling `yaml:"autoscaling,omitempty" validate:"excluded_if=Type job"`
+	// Container contains configuration for Kubernetes container spec
+	Container Container `yaml:"container"`
+	// Health contains configuration for Kubernetes health probes
+	Health *Health `yaml:"health,omitempty" validate:"excluded_unless=Type web"`
+	// Ingress contains all configuration for ingress
+	Ingress Ingress `yaml:"ingress"`
+	// ReplicaCount is the number of replicas to run. Ignored if Autoscaling is enabled.
+	ReplicaCount string `yaml:"replicaCount"`
+	// Resources contains all configuration for resources requests
+	Resources Resources `yaml:"resources"`
+	// Service contains all configuration for the Kubernetes Service associated with the chart
+	Service Service `yaml:"service"`
+	// Labels contains all the labels to be included in controller specs
+	Labels map[string]string `yaml:"labels"`
+	// PodLabels contains all the labels to be included in pod specs
+	PodLabels map[string]string `yaml:"podLabels"`
+	// AllowConcurrent allows multiple instances of the job to run at the same time
+	AllowConcurrency bool `yaml:"allowConcurrent" validate:"excluded_unless=Type job"`
+	// Schedule is the cron schedule for the job
+	Schedule Schedule `yaml:"schedule" validate:"excluded_unless=Type job"`
+}
+
+// Schedule contains all configuration for job schedules
+type Schedule struct {
+	// Enabled specifies whether or not to use a schedule
+	Enabled bool `yaml:"enabled"`
+	// Value is the cron schedule
+	Value string `yaml:"value,omitempty"`
+}
+
+// Autoscaling contains all configuration for autoscaling in a web/worker chart.  If enabled, ReplicaCount is ignored.
+type Autoscaling struct {
+	// Enabled specifies whether or not to use autoscaling
+	Enabled bool `yaml:"enabled"`
+	// MaxReplicas is the maximum number of replicas to scale to
+	MaxReplicas string `yaml:"maxReplicas"`
+	// MinReplicas is the minimum number of replicas to scale to
+	MinReplicas string `yaml:"minReplicas"`
+	// TargetCPUUtilizationPercentage is the target CPU utilization percentage to scale on
+	TargetCPUUtilizationPercentage string `yaml:"targetCPUUtilizationPercentage"`
+	// TargetMemoryUtilizationPercentage is the target memory utilization percentage to scale on
+	TargetMemoryUtilizationPercentage string `yaml:"targetMemoryUtilizationPercentage"`
+}
+
+// Container contains all configuration for containers
+type Container struct {
+	// Command is the command to run in the container
+	Command string `yaml:"command"`
+	// Env contains the environment variables for the container
+	Env ContainerEnv `yaml:"env"`
+	// Port is the port that the container exposes
+	Port string `yaml:"port"`
+}
+
+// ContainerEnv represents the environment variables for a container
+type ContainerEnv struct {
+	// Normal represents the service-specific environment variables (as opposed to environment variables from synced env groups)
+	Normal map[string]string `yaml:"normal"`
+}
+
+// Health contains user-configurable health probes
+type Health struct {
+	// LivenessProbe checks whether a container should be considered healthy
+	LivenessProbe LivenessProbe `yaml:"livenessProbe"`
+	// ReadinessProbe checks whether a container should be considered ready to receive traffic
+	ReadinessProbe ReadinessProbe `yaml:"readinessProbe"`
+}
+
+// LivenessProbe contains user-configurable values for a liveness probe
+type LivenessProbe struct {
+	// Enabled specifies whether or not to use a liveness probe
+	Enabled bool `yaml:"enabled"`
+	// Path is the endpoint path to use for the probe
+	Path string `yaml:"path"`
+}
+
+// ReadinessProbe contains user-configurable values for a readiness probe
+type ReadinessProbe struct {
+	// Enabled specifies whether or not to use a readiness probe
+	Enabled bool `yaml:"enabled"`
+	// Path is the endpoint path to use for the probe
+	Path string `yaml:"path"`
+}
+
+// Image contains configuration for images
+type Image struct {
+	// Repository is url of the image repository where the image should be pulled from
+	Repository string `yaml:"repository"`
+	// Tag is the tag of the image to pull
+	Tag string `yaml:"tag"`
+}
+
+// Ingress contains configuration for ingress used by web charts
+type Ingress struct {
+	// Enabled specifies whether or not to use an ingress
+	Enabled bool `yaml:"enabled"`
+	// Hosts specifies the domains to include in the routing rules. If Ingress is enabled, hosts must not be empty.
+	Hosts []string `yaml:"hosts"`
+}
+
+// Resources is a wrapper over requests
+type Resources struct {
+	// Requests contains configuration for resource requests
+	Requests Requests `yaml:"requests"`
+}
+
+// Requests contains configuration for resource requests
+type Requests struct {
+	// Cpu is the cpu request (e.g. 100m - m for millicores)
+	Cpu string `yaml:"cpu"`
+	// Memory is the memory request (e.g. 100Mi - Mi for mebibytes)
+	Memory string `yaml:"memory"`
+}
+
+// Service contains configuration for exposing services
+type Service struct {
+	// Port is the port to expose the service on. This port should match the port in the container.
+	Port string `yaml:"port"`
+}
+
+type v1_PorterYAML struct {
+	Applications map[string]*Application `yaml:"applications" validate:"required_without=Services Apps"`
+	Version      *string                 `yaml:"version"`
+	Build        *Build                  `yaml:"build"`
+	Env          map[string]string       `yaml:"env"`
+	SyncedEnv    []*SyncedEnvSection     `yaml:"synced_env"`
+	Apps         map[string]v1_Service   `yaml:"apps" validate:"required_without=Applications Services"`
+	Services     map[string]v1_Service   `yaml:"services" validate:"required_without=Applications Apps"`
+
+	Release *v1_Service `yaml:"release"`
+}
+
+type Application struct {
+	Services map[string]v1_Service `yaml:"services" validate:"required"`
+	Build    *Build                `yaml:"build"`
+	Env      map[string]string     `yaml:"env"`
+
+	Release *v1_Service `yaml:"release"`
+}
+
+type Build struct {
+	Context    string   `yaml:"context" validate:"dir"`
+	Method     string   `yaml:"method" validate:"required,oneof=pack docker registry"`
+	Builder    string   `yaml:"builder" validate:"required_if=Method pack"`
+	Buildpacks []string `yaml:"buildpacks"`
+	Dockerfile string   `yaml:"dockerfile" validate:"required_if=Method docker"`
+	Image      string   `yaml:"image" validate:"required_if=Method registry"`
+}
+
+type v1_Service struct {
+	Run    string           `yaml:"run"`
+	Config v1_ServiceConfig `yaml:"config"`
+	Type   string           `yaml:"type" validate:"required, oneof=web worker job"`
+}
+
+type SyncedEnvSection struct {
+	Name    string                `json:"name" yaml:"name"`
+	Version uint                  `json:"version" yaml:"version"`
+	Keys    []SyncedEnvSectionKey `json:"keys" yaml:"keys"`
+}
+
+type SyncedEnvSectionKey struct {
+	Name   string `json:"name" yaml:"name"`
+	Secret bool   `json:"secret" yaml:"secret"`
+}

+ 59 - 332
internal/porter_app/v1/yaml.go

@@ -22,7 +22,7 @@ func AppProtoFromYaml(ctx context.Context, porterYamlBytes []byte) (*porterv1.Po
 		return nil, telemetry.Error(ctx, span, nil, "porter yaml is nil")
 		return nil, telemetry.Error(ctx, span, nil, "porter yaml is nil")
 	}
 	}
 
 
-	porterYaml := &PorterStackYAML{}
+	porterYaml := &v1_PorterYAML{}
 	err := yaml.Unmarshal(porterYamlBytes, porterYaml)
 	err := yaml.Unmarshal(porterYamlBytes, porterYaml)
 	if err != nil {
 	if err != nil {
 		return nil, telemetry.Error(ctx, span, err, "error unmarshaling porter yaml")
 		return nil, telemetry.Error(ctx, span, err, "error unmarshaling porter yaml")
@@ -59,7 +59,7 @@ func AppProtoFromYaml(ctx context.Context, porterYamlBytes []byte) (*porterv1.Po
 	if porterYaml.Apps != nil && porterYaml.Services != nil {
 	if porterYaml.Apps != nil && porterYaml.Services != nil {
 		return nil, telemetry.Error(ctx, span, nil, "'apps' and 'services' are synonymous but both were defined")
 		return nil, telemetry.Error(ctx, span, nil, "'apps' and 'services' are synonymous but both were defined")
 	}
 	}
-	var services map[string]Service
+	var services map[string]v1_Service
 	if porterYaml.Apps != nil {
 	if porterYaml.Apps != nil {
 		services = porterYaml.Apps
 		services = porterYaml.Apps
 	}
 	}
@@ -99,53 +99,7 @@ func AppProtoFromYaml(ctx context.Context, porterYamlBytes []byte) (*porterv1.Po
 	return appProto, nil
 	return appProto, nil
 }
 }
 
 
-type PorterStackYAML struct {
-	Applications map[string]*Application `yaml:"applications" validate:"required_without=Services Apps"`
-	Version      *string                 `yaml:"version"`
-	Build        *Build                  `yaml:"build"`
-	Env          map[string]string       `yaml:"env"`
-	SyncedEnv    []*SyncedEnvSection     `yaml:"synced_env"`
-	Apps         map[string]Service      `yaml:"apps" validate:"required_without=Applications Services"`
-	Services     map[string]Service      `yaml:"services" validate:"required_without=Applications Apps"`
-
-	Release *Service `yaml:"release"`
-}
-
-type Application struct {
-	Services map[string]Service `yaml:"services" validate:"required"`
-	Build    *Build             `yaml:"build"`
-	Env      map[string]string  `yaml:"env"`
-
-	Release *Service `yaml:"release"`
-}
-
-type Build struct {
-	Context    string   `yaml:"context" validate:"dir"`
-	Method     string   `yaml:"method" validate:"required,oneof=pack docker registry"`
-	Builder    string   `yaml:"builder" validate:"required_if=Method pack"`
-	Buildpacks []string `yaml:"buildpacks"`
-	Dockerfile string   `yaml:"dockerfile" validate:"required_if=Method docker"`
-	Image      string   `yaml:"image" validate:"required_if=Method registry"`
-}
-
-type Service struct {
-	Run    string                 `yaml:"run"`
-	Config map[string]interface{} `yaml:"config"`
-	Type   string                 `yaml:"type" validate:"required, oneof=web worker job"`
-}
-
-type SyncedEnvSection struct {
-	Name    string                `json:"name" yaml:"name"`
-	Version uint                  `json:"version" yaml:"version"`
-	Keys    []SyncedEnvSectionKey `json:"keys" yaml:"keys"`
-}
-
-type SyncedEnvSectionKey struct {
-	Name   string `json:"name" yaml:"name"`
-	Secret bool   `json:"secret" yaml:"secret"`
-}
-
-func protoEnumFromType(name string, service Service) (porterv1.ServiceType, error) {
+func protoEnumFromType(name string, service v1_Service) (porterv1.ServiceType, error) {
 	var serviceType porterv1.ServiceType
 	var serviceType porterv1.ServiceType
 
 
 	if service.Type != "" {
 	if service.Type != "" {
@@ -181,31 +135,18 @@ func protoEnumFromType(name string, service Service) (porterv1.ServiceType, erro
 	return serviceType, errors.New("no type provided and could not parse service type from name")
 	return serviceType, errors.New("no type provided and could not parse service type from name")
 }
 }
 
 
-func serviceProtoFromConfig(service Service, serviceType porterv1.ServiceType) (*porterv1.Service, error) {
-	if service.Config != nil {
-		service.Config = convertMap(service.Config).(map[string]interface{})
-	}
-
-	var instances int
-	if service.Config != nil && service.Config["replicaCount"] != nil {
-		parsedInstancesInt, err := convertToInt(service.Config["replicaCount"])
-		if err != nil {
-			return nil, fmt.Errorf("error converting instances: %w", err)
-		}
-		instances = parsedInstancesInt
+func serviceProtoFromConfig(service v1_Service, serviceType porterv1.ServiceType) (*porterv1.Service, error) {
+	serviceProto := &porterv1.Service{
+		Run:  service.Run,
+		Type: serviceType,
 	}
 	}
 
 
-	var cpuCores float32
-	var ramMegabytes int
-
-	requestsMap, err := getNestedMap(service.Config, "resources", "requests")
-	if err == nil && requestsMap != nil {
-		parsedCpuCores := requestsMap["cpu"]
-		cpuCoresStr, ok := parsedCpuCores.(string)
-		if !ok {
-			return nil, fmt.Errorf("cpu is not a string")
-		}
+	// if the revision number cannot be converted, it will default to 0
+	replicaCount, _ := strconv.Atoi(service.Config.ReplicaCount)
+	serviceProto.Instances = int32(replicaCount)
 
 
+	if service.Config.Resources.Requests.Cpu != "" {
+		cpuCoresStr := service.Config.Resources.Requests.Cpu
 		if !strings.HasSuffix(cpuCoresStr, "m") {
 		if !strings.HasSuffix(cpuCoresStr, "m") {
 			return nil, fmt.Errorf("cpu is not in millicores")
 			return nil, fmt.Errorf("cpu is not in millicores")
 		}
 		}
@@ -215,94 +156,29 @@ func serviceProtoFromConfig(service Service, serviceType porterv1.ServiceType) (
 		if err != nil {
 		if err != nil {
 			return nil, fmt.Errorf("cpu is not a float")
 			return nil, fmt.Errorf("cpu is not a float")
 		}
 		}
-		cpuCores = float32(cpuCoresFloat64) / 1000
-
-		parsedRamMegabytes := requestsMap["memory"]
-		ramMegabytesStr, ok := parsedRamMegabytes.(string)
-		if !ok {
-			return nil, fmt.Errorf("memory is not a string")
-		}
-
-		if !strings.HasSuffix(ramMegabytesStr, "Mi") {
-			return nil, fmt.Errorf("memory is not in Mi")
-		}
-
-		ramMegabytesStr = strings.TrimSuffix(ramMegabytesStr, "Mi")
-		ramMegabytesInt, err := strconv.Atoi(ramMegabytesStr)
-		if err != nil {
-			return nil, fmt.Errorf("memory is not an int")
-		}
-		ramMegabytes = ramMegabytesInt
+		serviceProto.CpuCores = float32(cpuCoresFloat64) / 1000
 	}
 	}
 
 
-	var port int
-	containerMap, err := getNestedMap(service.Config, "container")
-	if err == nil && containerMap != nil {
-		parsedPort := containerMap["port"]
-		portStr, ok := parsedPort.(string)
-		if !ok {
-			return nil, fmt.Errorf("port is not a string")
+	if service.Config.Resources.Requests.Memory != "" {
+		memoryStr := service.Config.Resources.Requests.Memory
+		if !strings.HasSuffix(memoryStr, "Mi") {
+			return nil, fmt.Errorf("memory is not in Mi")
 		}
 		}
 
 
-		portInt, err := strconv.Atoi(portStr)
+		memoryStr = strings.TrimSuffix(memoryStr, "Mi")
+		memoryFloat64, err := strconv.ParseFloat(memoryStr, 32)
 		if err != nil {
 		if err != nil {
-			return nil, fmt.Errorf("port is not an int")
+			return nil, fmt.Errorf("memory is not a float")
 		}
 		}
-
-		port = portInt
+		serviceProto.RamMegabytes = int32(memoryFloat64)
 	}
 	}
 
 
-	autoscalingMap, err := getNestedMap(service.Config, "autoscaling")
-	autoscalingExists := err == nil && autoscalingMap != nil
-	var autoscalingEnabled bool
-	var autoscalingMinInstances int
-	var autoscalingMaxInstances int
-	var autoscalingCpuThresholdPercent int
-	var autoscalingMemoryThresholdPercent int
-	if autoscalingExists {
-		parsedEnabled := autoscalingMap["enabled"]
-		parsedEnabledBool, err := convertToBool(parsedEnabled)
+	if service.Config.Container.Port != "" {
+		port, err := strconv.Atoi(service.Config.Container.Port)
 		if err != nil {
 		if err != nil {
-			return nil, fmt.Errorf("error converting autoscaling enabled: %w", err)
+			return nil, fmt.Errorf("invalid port '%s'", service.Config.Container.Port)
 		}
 		}
-		autoscalingEnabled = parsedEnabledBool
-
-		parsedMinInstances := autoscalingMap["minReplicas"]
-		parsedMinInstancesInt, err := convertToInt(parsedMinInstances)
-		if err != nil {
-			return nil, fmt.Errorf("error converting autoscaling min instances: %w", err)
-		}
-		autoscalingMinInstances = parsedMinInstancesInt
-
-		parsedMaxInstances := autoscalingMap["maxReplicas"]
-		parsedMaxInstancesInt, err := convertToInt(parsedMaxInstances)
-		if err != nil {
-			return nil, fmt.Errorf("error converting autoscaling max instances: %w", err)
-		}
-		autoscalingMaxInstances = parsedMaxInstancesInt
-
-		parsedCpuThresholdPercent := autoscalingMap["targetCPUUtilizationPercentage"]
-		parsedCpuThresholdPercentInt, err := convertToInt(parsedCpuThresholdPercent)
-		if err != nil {
-			return nil, fmt.Errorf("error converting autoscaling cpu threshold percent: %w", err)
-		}
-		autoscalingCpuThresholdPercent = parsedCpuThresholdPercentInt
-
-		parsedMemoryThresholdPercent := autoscalingMap["targetMemoryUtilizationPercentage"]
-		parsedMemoryThresholdPercentInt, err := convertToInt(parsedMemoryThresholdPercent)
-		if err != nil {
-			return nil, fmt.Errorf("error converting autoscaling memory threshold percent: %w", err)
-		}
-		autoscalingMemoryThresholdPercent = parsedMemoryThresholdPercentInt
-	}
-
-	serviceProto := &porterv1.Service{
-		Run:          service.Run,
-		Type:         serviceType,
-		Instances:    int32(instances),
-		CpuCores:     cpuCores,
-		RamMegabytes: int32(ramMegabytes),
-		Port:         int32(port),
+		serviceProto.Port = int32(port)
 	}
 	}
 
 
 	switch serviceType {
 	switch serviceType {
@@ -314,81 +190,40 @@ func serviceProtoFromConfig(service Service, serviceType porterv1.ServiceType) (
 		webConfig := &porterv1.WebServiceConfig{}
 		webConfig := &porterv1.WebServiceConfig{}
 
 
 		var autoscaling *porterv1.Autoscaling
 		var autoscaling *porterv1.Autoscaling
-		if autoscalingExists && autoscalingEnabled {
+		if service.Config.Autoscaling != nil && service.Config.Autoscaling.Enabled {
 			autoscaling = &porterv1.Autoscaling{
 			autoscaling = &porterv1.Autoscaling{
-				Enabled:                autoscalingEnabled,
-				MinInstances:           int32(autoscalingMinInstances),
-				MaxInstances:           int32(autoscalingMaxInstances),
-				CpuThresholdPercent:    int32(autoscalingCpuThresholdPercent),
-				MemoryThresholdPercent: int32(autoscalingMemoryThresholdPercent),
+				Enabled: service.Config.Autoscaling.Enabled,
 			}
 			}
+			minReplicas, _ := strconv.Atoi(service.Config.Autoscaling.MinReplicas)
+			autoscaling.MinInstances = int32(minReplicas)
+			maxReplicas, _ := strconv.Atoi(service.Config.Autoscaling.MaxReplicas)
+			autoscaling.MaxInstances = int32(maxReplicas)
+			cpuThresholdPercent, _ := strconv.Atoi(service.Config.Autoscaling.TargetCPUUtilizationPercentage)
+			autoscaling.CpuThresholdPercent = int32(cpuThresholdPercent)
+			memoryThresholdPercent, _ := strconv.Atoi(service.Config.Autoscaling.TargetMemoryUtilizationPercentage)
+			autoscaling.MemoryThresholdPercent = int32(memoryThresholdPercent)
 		}
 		}
 		webConfig.Autoscaling = autoscaling
 		webConfig.Autoscaling = autoscaling
 
 
-		var healthCheckEnabled bool
-		var healthCheckHttpPath string
-
-		// note that we are only reading from the readiness probe config, since readiness and liveness share the same config now
-		readinessProbeMap, err := getNestedMap(service.Config, "health", "readinessProbe")
-		healthCheckExists := err == nil && readinessProbeMap != nil
-		if healthCheckExists {
-			parsedHealthCheckEnabled := readinessProbeMap["enabled"]
-			parsedHealthCheckEnabledBool, err := convertToBool(parsedHealthCheckEnabled)
-			if err != nil {
-				return nil, fmt.Errorf("error converting health check enabled: %w", err)
-			}
-			healthCheckEnabled = parsedHealthCheckEnabledBool
-
-			parsedHealthCheckHttpPath := readinessProbeMap["path"]
-			parsedHealthCheckHttpPathStr, err := convertToString(parsedHealthCheckHttpPath)
-			if err != nil {
-				return nil, fmt.Errorf("error converting health check http path: %w", err)
-			}
-			healthCheckHttpPath = parsedHealthCheckHttpPathStr
-		}
-
 		var healthCheck *porterv1.HealthCheck
 		var healthCheck *porterv1.HealthCheck
-		if healthCheckExists {
+		// note that we are only reading from the readiness probe config, since readiness and liveness share the same config now
+		if service.Config.Health != nil {
 			healthCheck = &porterv1.HealthCheck{
 			healthCheck = &porterv1.HealthCheck{
-				Enabled:  healthCheckEnabled,
-				HttpPath: healthCheckHttpPath,
+				Enabled:  service.Config.Health.ReadinessProbe.Enabled,
+				HttpPath: service.Config.Health.ReadinessProbe.Path,
 			}
 			}
 		}
 		}
 		webConfig.HealthCheck = healthCheck
 		webConfig.HealthCheck = healthCheck
 
 
-		ingressMap, err := getNestedMap(service.Config, "ingress")
-		ingressExists := err == nil && ingressMap != nil
-		var ingressEnabled bool
-		if ingressExists {
-			parsedIngressEnabled := ingressMap["enabled"]
-			parsedIngressEnabledBool, err := convertToBool(parsedIngressEnabled)
-			if err != nil {
-				return nil, fmt.Errorf("error converting ingress enabled: %w", err)
-			}
-			ingressEnabled = parsedIngressEnabledBool
-		}
-		webConfig.Private = !ingressEnabled
-
-		if ingressExists && ingressEnabled {
-			domains := make([]*porterv1.Domain, 0)
-			customDomains := ingressMap["hosts"]
-			if customDomains != nil {
-				customDomainsArr, ok := customDomains.([]interface{})
-				if !ok {
-					return nil, fmt.Errorf("error converting custom domains to array")
-				}
-				for _, domain := range customDomainsArr {
-					domainStr, ok := domain.(string)
-					if !ok {
-						return nil, fmt.Errorf("error converting custom domain to string")
-					}
-					domains = append(domains, &porterv1.Domain{
-						Name: domainStr,
-					})
-				}
-			}
-			webConfig.Domains = domains
+		domains := make([]*porterv1.Domain, 0)
+		for _, domain := range service.Config.Ingress.Hosts {
+			hostName := domain
+			domains = append(domains, &porterv1.Domain{
+				Name: hostName,
+			})
 		}
 		}
+		webConfig.Domains = domains
+		webConfig.Private = !service.Config.Ingress.Enabled
 
 
 		serviceProto.Config = &porterv1.Service_WebConfig{
 		serviceProto.Config = &porterv1.Service_WebConfig{
 			WebConfig: webConfig,
 			WebConfig: webConfig,
@@ -397,14 +232,18 @@ func serviceProtoFromConfig(service Service, serviceType porterv1.ServiceType) (
 		workerConfig := &porterv1.WorkerServiceConfig{}
 		workerConfig := &porterv1.WorkerServiceConfig{}
 
 
 		var autoscaling *porterv1.Autoscaling
 		var autoscaling *porterv1.Autoscaling
-		if autoscalingExists && autoscalingEnabled {
+		if service.Config.Autoscaling != nil && service.Config.Autoscaling.Enabled {
 			autoscaling = &porterv1.Autoscaling{
 			autoscaling = &porterv1.Autoscaling{
-				Enabled:                autoscalingEnabled,
-				MinInstances:           int32(autoscalingMinInstances),
-				MaxInstances:           int32(autoscalingMaxInstances),
-				CpuThresholdPercent:    int32(autoscalingCpuThresholdPercent),
-				MemoryThresholdPercent: int32(autoscalingMemoryThresholdPercent),
+				Enabled: service.Config.Autoscaling.Enabled,
 			}
 			}
+			minReplicas, _ := strconv.Atoi(service.Config.Autoscaling.MinReplicas)
+			autoscaling.MinInstances = int32(minReplicas)
+			maxReplicas, _ := strconv.Atoi(service.Config.Autoscaling.MaxReplicas)
+			autoscaling.MaxInstances = int32(maxReplicas)
+			cpuThresholdPercent, _ := strconv.Atoi(service.Config.Autoscaling.TargetCPUUtilizationPercentage)
+			autoscaling.CpuThresholdPercent = int32(cpuThresholdPercent)
+			memoryThresholdPercent, _ := strconv.Atoi(service.Config.Autoscaling.TargetMemoryUtilizationPercentage)
+			autoscaling.MemoryThresholdPercent = int32(memoryThresholdPercent)
 		}
 		}
 		workerConfig.Autoscaling = autoscaling
 		workerConfig.Autoscaling = autoscaling
 
 
@@ -412,29 +251,9 @@ func serviceProtoFromConfig(service Service, serviceType porterv1.ServiceType) (
 			WorkerConfig: workerConfig,
 			WorkerConfig: workerConfig,
 		}
 		}
 	case porterv1.ServiceType_SERVICE_TYPE_JOB:
 	case porterv1.ServiceType_SERVICE_TYPE_JOB:
-		var allowConcurrent bool
-		if service.Config != nil && service.Config["allowConcurrent"] != nil {
-			parsedAllowConcurrentBool, err := convertToBool(service.Config["allowConcurrent"])
-			if err != nil {
-				return nil, fmt.Errorf("error converting allow concurrency: %w", err)
-			}
-			allowConcurrent = parsedAllowConcurrentBool
-		}
-
-		var cron string
-		cronScheduleMap, err := getNestedMap(service.Config, "schedule")
-		if err == nil && cronScheduleMap != nil {
-			parsedCron := cronScheduleMap["value"]
-			parsedConString, err := convertToString(parsedCron)
-			if err != nil {
-				return nil, fmt.Errorf("error converting cron schedule: %w", err)
-			}
-			cron = parsedConString
-		}
-
 		jobConfig := &porterv1.JobServiceConfig{
 		jobConfig := &porterv1.JobServiceConfig{
-			AllowConcurrent: allowConcurrent,
-			Cron:            cron,
+			AllowConcurrent: service.Config.AllowConcurrency,
+			Cron:            service.Config.Schedule.Value,
 		}
 		}
 
 
 		serviceProto.Config = &porterv1.Service_JobConfig{
 		serviceProto.Config = &porterv1.Service_JobConfig{
@@ -444,95 +263,3 @@ func serviceProtoFromConfig(service Service, serviceType porterv1.ServiceType) (
 
 
 	return serviceProto, nil
 	return serviceProto, nil
 }
 }
-
-func getNestedMap(obj map[string]interface{}, fields ...string) (map[string]interface{}, error) {
-	var res map[string]interface{}
-	curr := obj
-
-	for _, field := range fields {
-		objField, ok := curr[field]
-
-		if !ok {
-			return nil, fmt.Errorf("%s does not exist in object", field)
-		}
-
-		res, ok = objField.(map[string]interface{})
-
-		if !ok {
-			return nil, fmt.Errorf("%s is not a nested object", field)
-		}
-
-		curr = res
-	}
-
-	return res, nil
-}
-
-func convertToInt(input interface{}) (int, error) {
-	if input == nil {
-		return 0, nil
-	}
-
-	switch value := input.(type) {
-	case int:
-		return value, nil
-	case string:
-		return strconv.Atoi(value)
-	default:
-		return 0, fmt.Errorf("input is not an int or string")
-	}
-}
-
-func convertToBool(input interface{}) (bool, error) {
-	if input == nil {
-		return false, nil
-	}
-
-	switch value := input.(type) {
-	case bool:
-		return value, nil
-	case string:
-		return strconv.ParseBool(value)
-	default:
-		return false, fmt.Errorf("input is not a bool or string")
-	}
-}
-
-func convertToString(input interface{}) (string, error) {
-	if input == nil {
-		return "", nil
-	}
-
-	switch value := input.(type) {
-	case string:
-		return value, nil
-	default:
-		return "", fmt.Errorf("input is not a string")
-	}
-}
-
-func convertMap(m interface{}) interface{} {
-	switch m := m.(type) {
-	case map[string]interface{}:
-		for k, v := range m {
-			m[k] = convertMap(v)
-		}
-	case map[string]string:
-		result := map[string]interface{}{}
-		for k, v := range m {
-			result[k] = v
-		}
-		return result
-	case map[interface{}]interface{}:
-		result := map[string]interface{}{}
-		for k, v := range m {
-			result[k.(string)] = convertMap(v)
-		}
-		return result
-	case []interface{}:
-		for i, v := range m {
-			m[i] = convertMap(v)
-		}
-	}
-	return m
-}