Example #1
0
func (self *RelationConfig) deploy(apiclient *juju.Client) error {
	_, err := apiclient.PutRelation(self.From, self.To)
	if err != nil {
		return err
	}
	return nil
}
Example #2
0
// Adds a bundletype to the system, by extracting the required template from the charm itself
func (self *System) AddJxaasCharm(apiclient *juju.Client, key string, charmName string) error {
	charmInfo, err := apiclient.CharmInfo(charmName)
	if err != nil {
		log.Warn("Error reading charm: %v", charmName, err)
		return err
	}

	if charmInfo == nil {
		return fmt.Errorf("Unable to find charm: %v", charmName)
	}

	url := charmInfo.URL
	if url == "" {
		return fmt.Errorf("Unable to find charm url: %v", charmName)
	}

	contents, err := apiclient.DownloadCharm(charmName)
	if err != nil {
		log.Warn("Error reading charm", err)
		return err
	}

	charmFile := NewCharmReader(contents)
	config, err := charmFile.read("jxaas.yaml")
	if err != nil {
		log.Warn("Error reading jxaas.yaml from charm: %v", charmName, err)
		return err
	}

	if config == nil {
		return fmt.Errorf("Could not find jxaas.yaml in charm: %v", charmName)
	}
	//	log.Info("Jxaas config: %v", string(config))

	bundleTemplate, err := bundle.NewBundleTemplate(sources.NewArrayToByteSource(config))
	if err != nil {
		return err
	}

	bundleType, err := bundletype.NewGenericBundleType(key, bundleTemplate)
	if err != nil {
		return err
	}

	self.BundleTypes[key] = bundleType

	return nil
}
Example #3
0
func NewHuddle(system *System, bundleStore *bundle.BundleStore, jujuApi *juju.Client, privateUrl string) (*Huddle, error) {
	key := "shared"

	huddle := &Huddle{}
	environmentInfo, err := jujuApi.EnvironmentInfo()
	if err != nil {
		log.Warn("Error reading juju environment info", err)
		return nil, err
	}
	if environmentInfo == nil {
		return nil, fmt.Errorf("No juju environment info found")
	}

	huddle.environmentProviderType = environmentInfo.ProviderType
	if huddle.environmentProviderType == "" {
		return nil, fmt.Errorf("Juju environment info invalid: no ProviderType")
	}
	log.Info("Juju environment ProviderType is '%v'", huddle.environmentProviderType)

	systemBundle, err := bundleStore.GetSystemBundle(key)
	if err != nil {
		log.Warn("Error loading system bundle: %v", key, err)
		return nil, err
	}

	if systemBundle == nil {
		log.Warn("Cannot load system bundle: %v", key, err)
		return nil, nil
	}

	info, err := systemBundle.Deploy("jx-", jujuApi)
	if err != nil {
		log.Warn("Error deploying system bundle", err)
		return nil, err
	}

	huddle.PrivateUrl = privateUrl
	huddle.SystemServices = map[string]*SystemService{}
	huddle.assignedPublicPorts = map[string]int{}

	for key, service := range info.Services {
		systemService := &SystemService{}
		systemService.JujuName = "jx-" + key
		systemService.Key = key

		status := service.Status
		if status != nil {
			for _, unit := range status.Units {
				if unit.PublicAddress != "" {
					systemService.PublicAddress = unit.PublicAddress
				}

				externalAddress := ""
				if unit.Machine != "" {
					externalAddress, err = jujuApi.PublicAddress(unit.Machine)
					if err != nil {
						log.Warn("Error getting public address for machine", err)
						return nil, err
					} else {
						if huddle.IsAmazon() {
							// Work around a problem where we sometimes get an address that is ip-X-X-X-X.ece2.internal
							// I think this is a Juju bug (?)
							if strings.HasSuffix(externalAddress, ".ec2.internal") {
								log.Warn("Juju gave invalid PublicAddress: %v", externalAddress)
								externalAddress = systemService.PublicAddress
							}

							// Amazon has a special DNS name: ec2-54-172-123-123.compute-1.amazonaws.com
							// Externally that resolves to 54.172.123.123 (i.e. the value embedded in the name)
							// Internally (inside EC2) that resolves to the internal IP (172.16.x.x)
							// We don't want that internal resolution to happen here (this is an _external_ IP)
							// But we may be within EC2, so we can't simply resolve the name
							if strings.HasPrefix(externalAddress, "ec2-") && strings.HasSuffix(externalAddress, ".compute-1.amazonaws.com") {
								ipString := externalAddress[4:]
								firstDot := strings.IndexRune(ipString, '.')
								ipString = ipString[:firstDot]

								ipString = strings.Replace(ipString, "-", ".", -1)

								log.Info("Replaced EC2 switching-address '%v' with IP '%v'", externalAddress, ipString)
								externalAddress = ipString
							}
						}

						if externalAddress != "" {
							log.Info("Chose public address for machine: '%v'", externalAddress)
						} else {
							log.Warn("Got empty public address for machine: %v", unit.Machine)
						}
					}
				}

				if externalAddress == "" {
					log.Warn("Unable to get external address for machine %v, falling back to public address %v", unit.Machine, systemService.PublicAddress)
					externalAddress = systemService.PublicAddress
				}
				systemService.ExternalAddress = externalAddress
			}
		}

		huddle.SystemServices[key] = systemService
	}

	huddle.JujuClient = jujuApi
	huddle.System = system
	// TODO: Wait until initialized or offer a separate 'bootstrap' command

	{
		check := &HealthCheckAllInstances{}
		check.huddle = huddle
		check.repair = true
		system.Scheduler.AddTask(check, time.Minute*1)
	}

	{
		scaling := &AutoScaleAllInstances{}
		scaling.huddle = huddle
		system.Scheduler.AddTask(scaling, time.Minute*1)
	}

	{
		task := &CleanupOldMachines{}
		task.huddle = huddle
		system.Scheduler.AddTask(task, time.Minute*5)
	}

	return huddle, nil
}
Example #4
0
func (self *ServiceConfig) deploy(jujuServiceId string, apiclient *juju.Client) (*DeployServiceInfo, error) {
	serviceInfo := &DeployServiceInfo{}

	jujuService, err := apiclient.FindService(jujuServiceId)
	if err != nil {
		return nil, err
	}

	charmUrl := self.Charm

	charmInfo, err := apiclient.CharmInfo(charmUrl)
	if err != nil {
		log.Warn("Error reading charm: %v", charmUrl, err)
	}
	if charmInfo == nil {
		log.Warn("Unable to find charm: %v", charmUrl)
	}

	charmUrl = charmInfo.URL

	if jujuService == nil {
		// Create new service

		numUnits := self.NumberUnits

		if charmInfo.Meta.Subordinate {
			numUnits = -1
		}

		configYaml, err := makeConfigYaml(jujuServiceId, self.Options)
		if err != nil {
			return nil, err
		}

		log.Debug("Deploying with YAML: %v", configYaml)

		err = apiclient.ServiceDeploy(
			charmUrl,
			jujuServiceId,
			numUnits,
			configYaml)

		if err != nil {
			return nil, err
		}

		//		for retry := 0; retry < 5; retry++ {
		//			status, err := apiclient.GetStatus(jujuServiceId)
		//			if err != nil {
		//				return err
		//			}
		//			if status != nil {
		//				break
		//			}
		//			log.Info("Service was not yet visible; waiting")
		//			time.Sleep(1 * time.Second)
		//		}
	} else {
		existingInstance := model.MapToInstance(jujuServiceId, nil, jujuService)
		existingServiceOptions := existingInstance.Options
		mergedServiceOptions := map[string]string{}
		{
			for key, value := range existingServiceOptions {
				mergedServiceOptions[key] = value
			}
			for key, value := range self.Options {
				mergedServiceOptions[key] = value
			}
		}

		if !reflect.DeepEqual(existingServiceOptions, mergedServiceOptions) {
			err = apiclient.SetConfig(jujuServiceId, mergedServiceOptions)
			if err != nil {
				return nil, err
			}
		} else {
			log.Debug("Configuration unchanged; won't reconfigure")
		}
	}

	if !charmInfo.Meta.Subordinate { // && self.Exposed != nil {
		status, err := apiclient.GetServiceStatus(jujuServiceId)
		if err != nil {
			return nil, err
		}
		if status == nil {
			return nil, fmt.Errorf("Service not found: %v", jujuServiceId)
		}

		serviceInfo.Status = status

		if status.Exposed != self.Exposed {
			err = apiclient.SetExposed(jujuServiceId, self.Exposed)
			if err != nil {
				log.Warn("Error setting service to Exposed=%v", self.Exposed, err)
				return nil, err
			}
		}

		actualUnits := len(status.Units)
		wantUnits := self.NumberUnits
		if actualUnits != wantUnits {
			if actualUnits < wantUnits {
				_, err = apiclient.AddServiceUnits(jujuServiceId, wantUnits-actualUnits)
				if err != nil {
					log.Warn("Error adding units", err)
				}
			} else {
				keys := []string{}
				for key, _ := range status.Units {
					keys = append(keys, key)
				}

				sort.Strings(keys)

				// TODO: Be more intelligent about which unit to kill?
				victims := keys[wantUnits:len(keys)]

				for _, victim := range victims {
					slash := strings.Index(victim, "/")
					unitId, err := strconv.Atoi(victim[slash+1:])
					if err != nil {
						log.Warn("Error parsing UnitId: %v", victim)
						return nil, err
					}

					err = apiclient.DestroyUnit(jujuServiceId, unitId)
					if err != nil {
						log.Warn("Error removing unit: %v/%v", jujuServiceId, unitId, err)
						return nil, err
					}
				}
			}
		}
	}

	//	for _, openPort := range self.OpenPorts {
	//	apiclient.Run(jujuServiceId, nil, ["open-port", openPort])
	//
	////		err = apiclient.OpenPort(jujuServiceId, openPort)
	//		if err != nil {
	//			log.Warn("Error opening port: %v/%v", jujuServiceId, openPort, err)
	//			return nil, err
	//		}
	//	}

	return serviceInfo, nil
}