func createApp()

in images/controller/cmd/reservation_broker/reservation_broker.go [591:665]


func createApp(app broker.AppConfigSpec, appCtx *AppContext, user, username string) (int, string) {
	statusCode := http.StatusOK
	msg := ""

	// Lock the reservation table so that users get an atomic reservation and they can't reserve multiple pods.
	appCtx.Lock()
	defer appCtx.Unlock()

	if pod, ok := appCtx.ReservedPods[user]; ok {
		msg = fmt.Sprintf("pod for %s: %s", user, pod.Name)
		return statusCode, msg
	}

	if len(appCtx.AvailablePods) == 0 {
		statusCode = http.StatusNotFound
		msg = "No available instances at this time"
		return statusCode, msg
	}

	// Generate session key
	sessionKey := broker.MakeSessionKey()

	// Assign user a pod and remove it from the list
	pod := appCtx.AvailablePods[0]
	appCtx.AvailablePods = appCtx.AvailablePods[1:]
	pod.SessionKey = sessionKey

	// Build the per-user manifest templates
	destDir, err := buildUserBundle(app, appCtx, user, username, pod)
	if err != nil {
		log.Printf("failed to build user bundle for %s/%s: %v", app.Name, user, err)
		statusCode = http.StatusInternalServerError
		msg = "error creating app"
		return statusCode, msg
	}

	// Determine the unique kinds of objects being applied and add them to a json patch that will add the list to an annotation.
	// This is done because 'kubectl delete all' does not capture things like CRDs or VirtualService so object can get orphaned.
	// See also: https://github.com/kubernetes/kubectl/issues/151
	userObjects, err := broker.GetObjectTypes(destDir)
	if err != nil {
		log.Printf("failed to determine object types in bundle: %v", err)
		statusCode = http.StatusInternalServerError
		msg = "error creating app"
		return statusCode, msg
	}
	pod.UserObjects = userObjects

	// Update the pod for the user
	if err := updatePodForUser(app, user, pod.SessionKey, pod.Name, pod.UserObjects); err != nil {
		log.Printf("failed to update pod for user %s: %s: %v", user, pod.Name, err)
		statusCode = http.StatusInternalServerError
		msg = "error creating app"
		return statusCode, msg
	}

	// Apply the per-user manifests
	cmd := exec.Command("sh", "-o", "pipefail", "-c", fmt.Sprintf("kustomize build %s | kubectl apply -f -", destDir))
	cmd.Dir = destDir
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("error applying per-user manifests for %s: %v\n%s", user, err, stdoutStderr)
		statusCode = http.StatusInternalServerError
		msg = "error creating app"
		return statusCode, msg
	}

	log.Printf("assigned pod %s to user: %s", pod.Name, user)

	// Reserve pod for user in map
	appCtx.ReservedPods[user] = pod

	msg = fmt.Sprintf("assigned pod: %s", pod.Name)
	return statusCode, msg
}