func (a *Workload) BoundServicesChange(ctx context.Context, userName string, oldServices NameSet, newServices services.ServiceList) error {
	_, err := Get(ctx, a.cluster, a.app)
	if err != nil {
		return err
	}
	bindings, err := ToBinds(ctx, newServices, a.app.Name, userName)
	if err != nil {
		return err
	}
	new := map[string]struct{}{}
	for _, s := range newServices {
		new[s.Name()] = struct{}{}
	}
	return retry.RetryOnConflict(retry.DefaultRetry, func() error {
		deployment, err := a.Deployment(ctx)
		if err != nil {
			return err
		}
		newVolumes := []corev1.Volume{}
		newMounts := []corev1.VolumeMount{}
		for _, volume := range deployment.Spec.Template.Spec.Volumes {
			_, hasold := oldServices[volume.Name]
			_, hasnew := new[volume.Name]
			if hasold && !hasnew {
				continue
			}
			newVolumes = append(newVolumes, volume)
		}
		for _, mount := range deployment.Spec.Template.Spec.Containers[0].VolumeMounts {
			_, hasold := oldServices[mount.Name]
			_, hasnew := new[mount.Name]
			if hasold && !hasnew {
				continue
			}
			newMounts = append(newMounts, mount)
		}
		for _, binding := range bindings {
			if _, hasold := oldServices[binding.service]; hasold {
				continue
			}
			newVolumes = append(newVolumes, corev1.Volume{
				Name: binding.service,
				VolumeSource: corev1.VolumeSource{
					Secret: &corev1.SecretVolumeSource{
						SecretName: binding.resource,
					},
				},
			})
			newMounts = append(newMounts, corev1.VolumeMount{
				Name:      binding.service,
				ReadOnly:  true,
				MountPath: fmt.Sprintf("/services/%s", binding.service),
			})
		}
		deployment.Spec.Template.Spec.Volumes = newVolumes
		deployment.Spec.Template.Spec.Containers[0].VolumeMounts = newMounts
		_, err = a.cluster.Kubectl.AppsV1().Deployments(a.app.Org).Update(
			ctx, deployment, metav1.UpdateOptions{})
		return err
	})
}
BoundServicesChange imports the currently bound services into the deployment. It takes a ServiceList, not just
names, as it has to create/retrieve the associated service binding secrets. It further takes a set of the old
services. This enables incremental modification of the deployment (add, remove affected, instead of wholsesale
replacement).
package application
import (
	"context"
	"fmt"
	"math"
	"time"
	"github.com/epinio/epinio/helpers/kubernetes"
	"github.com/epinio/epinio/internal/names"
	"github.com/epinio/epinio/internal/services"
	"github.com/epinio/epinio/pkg/api/core/v1/models"
	pkgerrors "github.com/pkg/errors"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	resource "k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/util/retry"
	metrics "k8s.io/metrics/pkg/client/clientset/versioned"
)
type AppServiceBind struct {
	service  string  
	resource string  
}
type AppServiceBindList []AppServiceBind
type Workload struct {
	app     models.AppRef
	cluster *kubernetes.Cluster
}
func NewWorkload(cluster *kubernetes.Cluster, app models.AppRef) *Workload {
	return &Workload{cluster: cluster, app: app}
}
func ToBinds(ctx context.Context, services services.ServiceList, appName string, userName string) (AppServiceBindList, error) {
	bindings := AppServiceBindList{}
	for _, service := range services {
		bindResource, err := service.GetBinding(ctx, appName, userName)
		if err != nil {
			return AppServiceBindList{}, err
		}
		bindings = append(bindings, AppServiceBind{
			resource: bindResource.Name,
			service:  service.Name(),
		})
	}
	return bindings, nil
}
func (b AppServiceBindList) ToVolumesArray() []corev1.Volume {
	volumes := []corev1.Volume{}
	for _, binding := range b {
		volumes = append(volumes, corev1.Volume{
			Name: binding.service,
			VolumeSource: corev1.VolumeSource{
				Secret: &corev1.SecretVolumeSource{
					SecretName: binding.resource,
				},
			},
		})
	}
	return volumes
}
func (b AppServiceBindList) ToMountsArray() []corev1.VolumeMount {
	mounts := []corev1.VolumeMount{}
	for _, binding := range b {
		mounts = append(mounts, corev1.VolumeMount{
			Name:      binding.service,
			ReadOnly:  true,
			MountPath: fmt.Sprintf("/services/%s", binding.service),
		})
	}
	return mounts
}