func ResolveDepValuesForZone(app string, zkEnv *datamodel.ZkEnv, zone string, names []string, encrypt bool, t *Task) (DepsType, error) {
	var (
		err    error
		suffix string
	)
	deps := DepsType{}
	// if we're using DNS and the app is registered, try to get the app cname (if deployed)
	if dns.Provider != nil {
		suffix, err = dns.Provider.Suffix(Region)
		if err != nil {
			return deps, err
		}
	}
	for _, name := range names {
		// if app is registered for this dependency name
		zkApp, err := datamodel.GetApp(name)
		if err != nil {
			continue
		}
		appEnvData := zkApp.GetDependerEnvDataForDependerApp(app, zkEnv.Name, true)
		if appEnvData == nil {
			continue
		}
		envData := zkApp.GetDependerEnvData(zkEnv.Name, true)
		if envData == nil {
			envData = &DependerEnvData{Name: appEnvData.Name}
		}
		// merge the data
		mergedEnvData := MergeDependerEnvData(envData, appEnvData)
		appDep := &AppDep{
			SecurityGroup: mergedEnvData.SecurityGroup,
			DataMap:       mergedEnvData.DataMap,
		}
		if dns.Provider != nil && !zkApp.NonAtlantis && zkApp.Internal {
			// auto-populate Address
			port, created, err := datamodel.ReserveRouterPortAndUpdateTrie(zkApp.Internal, name, "", zkEnv.Name)
			if err != nil {
				return deps, err
			}
			if created {
				// add warning since this means that the app has not been deployed in this env yet
				t.AddWarning("App dependency " + name + " has not yet been deployed in environment " + zkEnv.Name)
			}
			if appDep.DataMap == nil {
				appDep.DataMap = map[string]interface{}{}
			}
			appDep.DataMap["address"] = helper.GetZoneRouterCName(true, zone, suffix) + ":" + port

			// auto-populate SecurityGroup
			portUint, err := strconv.ParseUint(port, 10, 16)
			if err != nil {
				return deps, err
			}
			appDep.SecurityGroup = map[string][]uint16{netsec.InternalRouterIPGroup: []uint16{uint16(portUint)}}
		}
		deps[name] = appDep
	}
	if encrypt {
		for _, value := range deps {
			crypto.EncryptAppDep(value)
		}
	}
	for _, name := range names {
		if _, ok := deps[name]; !ok {
			return deps, errors.New("Could not resolve dep " + name)
		}
	}
	return deps, nil
}
func deployToHostsInZones(deps map[string]DepsType, manifest *Manifest, sha, env string,
	hosts map[string][]string, zones []string, t *Task) ([]*Container, error) {
	deployedContainers := []*Container{}
	// fetch the app
	zkApp, err := datamodel.GetApp(manifest.Name)
	if err != nil {
		return nil, err
	}
	// first check if zones have enough hosts
	for _, zone := range zones {
		// fail if zone has no hosts
		if hosts[zone] == nil || len(hosts[zone]) == 0 {
			return nil, errors.New(fmt.Sprintf("No hosts available for app %s in zone %s", manifest.Name, zone))
		}
	}
	// now that we know that enough hosts are available
	t.LogStatus("Deploying to zones: %v", zones)
	respCh := make(chan *DeployZoneResult, len(zones))
	for _, zone := range zones {
		go deployToZone(respCh, deps, manifest, sha, env, hosts[zone], zone)
	}
	numResults := 0
	status := "Deployed to zones: "
	for result := range respCh {
		deployedContainers = append(deployedContainers, result.Containers...)
		if result.Error != nil {
			err = result.Error
			t.Log(err.Error())
			status += result.Zone + ":FAIL "
		} else {
			status += result.Zone + ":SUCCESS "
		}
		t.LogStatus(status)
		numResults++
		if numResults >= len(zones) { // we're done
			close(respCh)
		}
	}
	if err != nil {
		cleanup(false, deployedContainers, t)
		return nil, err
	}

	// set ports on zk supervisor - can't do this in parallel. we may deploy to the same host at the same time
	// and since we don't lock zookeeper (maybe we should), this would result in a race condition.
	t.LogStatus("Updating Zookeeper")
	for _, cont := range deployedContainers {
		datamodel.Supervisor(cont.Host).SetContainerAndPort(cont.ID, cont.PrimaryPort)
	}

	// we're good now, so lets move on
	t.LogStatus("Updating Router")
	deployedIDs := make([]string, len(deployedContainers))
	count := 0
	for _, cont := range deployedContainers {
		deployedIDs[count] = cont.ID
		count++
	}
	err = datamodel.AddToPool(deployedIDs)
	if err != nil { // if we can't add the pool, clean up and fail
		cleanup(true, deployedContainers, t)
		return nil, errors.New("Update Pool Error: " + err.Error())
	}
	if zkApp.Internal {
		// reserve router port if needed and add app+env
		_, _, err = datamodel.ReserveRouterPortAndUpdateTrie(zkApp.Internal, manifest.Name, sha, env)
		if err != nil {
			datamodel.DeleteFromPool(deployedIDs)
			cleanup(true, deployedContainers, t)
			return nil, errors.New("Reserve Router Port Error: " + err.Error())
		}
	} else {
		// only update trie
		_, err = datamodel.UpdateAppEnvTrie(zkApp.Internal, manifest.Name, sha, env)
		if err != nil {
			datamodel.DeleteFromPool(deployedIDs)
			cleanup(true, deployedContainers, t)
			return nil, errors.New("Reserve Router Port Error: " + err.Error())
		}
	}
	return deployedContainers, nil
}