Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix defaulting by api-server differences #1214

Merged
merged 3 commits into from
Dec 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions operator/api/v1alpha2/seldondeployment_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,24 +271,6 @@ func (r *SeldonDeployment) DefaultSeldonDeployment() {
pu.Endpoint.ServicePort = portNum
}
}

// Add defaultMode to volumes if not set to ensure no changes when comparing later in controller
for k := 0; k < len(cSpec.Spec.Volumes); k++ {
vol := &cSpec.Spec.Volumes[k]
if vol.Secret != nil && vol.Secret.DefaultMode == nil {
var defaultMode = corev1.SecretVolumeSourceDefaultMode
vol.Secret.DefaultMode = &defaultMode
} else if vol.ConfigMap != nil && vol.ConfigMap.DefaultMode == nil {
var defaultMode = corev1.ConfigMapVolumeSourceDefaultMode
vol.ConfigMap.DefaultMode = &defaultMode
} else if vol.DownwardAPI != nil && vol.DownwardAPI.DefaultMode == nil {
var defaultMode = corev1.DownwardAPIVolumeSourceDefaultMode
vol.DownwardAPI.DefaultMode = &defaultMode
} else if vol.Projected != nil && vol.Projected.DefaultMode == nil {
var defaultMode = corev1.ProjectedVolumeSourceDefaultMode
vol.Projected.DefaultMode = &defaultMode
}
}
}

pus := GetPredictiveUnitList(p.Graph)
Expand Down
131 changes: 91 additions & 40 deletions operator/controllers/seldondeployment_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ import (

"github.com/seldonio/seldon-core/operator/constants"
"github.com/seldonio/seldon-core/operator/utils"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"knative.dev/pkg/kmp"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

"github.com/go-logr/logr"
Expand All @@ -39,8 +41,6 @@ import (

"encoding/json"

"reflect"

appsv1 "k8s.io/api/apps/v1"
autoscaling "k8s.io/api/autoscaling/v2beta1"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -730,15 +730,6 @@ func createDeploymentWithoutEngine(depName string, seldonId string, seldonPodSpe
deploy.Spec.Template.ObjectMeta.Labels[k] = v
}

for k := 0; k < len(deploy.Spec.Template.Spec.InitContainers); k++ {
con := &deploy.Spec.Template.Spec.InitContainers[k]
addContainerDefaults(con)
}
for k := 0; k < len(deploy.Spec.Template.Spec.Containers); k++ {
con := &deploy.Spec.Template.Spec.Containers[k]
addContainerDefaults(con)
}

//Add some default to help with diffs in controller
if deploy.Spec.Template.Spec.RestartPolicy == "" {
deploy.Spec.Template.Spec.RestartPolicy = corev1.RestartPolicyAlways
Expand Down Expand Up @@ -803,14 +794,29 @@ func createIstioServices(r *SeldonDeploymentReconciler, components *components,
return ready, err
} else {
// Update the found object and write the result back if there are any changes
if !reflect.DeepEqual(svc.Spec, found.Spec) {
ready = false
if !equality.Semantic.DeepEqual(svc.Spec, found.Spec) {
desiredSvc := found.DeepCopy()
found.Spec = svc.Spec
log.Info("Updating Virtual Service", "namespace", svc.Namespace, "name", svc.Name)
err = r.Update(context.TODO(), found)
if err != nil {
return ready, err
}

// Check if what came back from server modulo the defaults applied by k8s is the same or not
if !equality.Semantic.DeepEqual(desiredSvc.Spec, found.Spec) {
ready = false

//For debugging we will show the difference
diff, err := kmp.SafeDiff(desiredSvc.Spec, found.Spec)
if err != nil {
log.Error(err, "Failed to diff")
} else {
log.Info(fmt.Sprintf("Difference in VSVC: %v", diff))
}
} else {
log.Info("The VSVC are the same - api server defaults ignored")
}
} else {
log.Info("Found identical Virtual Service", "namespace", found.Namespace, "name", found.Name)

Expand Down Expand Up @@ -851,14 +857,29 @@ func createIstioServices(r *SeldonDeploymentReconciler, components *components,
return ready, err
} else {
// Update the found object and write the result back if there are any changes
if !reflect.DeepEqual(drule.Spec, found.Spec) {
ready = false
if !equality.Semantic.DeepEqual(drule.Spec, found.Spec) {
desiredDrule := found.DeepCopy()
found.Spec = drule.Spec
log.Info("Updating Istio Destination Rule", "namespace", drule.Namespace, "name", drule.Name)
err = r.Update(context.TODO(), found)
if err != nil {
return ready, err
}

// Check if what came back from server modulo the defaults applied by k8s is the same or not
if !equality.Semantic.DeepEqual(desiredDrule.Spec, found.Spec) {
ready = false

//For debugging we will show the difference
diff, err := kmp.SafeDiff(desiredDrule.Spec, found.Spec)
if err != nil {
log.Error(err, "Failed to diff")
} else {
log.Info(fmt.Sprintf("Difference in Destination Rules: %v", diff))
}
} else {
log.Info("The Destination Rules are the same - api server defaults ignored")
}
} else {
log.Info("Found identical Istio Destination Rule", "namespace", found.Namespace, "name", found.Name)

Expand Down Expand Up @@ -909,14 +930,29 @@ func createServices(r *SeldonDeploymentReconciler, components *components, insta
} else {
svc.Spec.ClusterIP = found.Spec.ClusterIP
// Update the found object and write the result back if there are any changes
if !reflect.DeepEqual(svc.Spec, found.Spec) {
ready = false
if !equality.Semantic.DeepEqual(svc.Spec, found.Spec) {
desiredSvc := found.DeepCopy()
found.Spec = svc.Spec
log.Info("Updating Service", "namespace", svc.Namespace, "name", svc.Name)
err = r.Update(context.TODO(), found)
if err != nil {
return ready, err
}

// Check if what came back from server modulo the defaults applied by k8s is the same or not
if !equality.Semantic.DeepEqual(desiredSvc.Spec, found.Spec) {
ready = false

//For debugging we will show the difference
diff, err := kmp.SafeDiff(desiredSvc.Spec, found.Spec)
if err != nil {
log.Error(err, "Failed to diff")
} else {
log.Info(fmt.Sprintf("Difference in SVCs: %v", diff))
}
} else {
log.Info("The SVCs are the same - api server defaults ignored")
}
} else {
log.Info("Found identical Service", "namespace", found.Namespace, "name", found.Name, "status", found.Status)

Expand Down Expand Up @@ -960,14 +996,32 @@ func createHpas(r *SeldonDeploymentReconciler, components *components, instance
return ready, err
} else {
// Update the found object and write the result back if there are any changes
if !reflect.DeepEqual(hpa.Spec, found.Spec) {
if !equality.Semantic.DeepEqual(hpa.Spec, found.Spec) {

desiredHpa := found.DeepCopy()
found.Spec = hpa.Spec
ready = false

log.Info("Updating HPA", "namespace", hpa.Namespace, "name", hpa.Name)
err = r.Update(context.TODO(), found)
if err != nil {
return ready, err
}

// Check if what came back from server modulo the defaults applied by k8s is the same or not
if !equality.Semantic.DeepEqual(desiredHpa.Spec, found.Spec) {
ready = false

//For debugging we will show the difference
diff, err := kmp.SafeDiff(desiredHpa.Spec, found.Spec)
if err != nil {
log.Error(err, "Failed to diff")
} else {
log.Info(fmt.Sprintf("Difference in HPAs: %v", diff))
}
} else {
log.Info("The HPAs are the same - api server defaults ignored")
}

} else {
log.Info("Found identical HPA", "namespace", found.Namespace, "name", found.Name, "status", found.Status)
}
Expand Down Expand Up @@ -1016,35 +1070,32 @@ func createDeployments(r *SeldonDeploymentReconciler, components *components, in
} else if err != nil {
return ready, err
} else {
//Hack to add default procMount which if not present in old k8s versions might cause us to believe the Specs are different and we need an update
for _, c := range found.Spec.Template.Spec.Containers {
if c.SecurityContext != nil && c.SecurityContext.ProcMount == nil {
var procMount = corev1.DefaultProcMount
c.SecurityContext.ProcMount = &procMount
}
}
// Update the found object and write the result back if there are any changes
jEquals, err := jsonEquals(deploy.Spec.Template.Spec, found.Spec.Template.Spec)
if err != nil {
return ready, err
}
//if !reflect.DeepEqual(deploy.Spec.Template.Spec, found.Spec.Template.Spec) {
if !jEquals {
if !equality.Semantic.DeepEqual(deploy.Spec.Template.Spec, found.Spec.Template.Spec) {
log.Info("Updating Deployment", "namespace", deploy.Namespace, "name", deploy.Name)

if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].Resources, found.Spec.Template.Spec.Containers[0].Resources) {
log.Info("Containers differ")
} else {
log.Info("Deployments differ")
}

ready = false
desiredDeployment := found.DeepCopy()
found.Spec = deploy.Spec

err = r.Update(context.TODO(), found)
if err != nil {
return ready, err
}

// Check if what came back from server modulo the defaults applied by k8s is the same or not
if !equality.Semantic.DeepEqual(desiredDeployment.Spec.Template.Spec, found.Spec.Template.Spec) {
ready = false

//For debugging we will show the difference
diff, err := kmp.SafeDiff(desiredDeployment.Spec.Template.Spec, found.Spec.Template.Spec)
if err != nil {
log.Error(err, "Failed to diff")
} else {
log.Info(fmt.Sprintf("Difference in deployments: %v", diff))
}
} else {
log.Info("The deployments are the same - api server defaults ignored")
}

} else {
log.Info("Found identical deployment", "namespace", found.Namespace, "name", found.Name, "status", found.Status)
deploymentStatus, present := instance.Status.DeploymentStatus[found.Name]
Expand Down
3 changes: 1 addition & 2 deletions operator/controllers/seldondeployment_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ func createEngineContainer(mlDep *machinelearningv1alpha2.SeldonDeployment, p *m
}

if engineUser != -1 {
var procMount = corev1.DefaultProcMount
c.SecurityContext = &corev1.SecurityContext{RunAsUser: &engineUser, ProcMount: &procMount}
c.SecurityContext = &corev1.SecurityContext{RunAsUser: &engineUser}
}

// Environment vars if specified
Expand Down
24 changes: 0 additions & 24 deletions operator/controllers/seldondeployment_prepackaged_servers.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/seldonio/seldon-core/operator/utils"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"strings"
)

Expand Down Expand Up @@ -55,7 +54,6 @@ func addTFServerContainer(r *SeldonDeploymentReconciler, pu *machinelearningv1al
//Add missing fields
machinelearningv1alpha2.SetImageNameForPrepackContainer(pu, c)
SetUriParamsForTFServingProxyContainer(pu, c)
addContainerDefaults(c)

// Add container to deployment
if !existing {
Expand Down Expand Up @@ -100,8 +98,6 @@ func addTFServerContainer(r *SeldonDeploymentReconciler, pu *machinelearningv1al
}
}

addContainerDefaults(tfServingContainer)

if !existing {
deploy.Spec.Template.Spec.Containers = append(deploy.Spec.Template.Spec.Containers, *tfServingContainer)
}
Expand Down Expand Up @@ -152,7 +148,6 @@ func addModelDefaultServers(r *SeldonDeploymentReconciler, pu *machinelearningv1
if err != nil {
return err
}
addContainerDefaults(c)

if len(params) > 0 {
if !utils.HasEnvVar(c.Env, machinelearningv1alpha2.ENV_PREDICTIVE_UNIT_PARAMETERS) {
Expand Down Expand Up @@ -233,25 +228,6 @@ func SetUriParamsForTFServingProxyContainer(pu *machinelearningv1alpha2.Predicti
}
}

func addContainerDefaults(c *v1.Container) {
// Add some defaults for easier diffs
if c.TerminationMessagePath == "" {
c.TerminationMessagePath = "/dev/termination-log"
}
if c.TerminationMessagePolicy == "" {
c.TerminationMessagePolicy = corev1.TerminationMessageReadFile
}

if c.ImagePullPolicy == "" {
c.ImagePullPolicy = corev1.PullIfNotPresent
}

if c.SecurityContext != nil && c.SecurityContext.ProcMount == nil {
var procMount = corev1.DefaultProcMount
c.SecurityContext.ProcMount = &procMount
}
}

func createStandaloneModelServers(r *SeldonDeploymentReconciler, mlDep *machinelearningv1alpha2.SeldonDeployment, p *machinelearningv1alpha2.PredictorSpec, c *components, pu *machinelearningv1alpha2.PredictiveUnit) error {

// some predictors have no podSpec so this could be nil
Expand Down