func (f *EnvAWSFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { if !f.isAWS() { return false, nil } // newNetwork is populated and addded to the Nodes resources newNetwork := &structs.NetworkResource{ Device: "eth0", } if node.Links == nil { node.Links = make(map[string]string) } metadataURL := os.Getenv("AWS_ENV_URL") if metadataURL == "" { metadataURL = DEFAULT_AWS_URL } // assume 2 seconds is enough time for inside AWS network client := &http.Client{ Timeout: 2 * time.Second, Transport: cleanhttp.DefaultTransport(), } // Keys and whether they should be namespaced as unique. Any key whose value // uniquely identifies a node, such as ip, should be marked as unique. When // marked as unique, the key isn't included in the computed node class. keys := map[string]bool{ "ami-id": true, "hostname": true, "instance-id": true, "instance-type": false, "local-hostname": true, "local-ipv4": true, "public-hostname": true, "public-ipv4": true, "placement/availability-zone": false, } for k, unique := range keys { res, err := client.Get(metadataURL + k) if res.StatusCode != http.StatusOK { f.logger.Printf("[WARN]: fingerprint.env_aws: Could not read value for attribute %q", k) continue } if err != nil { // if it's a URL error, assume we're not in an AWS environment // TODO: better way to detect AWS? Check xen virtualization? if _, ok := err.(*url.Error); ok { return false, nil } // not sure what other errors it would return return false, err } resp, err := ioutil.ReadAll(res.Body) res.Body.Close() if err != nil { f.logger.Printf("[ERR]: fingerprint.env_aws: Error reading response body for AWS %s", k) } // assume we want blank entries key := "platform.aws." + strings.Replace(k, "/", ".", -1) if unique { key = structs.UniqueNamespace(key) } node.Attributes[key] = strings.Trim(string(resp), "\n") } // copy over network specific information if val := node.Attributes["unique.platform.aws.local-ipv4"]; val != "" { node.Attributes["unique.network.ip-address"] = val newNetwork.IP = val newNetwork.CIDR = newNetwork.IP + "/32" } // find LinkSpeed from lookup throughput := f.linkSpeed() if cfg.NetworkSpeed != 0 { throughput = cfg.NetworkSpeed } else if throughput == 0 { // Failed to determine speed. Check if the network fingerprint got it found := false if node.Resources != nil && len(node.Resources.Networks) > 0 { for _, n := range node.Resources.Networks { if n.IP == newNetwork.IP { throughput = n.MBits found = true break } } } // Nothing detected so default if !found { throughput = defaultNetworkSpeed } } // populate Node Network Resources if node.Resources == nil { node.Resources = &structs.Resources{} } newNetwork.MBits = throughput node.Resources.Networks = []*structs.NetworkResource{newNetwork} // populate Links node.Links["aws.ec2"] = fmt.Sprintf("%s.%s", node.Attributes["platform.aws.placement.availability-zone"], node.Attributes["unique.platform.aws.instance-id"]) return true, nil }
func (f *EnvGCEFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { if !f.isGCE() { return false, nil } if node.Links == nil { node.Links = make(map[string]string) } // Keys and whether they should be namespaced as unique. Any key whose value // uniquely identifies a node, such as ip, should be marked as unique. When // marked as unique, the key isn't included in the computed node class. keys := map[string]bool{ "hostname": true, "id": true, "cpu-platform": false, "scheduling/automatic-restart": false, "scheduling/on-host-maintenance": false, } for k, unique := range keys { value, err := f.Get(k, false) if err != nil { return false, checkError(err, f.logger, k) } // assume we want blank entries key := "platform.gce." + strings.Replace(k, "/", ".", -1) if unique { key = structs.UniqueNamespace(key) } node.Attributes[key] = strings.Trim(string(value), "\n") } // These keys need everything before the final slash removed to be usable. keys = map[string]bool{ "machine-type": false, "zone": false, } for k, unique := range keys { value, err := f.Get(k, false) if err != nil { return false, checkError(err, f.logger, k) } key := "platform.gce." + k if unique { key = structs.UniqueNamespace(key) } node.Attributes[key] = strings.Trim(lastToken(value), "\n") } // Get internal and external IPs (if they exist) value, err := f.Get("network-interfaces/", true) var interfaces []GCEMetadataNetworkInterface if err := json.Unmarshal([]byte(value), &interfaces); err != nil { f.logger.Printf("[WARN] fingerprint.env_gce: Error decoding network interface information: %s", err.Error()) } for _, intf := range interfaces { prefix := "platform.gce.network." + lastToken(intf.Network) uniquePrefix := "unique." + prefix node.Attributes[prefix] = "true" node.Attributes[uniquePrefix+".ip"] = strings.Trim(intf.Ip, "\n") for index, accessConfig := range intf.AccessConfigs { node.Attributes[uniquePrefix+".external-ip."+strconv.Itoa(index)] = accessConfig.ExternalIp } } var tagList []string value, err = f.Get("tags", false) if err != nil { return false, checkError(err, f.logger, "tags") } if err := json.Unmarshal([]byte(value), &tagList); err != nil { f.logger.Printf("[WARN] fingerprint.env_gce: Error decoding instance tags: %s", err.Error()) } for _, tag := range tagList { attr := "platform.gce.tag." var key string // If the tag is namespaced as unique, we strip it from the tag and // prepend to the whole attribute. if structs.IsUniqueNamespace(tag) { tag = strings.TrimPrefix(tag, structs.NodeUniqueNamespace) key = fmt.Sprintf("%s%s%s", structs.NodeUniqueNamespace, attr, tag) } else { key = fmt.Sprintf("%s%s", attr, tag) } node.Attributes[key] = "true" } var attrDict map[string]string value, err = f.Get("attributes/", true) if err != nil { return false, checkError(err, f.logger, "attributes/") } if err := json.Unmarshal([]byte(value), &attrDict); err != nil { f.logger.Printf("[WARN] fingerprint.env_gce: Error decoding instance attributes: %s", err.Error()) } for k, v := range attrDict { attr := "platform.gce.attr." var key string // If the key is namespaced as unique, we strip it from the // key and prepend to the whole attribute. if structs.IsUniqueNamespace(k) { k = strings.TrimPrefix(k, structs.NodeUniqueNamespace) key = fmt.Sprintf("%s%s%s", structs.NodeUniqueNamespace, attr, k) } else { key = fmt.Sprintf("%s%s", attr, k) } node.Attributes[key] = strings.Trim(v, "\n") } // populate Links node.Links["gce"] = node.Attributes["unique.platform.gce.id"] return true, nil }