Exemple #1
0
func (f *ConsulFingerprint) Fingerprint(config *client.Config, node *structs.Node) (bool, error) {
	// Guard against uninitialized Links
	if node.Links == nil {
		node.Links = map[string]string{}
	}

	// Only create the client once to avoid creating too many connections to
	// Consul.
	if f.client == nil {
		address := config.ReadDefault("consul.address", "127.0.0.1:8500")
		timeout, err := time.ParseDuration(config.ReadDefault("consul.timeout", "10ms"))
		if err != nil {
			return false, fmt.Errorf("Unable to parse consul.timeout: %s", err)
		}

		consulConfig := consul.DefaultConfig()
		consulConfig.Address = address
		consulConfig.HttpClient.Timeout = timeout

		f.client, err = consul.NewClient(consulConfig)
		if err != nil {
			return false, fmt.Errorf("Failed to initialize consul client: %s", err)
		}
	}

	// We'll try to detect consul by making a query to to the agent's self API.
	// If we can't hit this URL consul is probably not running on this machine.
	info, err := f.client.Agent().Self()
	if err != nil {
		// Clear any attributes set by a previous fingerprint.
		f.clearConsulAttributes(node)

		// Print a message indicating that the Consul Agent is not available
		// anymore
		if f.lastState == consulAvailable {
			f.logger.Printf("[INFO] fingerprint.consul: consul agent is unavailable")
		}
		f.lastState = consulUnavailable
		return false, nil
	}

	node.Attributes["consul.server"] = strconv.FormatBool(info["Config"]["Server"].(bool))
	node.Attributes["consul.version"] = info["Config"]["Version"].(string)
	node.Attributes["consul.revision"] = info["Config"]["Revision"].(string)
	node.Attributes["consul.name"] = info["Config"]["NodeName"].(string)
	node.Attributes["consul.datacenter"] = info["Config"]["Datacenter"].(string)

	node.Links["consul"] = fmt.Sprintf("%s.%s",
		node.Attributes["consul.datacenter"],
		node.Attributes["consul.name"])

	// If the Consul Agent was previously unavailable print a message to
	// indicate the Agent is available now
	if f.lastState == consulUnavailable {
		f.logger.Printf("[INFO] fingerprint.consul: consul agent is available")
	}
	f.lastState = consulAvailable
	return true, nil
}
Exemple #2
0
func (f *ConsulFingerprint) Fingerprint(config *client.Config, node *structs.Node) (bool, error) {
	// Guard against uninitialized Links
	if node.Links == nil {
		node.Links = map[string]string{}
	}

	address := config.ReadDefault("consul.address", "127.0.0.1:8500")
	timeout, err := time.ParseDuration(config.ReadDefault("consul.timeout", "10ms"))
	if err != nil {
		return false, fmt.Errorf("Unable to parse consul.timeout: %s", err)
	}

	consulConfig := consul.DefaultConfig()
	consulConfig.Address = address
	consulConfig.HttpClient.Timeout = timeout

	consulClient, err := consul.NewClient(consulConfig)
	if err != nil {
		return false, fmt.Errorf("Failed to initialize consul client: %s", err)
	}

	// We'll try to detect consul by making a query to to the agent's self API.
	// If we can't hit this URL consul is probably not running on this machine.
	info, err := consulClient.Agent().Self()
	if err != nil {
		return false, fmt.Errorf("Failed to query consul for agent status: %s", err)
	}

	node.Attributes["consul.server"] = strconv.FormatBool(info["Config"]["Server"].(bool))
	node.Attributes["consul.version"] = info["Config"]["Version"].(string)
	node.Attributes["consul.revision"] = info["Config"]["Revision"].(string)
	node.Attributes["consul.name"] = info["Config"]["NodeName"].(string)
	node.Attributes["consul.datacenter"] = info["Config"]["Datacenter"].(string)

	node.Links["consul"] = fmt.Sprintf("%s.%s",
		node.Attributes["consul.datacenter"],
		node.Attributes["consul.name"])

	return true, nil
}
Exemple #3
0
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 := []string{
		"hostname",
		"id",
		"cpu-platform",
		"scheduling/automatic-restart",
		"scheduling/on-host-maintenance",
	}
	for _, k := range keys {
		value, err := f.Get(k, false)
		if err != nil {
			return false, checkError(err, f.logger, k)
		}

		// assume we want blank entries
		key := strings.Replace(k, "/", ".", -1)
		node.Attributes["platform.gce."+key] = strings.Trim(string(value), "\n")
	}

	// These keys need everything before the final slash removed to be usable.
	keys = []string{
		"machine-type",
		"zone",
	}
	for _, k := range keys {
		value, err := f.Get(k, false)
		if err != nil {
			return false, checkError(err, f.logger, k)
		}

		node.Attributes["platform.gce."+k] = 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)
		node.Attributes[prefix] = "true"
		node.Attributes[prefix+".ip"] = strings.Trim(intf.Ip, "\n")
		for index, accessConfig := range intf.AccessConfigs {
			node.Attributes[prefix+".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 {
		node.Attributes["platform.gce.tag."+tag] = "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 {
		node.Attributes["platform.gce.attr."+k] = strings.Trim(v, "\n")
	}

	// populate Links
	node.Links["gce"] = node.Attributes["platform.gce.id"]

	return true, nil
}
Exemple #4
0
func (f *EnvAWSFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	if !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 := []string{
		"ami-id",
		"hostname",
		"instance-id",
		"instance-type",
		"local-hostname",
		"local-ipv4",
		"public-hostname",
		"public-ipv4",
		"placement/availability-zone",
	}
	for _, k := range keys {
		res, err := client.Get(metadataURL + k)
		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 := strings.Replace(k, "/", ".", -1)
		node.Attributes["platform.aws."+key] = strings.Trim(string(resp), "\n")
	}

	// copy over network specific information
	if node.Attributes["platform.aws.local-ipv4"] != "" {
		node.Attributes["network.ip-address"] = node.Attributes["platform.aws.local-ipv4"]
		newNetwork.IP = node.Attributes["platform.aws.local-ipv4"]
		newNetwork.CIDR = newNetwork.IP + "/32"
	}

	// find LinkSpeed from lookup
	if throughput := f.linkSpeed(); throughput > 0 {
		newNetwork.MBits = throughput
	}

	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}
	node.Resources.Networks = append(node.Resources.Networks, newNetwork)

	// populate Node Network Resources

	// populate Links
	node.Links["aws.ec2"] = node.Attributes["platform.aws.placement.availability-zone"] + "." + node.Attributes["platform.aws.instance-id"]

	return true, nil
}
Exemple #5
0
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
}
Exemple #6
0
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
}