func (self *RelationConfig) deploy(apiclient *juju.Client) error { _, err := apiclient.PutRelation(self.From, self.To) if err != nil { return err } return nil }
// 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 }
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 }
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 }